Skip to content

Commit 1bae169

Browse files
committed
Teach detect_{libgfortran,libstdcxx}_version to deal with lazy CSL
We can no longer depend on the fact that these libraries will be eagerly loaded (huzzah!) so we must teach these helper functions to either inspect the lazy CSL JLL for the necessary information, or just directly load the library.
1 parent f4aab84 commit 1bae169

File tree

2 files changed

+60
-19
lines changed

2 files changed

+60
-19
lines changed

base/Base.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,6 @@ using .PermutedDimsArrays
213213
include("sort.jl")
214214
using .Sort
215215

216-
# BinaryPlatforms, used by Artifacts. Needs `Sort`.
217-
include("binaryplatforms.jl")
218-
219216
# Fast math
220217
include("fastmath.jl")
221218
using .FastMath
@@ -269,6 +266,9 @@ include("linking.jl")
269266
include("staticdata.jl")
270267
include("loading.jl")
271268

269+
# BinaryPlatforms, used by Artifacts. Needs `Sort`.
270+
include("binaryplatforms.jl")
271+
272272
# misc useful functions & macros
273273
include("timing.jl")
274274
include("client.jl")

base/binaryplatforms.jl

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -841,20 +841,48 @@ function parse_dl_name_version(path::AbstractString, os::AbstractString)
841841
return parse_dl_name_version(string(path)::String, string(os)::String)
842842
end
843843

844+
function get_csl_member(member::Symbol)
845+
# If CompilerSupportLibraries_jll is an stdlib, we can just grab things from it
846+
csl_pkgids = filter(pkgid -> pkgid.name == "CompilerSupportLibraries_jll", keys(Base.loaded_modules))
847+
if !isempty(csl_pkgids)
848+
CSL_mod = Base.loaded_modules[first(csl_pkgids)]
849+
850+
# This can fail during bootstrap, so we skip in that case.
851+
if isdefined(CSL_mod, member)
852+
return getproperty(CSL_mod, member)
853+
end
854+
end
855+
856+
return nothing
857+
end
858+
844859
"""
845860
detect_libgfortran_version()
846861
847862
Inspects the current Julia process to determine the libgfortran version this Julia is
848-
linked against (if any).
863+
linked against (if any). Returns `nothing` if no libgfortran version dependence is
864+
detected.
849865
"""
850866
function detect_libgfortran_version()
851-
libgfortran_paths = filter!(x -> occursin("libgfortran", x), Libdl.dllist())
852-
if isempty(libgfortran_paths)
867+
function get_libgfortran_path()
868+
# If CompilerSupportLibraries_jll is an stdlib, we can just directly ask for
869+
# the path here, without checking `dllist()`:
870+
libgfortran_path = get_csl_member(:libgfortran_path)
871+
if libgfortran_path !== nothing
872+
return libgfortran_path::String
873+
end
874+
875+
# Otherwise, look for it having already been loaded by something
876+
libgfortran_paths = filter!(x -> occursin("libgfortran", x), Libdl.dllist())
877+
if !isempty(libgfortran_paths)
878+
return first(libgfortran_paths)::String
879+
end
880+
853881
# One day, I hope to not be linking against libgfortran in base Julia
854882
return nothing
855883
end
856-
libgfortran_path = first(libgfortran_paths)
857884

885+
libgfortran_path = get_libgfortran_path()
858886
name, version = parse_dl_name_version(libgfortran_path, os())
859887
if version === nothing
860888
# Even though we complain about this, we allow it to continue in the hopes that
@@ -878,24 +906,37 @@ it is linked against (if any). `max_minor_version` is the latest version in the
878906
3.4 series of GLIBCXX where the search is performed.
879907
"""
880908
function detect_libstdcxx_version(max_minor_version::Int=30)
881-
libstdcxx_paths = filter!(x -> occursin("libstdc++", x), Libdl.dllist())
882-
if isempty(libstdcxx_paths)
883-
# This can happen if we were built by clang, so we don't link against
884-
# libstdc++ at all.
909+
function get_libstdcxx_handle()
910+
# If CompilerSupportLibraries_jll is an stdlib, we can just directly open it
911+
libstdcxx = get_csl_member(:libstdcxx)
912+
if libstdcxx !== nothing
913+
return nothing
914+
end
915+
916+
# Otherwise, look for it having already been loaded by something
917+
libstdcxx_paths = filter!(x -> occursin("libstdc++", x), Libdl.dllist())
918+
if !isempty(libstdcxx_paths)
919+
return Libdl.dlopen(first(libstdcxx_paths), Libdl.RTLD_NOLOAD)::Ptr{Cvoid}
920+
end
921+
922+
# One day, I hope to not be linking against libgfortran in base Julia
885923
return nothing
886924
end
887925

888926
# Brute-force our way through GLIBCXX_* symbols to discover which version we're linked against
889-
hdl = Libdl.dlopen(first(libstdcxx_paths))::Ptr{Cvoid}
890-
# Try all GLIBCXX versions down to GCC v4.8:
891-
# https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
892-
for minor_version in max_minor_version:-1:18
893-
if Libdl.dlsym(hdl, "GLIBCXX_3.4.$(minor_version)"; throw_error=false) !== nothing
894-
Libdl.dlclose(hdl)
895-
return VersionNumber("3.4.$(minor_version)")
927+
libstdcxx = get_libstdcxx_handle()
928+
929+
if libstdcxx !== nothing
930+
# Try all GLIBCXX versions down to GCC v4.8:
931+
# https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
932+
for minor_version in max_minor_version:-1:18
933+
if Libdl.dlsym(libstdcxx, "GLIBCXX_3.4.$(minor_version)"; throw_error=false) !== nothing
934+
Libdl.dlclose(libstdcxx)
935+
return VersionNumber("3.4.$(minor_version)")
936+
end
896937
end
897938
end
898-
Libdl.dlclose(hdl)
939+
Libdl.dlclose(libstdcxx)
899940
return nothing
900941
end
901942

0 commit comments

Comments
 (0)