From 7df0d9c2f6ad0e60ea04cd481820fe1f3a8091a1 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Fri, 9 Jun 2023 18:53:59 -0700 Subject: [PATCH 1/4] Showcase example of using LazyLibrary in shipped JLLs This converts the following JLLs to LazyLibrary APIs: * LibCURL_jll * LibSSH2_jll * MbedTLS_jll * OpenBLAS_jll * libblastrampoline_jll * nghttp2_jll It also introduces a new precompilation statement for a basic matrix multiplciation to ensure that TTFMM (time to first matmul) remains excellent. --- contrib/generate_precompile.jl | 1 + pkgimage.mk | 10 +-- stdlib/LibCURL_jll/src/LibCURL_jll.jl | 41 +++--------- stdlib/LibSSH2_jll/src/LibSSH2_jll.jl | 37 ++--------- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 23 ++++--- stdlib/MbedTLS_jll/src/MbedTLS_jll.jl | 62 +++++-------------- stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl | 59 ++++-------------- .../src/libblastrampoline_jll.jl | 41 ++++-------- stdlib/nghttp2_jll/src/nghttp2_jll.jl | 36 ++--------- test/precompile.jl | 4 +- 10 files changed, 80 insertions(+), 234 deletions(-) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index fea4ca6bc1fe3..2a9fb476aa58e 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -88,6 +88,7 @@ f(x) = x03 f(1,2) [][1] cd("complet_path\t\t$CTRL_C +randn(10, 10) * randn(10, 10) """ precompile_script = """ diff --git a/pkgimage.mk b/pkgimage.mk index 0803a188851bb..9ee39d10209ac 100644 --- a/pkgimage.mk +++ b/pkgimage.mk @@ -81,11 +81,11 @@ $(eval $(call pkgimg_builder,GMP_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,LLVMLibUnwind_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,LibUV_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,LibUnwind_jll,Artifacts Libdl)) -$(eval $(call pkgimg_builder,MbedTLS_jll,Artifacts Libdl)) -$(eval $(call pkgimg_builder,nghttp2_jll,Artifacts Libdl)) +$(eval $(call sysimg_builder,MbedTLS_jll,Artifacts Libdl)) +$(eval $(call sysimg_builder,nghttp2_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,OpenLibm_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,PCRE2_jll,Artifacts Libdl)) -$(eval $(call pkgimg_builder,Zlib_jll,Artifacts Libdl)) +$(eval $(call sysimg_builder,Zlib_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,dSFMT_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,libLLVM_jll,Artifacts Libdl)) $(eval $(call sysimg_builder,libblastrampoline_jll,Artifacts Libdl)) @@ -98,7 +98,7 @@ $(eval $(call pkgimg_builder,DelimitedFiles,Mmap)) # 2-depth packages $(eval $(call pkgimg_builder,LLD_jll,Zlib_jll libLLVM_jll Artifacts Libdl)) -$(eval $(call pkgimg_builder,LibSSH2_jll,Artifacts Libdl MbedTLS_jll)) +$(eval $(call sysimg_builder,LibSSH2_jll,Artifacts Libdl MbedTLS_jll)) $(eval $(call pkgimg_builder,MPFR_jll,Artifacts Libdl GMP_jll)) $(eval $(call sysimg_builder,LinearAlgebra,Libdl libblastrampoline_jll OpenBLAS_jll)) $(eval $(call sysimg_builder,Dates,Printf)) @@ -110,7 +110,7 @@ $(eval $(call sysimg_builder,UUIDs,Random SHA)) # 3-depth packages # LibGit2_jll -$(eval $(call pkgimg_builder,LibCURL_jll,LibSSH2_jll nghttp2_jll MbedTLS_jll Zlib_jll Artifacts Libdl)) +$(eval $(call sysimg_builder,LibCURL_jll,LibSSH2_jll nghttp2_jll MbedTLS_jll Zlib_jll Artifacts Libdl)) $(eval $(call sysimg_builder,REPL,InteractiveUtils Markdown Sockets Unicode)) $(eval $(call pkgimg_builder,SharedArrays,Distributed Mmap Random Serialization)) $(eval $(call sysimg_builder,TOML,Dates)) diff --git a/stdlib/LibCURL_jll/src/LibCURL_jll.jl b/stdlib/LibCURL_jll/src/LibCURL_jll.jl index cd67bfac0006a..1fa57f1e01fb8 100644 --- a/stdlib/LibCURL_jll/src/LibCURL_jll.jl +++ b/stdlib/LibCURL_jll/src/LibCURL_jll.jl @@ -3,44 +3,21 @@ ## dummy stub for https://github.com/JuliaBinaryWrappers/LibCURL_jll.jl baremodule LibCURL_jll -using Base, Libdl, nghttp2_jll -Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - +using Base, Libdl, nghttp2_jll, LibSSH2_jll export libcurl -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libcurl_handle::Ptr{Cvoid} = C_NULL -libcurl_path::String = "" - if Sys.iswindows() - const libcurl = "libcurl-4.dll" + const libcurl_name = "bin/libcurl-4.dll" elseif Sys.isapple() - const libcurl = "@rpath/libcurl.4.dylib" + const libcurl_name = "lib/libcurl.4.dylib" else - const libcurl = "libcurl.so.4" -end - -function __init__() - global libcurl_handle = dlopen(libcurl) - global libcurl_path = dlpath(libcurl_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libcurl_path) - push!(LIBPATH_list, LIBPATH[]) + const libcurl_name = "lib/libcurl.so.4" end -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libcurl_path() = libcurl_path +const libcurl_path = BundledLazyLibraryPath(libcurl_name) +const libcurl = LazyLibrary(libcurl_path; dependencies=[libssh2, libnghttp2], + on_load_callback = () -> begin + @assert ccall(dlsym(libcurl, :curl_global_init), UInt32, (Clong,), 0x03) == 0 + end) # eventually add libz end # module LibCURL_jll diff --git a/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl b/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl index a809f7a912d6b..26978b34e3fc2 100644 --- a/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl +++ b/stdlib/LibSSH2_jll/src/LibSSH2_jll.jl @@ -4,44 +4,17 @@ baremodule LibSSH2_jll using Base, Libdl, MbedTLS_jll -Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - export libssh2 -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libssh2_handle::Ptr{Cvoid} = C_NULL -libssh2_path::String = "" - if Sys.iswindows() - const libssh2 = "libssh2.dll" + const libssh2_name = "bin/libssh2.dll" elseif Sys.isapple() - const libssh2 = "@rpath/libssh2.1.dylib" + const libssh2_name = "lib/libssh2.1.dylib" else - const libssh2 = "libssh2.so.1" + const libssh2_name = "lib/libssh2.so.1" end -function __init__() - global libssh2_handle = dlopen(libssh2) - global libssh2_path = dlpath(libssh2_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libssh2_path) - push!(LIBPATH_list, LIBPATH[]) -end - - -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libssh2_path() = libssh2_path +const libssh2_path = BundledLazyLibraryPath(libssh2_name) +const libssh2 = LazyLibrary(libssh2_path; dependencies=[libmbedx509, libmbedcrypto, libmbedtls]) end # module LibSSH2_jll diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 386de771d666f..459da796a9aa7 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -676,24 +676,29 @@ function versioninfo(io::IO=stdout) return nothing end -function __init__() - try - BLAS.lbt_forward(OpenBLAS_jll.libopenblas_path; clear=true) - BLAS.check() - catch ex - Base.showerror_nostdio(ex, "WARNING: Error during initialization of module LinearAlgebra") - end + +function lbt_onload_callback() + # We don't use `BLAS.lbt_forward()` here because we explicitly don't + # want to take a lock on the config cache. + ccall(Libdl.dlsym(libblastrampoline, :lbt_forward), Int32, (Cstring, Int32, Int32, Cstring), + OpenBLAS_jll.libopenblas_path, 1, 0, C_NULL) + # register a hook to disable BLAS threading Base.at_disable_library_threading(() -> BLAS.set_num_threads(1)) # https://github.com/xianyi/OpenBLAS/blob/c43ec53bdd00d9423fc609d7b7ecb35e7bf41b85/README.md#setting-the-number-of-threads-using-environment-variables if !haskey(ENV, "OPENBLAS_NUM_THREADS") && !haskey(ENV, "GOTO_NUM_THREADS") && !haskey(ENV, "OMP_NUM_THREADS") @static if Sys.isapple() && Base.BinaryPlatforms.arch(Base.BinaryPlatforms.HostPlatform()) == "aarch64" - BLAS.set_num_threads(max(1, Sys.CPU_THREADS)) + nthreads = max(1, Sys.CPU_THREADS) else - BLAS.set_num_threads(max(1, Sys.CPU_THREADS ÷ 2)) + nthreads = max(1, Sys.CPU_THREADS ÷ 2) end + ccall(Libdl.dlsym(libblastrampoline, :lbt_set_num_threads), Cvoid, (Int32,), nthreads) end end +# Force `libblastrampoline` to forward to `libopenblas` once it's loaded +Libdl.add_dependency!(libblastrampoline, libopenblas) +push!(libblastrampoline_jll.on_load_callbacks, lbt_onload_callback) + end # module LinearAlgebra diff --git a/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl b/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl index e46da42a9a638..73966e1b8d742 100644 --- a/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl +++ b/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl @@ -4,59 +4,29 @@ baremodule MbedTLS_jll using Base, Libdl -Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - export libmbedcrypto, libmbedtls, libmbedx509 -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libmbedcrypto_handle::Ptr{Cvoid} = C_NULL -libmbedcrypto_path::String = "" -libmbedtls_handle::Ptr{Cvoid} = C_NULL -libmbedtls_path::String = "" -libmbedx509_handle::Ptr{Cvoid} = C_NULL -libmbedx509_path::String = "" - if Sys.iswindows() - const libmbedcrypto = "libmbedcrypto.dll" - const libmbedtls = "libmbedtls.dll" - const libmbedx509 = "libmbedx509.dll" + const libmbedcrypto_name = "bin/libmbedcrypto.dll" + const libmbedx509_name = "bin/libmbedx509.dll" + const libmbedtls_name = "bin/libmbedtls.dll" elseif Sys.isapple() - const libmbedcrypto = "@rpath/libmbedcrypto.7.dylib" - const libmbedtls = "@rpath/libmbedtls.14.dylib" - const libmbedx509 = "@rpath/libmbedx509.1.dylib" + const libmbedcrypto_name = "lib/libmbedcrypto.7.dylib" + const libmbedx509_name = "lib/libmbedx509.1.dylib" + const libmbedtls_name = "lib/libmbedtls.14.dylib" else - const libmbedcrypto = "libmbedcrypto.so.7" - const libmbedtls = "libmbedtls.so.14" - const libmbedx509 = "libmbedx509.so.1" + const libmbedcrypto_name = "lib/libmbedcrypto.so.7" + const libmbedx509_name = "lib/libmbedx509.so.1" + const libmbedtls_name = "lib/libmbedtls.so.14" end -function __init__() - global libmbedcrypto_handle = dlopen(libmbedcrypto) - global libmbedcrypto_path = dlpath(libmbedcrypto_handle) - global libmbedtls_handle = dlopen(libmbedtls) - global libmbedtls_path = dlpath(libmbedtls_handle) - global libmbedx509_handle = dlopen(libmbedx509) - global libmbedx509_path = dlpath(libmbedx509_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libmbedtls_path) - push!(LIBPATH_list, LIBPATH[]) -end +const libmbedcrypto_path = BundledLazyLibraryPath(libmbedcrypto_name) +const libmbedtls_path = BundledLazyLibraryPath(libmbedtls_name) +const libmbedx509_path = BundledLazyLibraryPath(libmbedx509_name) -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libmbedcrypto_path() =libmbedcrypto_path -get_libmbedtls_path() = libmbedtls_path -get_libmbedx509_path() = libmbedx509_path +const libmbedcrypto = LazyLibrary(libmbedcrypto_path) +const libmbedx509 = LazyLibrary(libmbedx509_path; dependencies=[libmbedcrypto]) +libmbedtls_stack = Any[] +const libmbedtls = LazyLibrary(libmbedtls_path; dependencies=[libmbedcrypto, libmbedx509], on_load_callback = () -> push!(libmbedtls_stack, stacktrace())) end # module MbedTLS_jll diff --git a/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl b/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl index a0c11ab047142..d2ba79282f605 100644 --- a/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl +++ b/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl @@ -3,30 +3,8 @@ ## dummy stub for https://github.com/JuliaBinaryWrappers/OpenBLAS_jll.jl baremodule OpenBLAS_jll using Base, Libdl, Base.BinaryPlatforms - -# We are explicitly NOT loading this at runtime, as it contains `libgomp` -# which conflicts with `libiomp5`, breaking things like MKL. In the future, -# we hope to transition to a JLL interface that provides a more granular -# interface than eagerly dlopen'ing all libraries provided in the JLL -# which will eliminate issues like this, where we avoid loading a JLL -# because we don't want to load a library that we don't even use yet. -# using CompilerSupportLibraries_jll -# Because of this however, we have to manually load the libraries we -# _do_ care about, namely libgfortran -Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - export libopenblas -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libopenblas_handle::Ptr{Cvoid} = C_NULL -libopenblas_path::String = "" - if Base.USE_BLAS64 const libsuffix = "64_" else @@ -34,16 +12,22 @@ else end if Sys.iswindows() - const libopenblas = "libopenblas$(libsuffix).dll" - const _libgfortran = string("libgfortran-", libgfortran_version(HostPlatform()).major, ".dll") + const libopenblas_name = "bin/libopenblas$(libsuffix).dll" + const libgfortran_name = string("libgfortran-", libgfortran_version(HostPlatform()).major, ".dll") elseif Sys.isapple() - const libopenblas = "@rpath/libopenblas$(libsuffix).dylib" - const _libgfortran = string("@rpath/", "libgfortran.", libgfortran_version(HostPlatform()).major, ".dylib") + const libopenblas_name = "lib/libopenblas$(libsuffix).dylib" + const libgfortran_name = string("lib/libgfortran.", libgfortran_version(HostPlatform()).major, ".dylib") else - const libopenblas = "libopenblas$(libsuffix).so" - const _libgfortran = string("libgfortran.so.", libgfortran_version(HostPlatform()).major) + const libopenblas_name = "lib/libopenblas$(libsuffix).so" + const libgfortran_name = string("lib/libgfortran.so.", libgfortran_version(HostPlatform()).major) end +const libgfortran_path = BundledLazyLibraryPath(libgfortran_name) +const libgfortran = LazyLibrary(libgfortran_path) + +const libopenblas_path = BundledLazyLibraryPath(libopenblas_name) +const libopenblas = LazyLibrary(libopenblas_path; dependencies=[libgfortran]) + function __init__() # make sure OpenBLAS does not set CPU affinity (#1070, #9639) if !haskey(ENV, "OPENBLAS_MAIN_FREE") @@ -62,25 +46,6 @@ function __init__() # to the true value in its `__init__()` function. ENV["OPENBLAS_DEFAULT_NUM_THREADS"] = "1" end - - # As mentioned above, we are sneaking this in here so that we don't have to - # depend on CSL_jll and load _all_ of its libraries. - dlopen(_libgfortran) - - global libopenblas_handle = dlopen(libopenblas) - global libopenblas_path = dlpath(libopenblas_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libopenblas_path) - push!(LIBPATH_list, LIBPATH[]) end -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libopenblas_path() = libopenblas_path - end # module OpenBLAS_jll diff --git a/stdlib/libblastrampoline_jll/src/libblastrampoline_jll.jl b/stdlib/libblastrampoline_jll/src/libblastrampoline_jll.jl index 49e7932a6b701..96a86b9a642b0 100644 --- a/stdlib/libblastrampoline_jll/src/libblastrampoline_jll.jl +++ b/stdlib/libblastrampoline_jll/src/libblastrampoline_jll.jl @@ -4,44 +4,25 @@ baremodule libblastrampoline_jll using Base, Libdl -Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - export libblastrampoline -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libblastrampoline_handle::Ptr{Cvoid} = C_NULL -libblastrampoline_path::String = "" - # NOTE: keep in sync with `Base.libblas_name` and `Base.liblapack_name`. -const libblastrampoline = if Sys.iswindows() - "libblastrampoline-5.dll" +if Sys.iswindows() + const libblastrampoline_name = "bin/libblastrampoline-5.dll" elseif Sys.isapple() - "@rpath/libblastrampoline.5.dylib" + const libblastrampoline_name = "lib/libblastrampoline.5.dylib" else - "libblastrampoline.so.5" + const libblastrampoline_name = "lib/libblastrampoline.so.5" end -function __init__() - global libblastrampoline_handle = dlopen(libblastrampoline) - global libblastrampoline_path = dlpath(libblastrampoline_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libblastrampoline_path) - push!(LIBPATH_list, LIBPATH[]) +const on_load_callbacks::Vector{Function} = Function[] +function libblastrampoline_on_load_callback() + for callback in on_load_callbacks + callback() + end end -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libblastrampoline_path() = libblastrampoline_path +const libblastrampoline_path = BundledLazyLibraryPath(libblastrampoline_name) +const libblastrampoline = LazyLibrary(libblastrampoline_path; on_load_callback=libblastrampoline_on_load_callback) end # module libblastrampoline_jll diff --git a/stdlib/nghttp2_jll/src/nghttp2_jll.jl b/stdlib/nghttp2_jll/src/nghttp2_jll.jl index 76e8d3582c402..f2177605fc5cc 100644 --- a/stdlib/nghttp2_jll/src/nghttp2_jll.jl +++ b/stdlib/nghttp2_jll/src/nghttp2_jll.jl @@ -3,43 +3,17 @@ ## dummy stub for https://github.com/JuliaBinaryWrappers/nghttp2_jll.jl baremodule nghttp2_jll using Base, Libdl -Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - export libnghttp2 -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libnghttp2_handle::Ptr{Cvoid} = C_NULL -libnghttp2_path::String = "" - if Sys.iswindows() - const libnghttp2 = "libnghttp2-14.dll" + const libnghttp2_name = "bin/libnghttp2-14.dll" elseif Sys.isapple() - const libnghttp2 = "@rpath/libnghttp2.14.dylib" + const libnghttp2_name = "lib/libnghttp2.14.dylib" else - const libnghttp2 = "libnghttp2.so.14" -end - -function __init__() - global libnghttp2_handle = dlopen(libnghttp2) - global libnghttp2_path = dlpath(libnghttp2_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libnghttp2_path) - push!(LIBPATH_list, LIBPATH[]) + const libnghttp2_name = "lib/libnghttp2.so.14" end -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libnghttp2_path() = libnghttp2_path +const libnghttp2_path = BundledLazyLibraryPath(libnghttp2_name) +const libnghttp2 = LazyLibrary(libnghttp2_path) end # module nghttp2_jll diff --git a/test/precompile.jl b/test/precompile.jl index 31ceb49475122..e1b40a15d9874 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -400,11 +400,11 @@ precompile_test_harness(false) do dir end for s in [:ArgTools, :Artifacts, :Base64, :CRC32c, :Dates, :Downloads, :FileWatching, :Future, :InteractiveUtils, :libblastrampoline_jll, - :LibCURL, :LibCURL_jll, :LibGit2, :Libdl, :LinearAlgebra, + :LibCURL, :LibCURL_jll, :MbedTLS_jll, :LibSSH2_jll, :LibGit2, :Libdl, :LinearAlgebra, :Logging, :Markdown, :Mmap, :MozillaCACerts_jll, :NetworkOptions, :OpenBLAS_jll, :Pkg, :Printf, :p7zip_jll, :REPL, :Random, :SHA, :Serialization, :Sockets, :TOML, :Tar, :Test, :UUIDs, :Unicode, - :nghttp2_jll] + :nghttp2_jll, :Zlib_jll] ), ) @test discard_module.(deps) == deps1 From 9ebc52e5d4f452bbb887352cd8c61261064f5d36 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Wed, 26 Jul 2023 15:22:20 -0400 Subject: [PATCH 2/4] More lazy JLL stdlibs * `OpenBLAS_jll` * `CompilerSupportLibraries_jll` * `dSFMT_jll` --- .../src/CompilerSupportLibraries_jll.jl | 93 +++++++------------ stdlib/MbedTLS_jll/src/MbedTLS_jll.jl | 3 +- stdlib/OpenBLAS_jll/Project.toml | 1 - stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl | 8 +- stdlib/dSFMT_jll/src/dSFMT_jll.jl | 35 +------ 5 files changed, 43 insertions(+), 97 deletions(-) diff --git a/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl b/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl index bd7a0571f9d5a..5b2a949b6f706 100644 --- a/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl +++ b/stdlib/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl @@ -6,78 +6,57 @@ baremodule CompilerSupportLibraries_jll using Base, Libdl, Base.BinaryPlatforms Base.Experimental.@compiler_options compile=min optimize=0 infer=false -const PATH_list = String[] -const LIBPATH_list = String[] - -export libgfortran, libstdcxx, libgomp - -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libgfortran_handle::Ptr{Cvoid} = C_NULL -libgfortran_path::String = "" -libstdcxx_handle::Ptr{Cvoid} = C_NULL -libstdcxx_path::String = "" -libgomp_handle::Ptr{Cvoid} = C_NULL -libgomp_path::String = "" +export libgcc_s, libgomp, libstdcxx, libquadmath, libgfortran, libssp if Sys.iswindows() if arch(HostPlatform()) == "x86_64" - const libgcc_s = "libgcc_s_seh-1.dll" + const libgcc_s_name = "bin/libgcc_s_seh-1.dll" else - const libgcc_s = "libgcc_s_sjlj-1.dll" + const libgcc_s_name = "bin/libgcc_s_sjlj-1.dll" end - const libgfortran = string("libgfortran-", libgfortran_version(HostPlatform()).major, ".dll") - const libstdcxx = "libstdc++-6.dll" - const libgomp = "libgomp-1.dll" - const libssp = "libssp-0.dll" + const libgomp_name = "bin/libgomp-1.dll" + const libstdcxx_name = "bin/libstdc++-6.dll" + const libquadmath_name = "bin/libquadmath-0.dll" + const libgfortran_name = string("bin/libgfortran-", libgfortran_version(HostPlatform()).major, ".dll") + const libssp_name = "bin/libssp-0.dll" elseif Sys.isapple() if arch(HostPlatform()) == "aarch64" || libgfortran_version(HostPlatform()) == v"5" - const libgcc_s = "@rpath/libgcc_s.1.1.dylib" + const libgcc_s_name = "lib/libgcc_s.1.1.dylib" else - const libgcc_s = "@rpath/libgcc_s.1.dylib" + const libgcc_s_name = "lib/libgcc_s.1.dylib" end - const libgfortran = string("@rpath/", "libgfortran.", libgfortran_version(HostPlatform()).major, ".dylib") - const libstdcxx = "@rpath/libstdc++.6.dylib" - const libgomp = "@rpath/libgomp.1.dylib" - const libssp = "@rpath/libssp.0.dylib" + const libgomp_name = "lib/libgomp.1.dylib" + const libstdcxx_name = "lib/libstdc++.6.dylib" + const libquadmath_name = "lib/libquadmath.0.dylib" + const libgfortran_name = string("lib/", "libgfortran.", libgfortran_version(HostPlatform()).major, ".dylib") + const libssp_name = "lib/libssp.0.dylib" else - const libgcc_s = "libgcc_s.so.1" - const libgfortran = string("libgfortran.so.", libgfortran_version(HostPlatform()).major) - const libstdcxx = "libstdc++.so.6" - const libgomp = "libgomp.so.1" + const libgcc_s_name = "lib/libgcc_s.so.1" + const libgomp_name = "lib/libgomp.so.1" + const libstdcxx_name = "lib/libstdc++.so.6" + const libquadmath_name = "lib/libquadmath.so.0" + const libgfortran_name = string("lib/libgfortran.so.", libgfortran_version(HostPlatform()).major) if libc(HostPlatform()) != "musl" - const libssp = "libssp.so.0" + const libssp_name = "lib/libssp.so.0" end end -function __init__() - global libgcc_s_handle = dlopen(libgcc_s) - global libgcc_s_path = dlpath(libgcc_s_handle) - global libgfortran_handle = dlopen(libgfortran) - global libgfortran_path = dlpath(libgfortran_handle) - global libstdcxx_handle = dlopen(libstdcxx) - global libstdcxx_path = dlpath(libstdcxx_handle) - global libgomp_handle = dlopen(libgomp) - global libgomp_path = dlpath(libgomp_handle) - @static if libc(HostPlatform()) != "musl" - dlopen(libssp; throw_error = false) - end - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libgcc_s_path) - push!(LIBPATH_list, LIBPATH[]) +const libgcc_s_path = BundledLazyLibraryPath(libgcc_s_name) +const libgomp_path = BundledLazyLibraryPath(libgomp_name) +const libstdcxx_path = BundledLazyLibraryPath(libstdcxx_name) +const libquadmath_path = BundledLazyLibraryPath(libquadmath_name) +const libgfortran_path = BundledLazyLibraryPath(libgfortran_name) +if libc(HostPlatform()) != "musl" + const libssp_path = BundledLazyLibraryPath(libssp_name) end -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libgfortran_path() = libgfortran_path -get_libstdcxx_path() = libstdcxx_path -get_libgomp_path() = libgomp_path +const libgcc_s = LazyLibrary(libgcc_s_path) +const libgomp = LazyLibrary(libgomp_path) +const libstdcxx = LazyLibrary(libstdcxx_path; dependencies=[libgcc_s]) +const libquadmath = LazyLibrary(libquadmath_path) +const libgfortran = LazyLibrary(libgfortran_path; dependencies=[libquadmath, libgcc_s]) +if libc(HostPlatform()) != "musl" + const libssp = LazyLibrary(libssp_path) +end end # module CompilerSupportLibraries_jll diff --git a/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl b/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl index 73966e1b8d742..9dd1eb4703097 100644 --- a/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl +++ b/stdlib/MbedTLS_jll/src/MbedTLS_jll.jl @@ -26,7 +26,6 @@ const libmbedx509_path = BundledLazyLibraryPath(libmbedx509_name) const libmbedcrypto = LazyLibrary(libmbedcrypto_path) const libmbedx509 = LazyLibrary(libmbedx509_path; dependencies=[libmbedcrypto]) -libmbedtls_stack = Any[] -const libmbedtls = LazyLibrary(libmbedtls_path; dependencies=[libmbedcrypto, libmbedx509], on_load_callback = () -> push!(libmbedtls_stack, stacktrace())) +const libmbedtls = LazyLibrary(libmbedtls_path; dependencies=[libmbedcrypto, libmbedx509]) end # module MbedTLS_jll diff --git a/stdlib/OpenBLAS_jll/Project.toml b/stdlib/OpenBLAS_jll/Project.toml index 529c9945e65f1..6d953327003be 100644 --- a/stdlib/OpenBLAS_jll/Project.toml +++ b/stdlib/OpenBLAS_jll/Project.toml @@ -3,7 +3,6 @@ uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" version = "0.3.23+0" [deps] -# See note in `src/OpenBLAS_jll.jl` about this dependency. CompilerSupportLibraries_jll = "e66e0078-7015-5450-92f7-15fbd957f2ae" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" diff --git a/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl b/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl index d2ba79282f605..ec1a3b5f693af 100644 --- a/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl +++ b/stdlib/OpenBLAS_jll/src/OpenBLAS_jll.jl @@ -2,7 +2,7 @@ ## dummy stub for https://github.com/JuliaBinaryWrappers/OpenBLAS_jll.jl baremodule OpenBLAS_jll -using Base, Libdl, Base.BinaryPlatforms +using Base, Libdl, Base.BinaryPlatforms, CompilerSupportLibraries_jll export libopenblas if Base.USE_BLAS64 @@ -13,18 +13,12 @@ end if Sys.iswindows() const libopenblas_name = "bin/libopenblas$(libsuffix).dll" - const libgfortran_name = string("libgfortran-", libgfortran_version(HostPlatform()).major, ".dll") elseif Sys.isapple() const libopenblas_name = "lib/libopenblas$(libsuffix).dylib" - const libgfortran_name = string("lib/libgfortran.", libgfortran_version(HostPlatform()).major, ".dylib") else const libopenblas_name = "lib/libopenblas$(libsuffix).so" - const libgfortran_name = string("lib/libgfortran.so.", libgfortran_version(HostPlatform()).major) end -const libgfortran_path = BundledLazyLibraryPath(libgfortran_name) -const libgfortran = LazyLibrary(libgfortran_path) - const libopenblas_path = BundledLazyLibraryPath(libopenblas_name) const libopenblas = LazyLibrary(libopenblas_path; dependencies=[libgfortran]) diff --git a/stdlib/dSFMT_jll/src/dSFMT_jll.jl b/stdlib/dSFMT_jll/src/dSFMT_jll.jl index 35ada23778a94..0bd51a217e213 100644 --- a/stdlib/dSFMT_jll/src/dSFMT_jll.jl +++ b/stdlib/dSFMT_jll/src/dSFMT_jll.jl @@ -6,41 +6,16 @@ baremodule dSFMT_jll using Base, Libdl Base.Experimental.@compiler_options compile=min optimize=0 infer=false -const PATH_list = String[] -const LIBPATH_list = String[] - export libdSFMT -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libdSFMT_handle::Ptr{Cvoid} = C_NULL -libdSFMT_path::String = "" - if Sys.iswindows() - const libdSFMT = "libdSFMT.dll" + const libdSFMT_name = "bin/libdSFMT.dll" elseif Sys.isapple() - const libdSFMT = "@rpath/libdSFMT.dylib" + const libdSFMT_name = "lib/libdSFMT.dylib" else - const libdSFMT = "libdSFMT.so" + const libdSFMT_name = "lib/libdSFMT.so" end - -function __init__() - global libdSFMT_handle = dlopen(libdSFMT) - global libdSFMT_path = dlpath(libdSFMT_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libdSFMT_path) - push!(LIBPATH_list, LIBPATH[]) -end - -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libdSFMT_path() = libdSFMT_path +const libdSFMT_path = BundledLazyLibraryPath(libdSFMT_name) +const libdSFMT = LazyLibrary(libdSFMT_path) end # module dSFMT_jll From 30dfa21efc5679051a052b23e91c92823812f815 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Wed, 26 Jul 2023 16:08:50 -0400 Subject: [PATCH 3/4] Change `Random` to use `dSFMT_jll` --- pkgimage.mk | 4 ++-- stdlib/Random/Project.toml | 1 + stdlib/Random/src/DSFMT.jl | 15 ++++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pkgimage.mk b/pkgimage.mk index 9ee39d10209ac..bd8d46a1a289e 100644 --- a/pkgimage.mk +++ b/pkgimage.mk @@ -86,17 +86,17 @@ $(eval $(call sysimg_builder,nghttp2_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,OpenLibm_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,PCRE2_jll,Artifacts Libdl)) $(eval $(call sysimg_builder,Zlib_jll,Artifacts Libdl)) -$(eval $(call pkgimg_builder,dSFMT_jll,Artifacts Libdl)) +$(eval $(call sysimg_builder,dSFMT_jll,Artifacts Libdl)) $(eval $(call pkgimg_builder,libLLVM_jll,Artifacts Libdl)) $(eval $(call sysimg_builder,libblastrampoline_jll,Artifacts Libdl)) $(eval $(call sysimg_builder,OpenBLAS_jll,Artifacts Libdl)) $(eval $(call sysimg_builder,Markdown,Base64)) $(eval $(call sysimg_builder,Printf,Unicode)) -$(eval $(call sysimg_builder,Random,SHA)) $(eval $(call sysimg_builder,Tar,ArgTools,SHA)) $(eval $(call pkgimg_builder,DelimitedFiles,Mmap)) # 2-depth packages +$(eval $(call sysimg_builder,Random,SHA dSFMT_jll)) $(eval $(call pkgimg_builder,LLD_jll,Zlib_jll libLLVM_jll Artifacts Libdl)) $(eval $(call sysimg_builder,LibSSH2_jll,Artifacts Libdl MbedTLS_jll)) $(eval $(call pkgimg_builder,MPFR_jll,Artifacts Libdl GMP_jll)) diff --git a/stdlib/Random/Project.toml b/stdlib/Random/Project.toml index f32fc3e2a4f84..0cb89ddecdf5c 100644 --- a/stdlib/Random/Project.toml +++ b/stdlib/Random/Project.toml @@ -2,6 +2,7 @@ name = "Random" uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [deps] +dSFMT_jll = "05ff407c-b0c1-5878-9df8-858cc2e60c36" SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" [extras] diff --git a/stdlib/Random/src/DSFMT.jl b/stdlib/Random/src/DSFMT.jl index 4c5cb8c522667..a78a8124758ed 100644 --- a/stdlib/Random/src/DSFMT.jl +++ b/stdlib/Random/src/DSFMT.jl @@ -4,6 +4,7 @@ module DSFMT import Base: copy, copy!, ==, hash using Base.GMP.MPZ +using dSFMT_jll export DSFMT_state, dsfmt_get_min_array_size, dsfmt_get_idstring, dsfmt_init_gen_rand, dsfmt_init_by_array, dsfmt_gv_init_by_array, @@ -44,14 +45,14 @@ hash(s::DSFMT_state, h::UInt) = hash(s.val, h) ## wrapper functions function dsfmt_get_idstring() - idstring = ccall((:dsfmt_get_idstring,:libdSFMT), + idstring = ccall((:dsfmt_get_idstring,libdSFMT), Ptr{UInt8}, ()) return unsafe_string(idstring) end function dsfmt_get_min_array_size() - min_array_size = ccall((:dsfmt_get_min_array_size,:libdSFMT), + min_array_size = ccall((:dsfmt_get_min_array_size,libdSFMT), Int32, ()) end @@ -59,21 +60,21 @@ end const dsfmt_min_array_size = dsfmt_get_min_array_size() function dsfmt_init_gen_rand(s::DSFMT_state, seed::UInt32) - ccall((:dsfmt_init_gen_rand,:libdSFMT), + ccall((:dsfmt_init_gen_rand,libdSFMT), Cvoid, (Ptr{Cvoid}, UInt32,), s.val, seed) end function dsfmt_init_by_array(s::DSFMT_state, seed::Vector{UInt32}) - ccall((:dsfmt_init_by_array,:libdSFMT), + ccall((:dsfmt_init_by_array,libdSFMT), Cvoid, (Ptr{Cvoid}, Ptr{UInt32}, Int32), s.val, seed, length(seed)) end function dsfmt_gv_init_by_array(seed::Vector{UInt32}) - ccall((:dsfmt_gv_init_by_array,:libdSFMT), + ccall((:dsfmt_gv_init_by_array,libdSFMT), Cvoid, (Ptr{UInt32}, Int32), seed, length(seed)) @@ -82,7 +83,7 @@ end function dsfmt_fill_array_close1_open2!(s::DSFMT_state, A::Ptr{Float64}, n::Int) @assert Csize_t(A) % 16 == 0 # the underlying C array must be 16-byte aligned @assert dsfmt_min_array_size <= n && iseven(n) - ccall((:dsfmt_fill_array_close1_open2,:libdSFMT), + ccall((:dsfmt_fill_array_close1_open2,libdSFMT), Cvoid, (Ptr{Cvoid}, Ptr{Float64}, Int), s.val, A, n) @@ -91,7 +92,7 @@ end function dsfmt_fill_array_close_open!(s::DSFMT_state, A::Ptr{Float64}, n::Int) @assert Csize_t(A) % 16 == 0 # the underlying C array must be 16-byte aligned @assert dsfmt_min_array_size <= n && iseven(n) - ccall((:dsfmt_fill_array_close_open,:libdSFMT), + ccall((:dsfmt_fill_array_close_open,libdSFMT), Cvoid, (Ptr{Cvoid}, Ptr{Float64}, Int), s.val, A, n) From 12269e0b9c69979bb46b78896fd897296bd19550 Mon Sep 17 00:00:00 2001 From: Elliot Saba Date: Thu, 27 Jul 2023 11:16:10 -0400 Subject: [PATCH 4/4] Lazy base JLLs This implements lazy libraries for the three potentially-lazy libraries needed by Base, `PCRE2_jll`, `GMP_jll` and `MPFR_jll`. Because these libraries are needed by bootstrap (and in the case of `PCRE2`, needed by Julia's own initialization) we have to go through some extra work to get them to properly load lazily. We move the `LazyLibraryPath` definition to be much earlier in the bootstrap process and use this path to load e.g. `GMP` and `MPFR` during bootstrap, but then replace that path with a `LazyLibrary` after bootstrap has finished. This provides a mechanism for loading things before e.g. `dlopen()` has been defined. --- base/Base.jl | 4 + base/base_jll_adapters.jl | 117 ++++++++++++++ base/base_jll_insertion.jl | 18 +++ base/gmp.jl | 106 ++++++------- base/libdl.jl | 43 +---- base/mpfr.jl | 252 +++++++++++++++--------------- base/pcre.jl | 39 +++-- stdlib/GMP_jll/src/GMP_jll.jl | 47 ++---- stdlib/MPFR_jll/src/MPFR_jll.jl | 36 +---- stdlib/PCRE2_jll/src/PCRE2_jll.jl | 33 +--- 10 files changed, 355 insertions(+), 340 deletions(-) create mode 100644 base/base_jll_adapters.jl create mode 100644 base/base_jll_insertion.jl diff --git a/base/Base.jl b/base/Base.jl index ecc0f0e5522ed..1c012c6288d7a 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -291,6 +291,7 @@ include("iobuffer.jl") # strings & printing include("intfuncs.jl") include("strings/strings.jl") +include("base_jll_adapters.jl") include("regex.jl") include("parse.jl") include("shell.jl") @@ -497,6 +498,9 @@ include(mapexpr::Function, mod::Module, _path::AbstractString) = _include(mapexp Core.println("JuliaSyntax/src/JuliaSyntax.jl") include(@__MODULE__, "JuliaSyntax/src/JuliaSyntax.jl") +# Finish up by inserting lazy libraries for the JLLS that must be loaded during bootstrap +include(@__MODULE__, "base_jll_insertion.jl") + end_base_include = time_ns() const _sysimage_modules = PkgId[] diff --git a/base/base_jll_adapters.jl b/base/base_jll_adapters.jl new file mode 100644 index 0000000000000..a8a63d7c33c8f --- /dev/null +++ b/base/base_jll_adapters.jl @@ -0,0 +1,117 @@ +# This file serves as a way to provide access to libraries that Base needs +# that are usually included as artifacts. We can't use Artifacts this early +# becuase we haven't bootstrapped far enough, so this file contains "Base" +# JLLs that are manually adapted to load things from hardcoded paths so that +# we can bootstrap, but once GMP_jll, MPFR_jll, etc... are loaded, we replace +# the definitions here with the `LazyLibrary` objects defined there, as they +# may be overloaded by Preferences and refer to a different library than we +# would have used during bootstrap. +module JLLAdapters + +# We're early enough that we don't have access to `Sys.iswindows()`, etc... +const UNAME = ccall(:jl_get_UNAME, Any, ())::Symbol +const early_pathsep = (UNAME === :Windows || UNAME === :NT) ? "\\" : "/" + +function early_joinpath(pieces...) + result = pieces[1] + for piece in pieces[2:end] + result = string(result, early_pathsep, piece) + end + return result +end + +""" + LazyLibraryPath + +Helper type for lazily constructed library paths for use with `LazyLibrary`. +Arguments are passed to `joinpath()`. Arguments must be able to have +`string()` called on them. + +``` +libfoo = LazyLibrary(LazyLibraryPath(prefix, "lib/libfoo.so.1.2.3")) +``` +""" +struct LazyLibraryPath + pieces::Vector + LazyLibraryPath(pieces::Vector) = new(pieces) +end +LazyLibraryPath(args...) = LazyLibraryPath(collect(args)) +Base.string(llp::LazyLibraryPath) = early_joinpath([string(p) for p in llp.pieces]...) +Base.cconvert(::Type{Cstring}, llp::LazyLibraryPath) = Base.cconvert(Cstring, string(llp)) +# Define `print` so that we can wrap this in a `LazyString` +Base.print(io::IO, llp::LazyLibraryPath) = print(io, string(llp)) + +# Helper to get `Sys.BINDIR` at runtime +struct SysBindirGetter; end +Base.string(::SysBindirGetter) = string(ccall(:jl_get_julia_bindir, Any, ())::String, early_pathsep, "..") + +""" + BundledLazyLibraryPath + +Helper type for lazily constructed library paths that are stored within the +bundled Julia distribution, primarily for use by Base modules. + +``` +libfoo = LazyLibrary(BundledLazyLibraryPath("lib/libfoo.so.1.2.3")) +``` +""" +BundledLazyLibraryPath(subpath) = LazyLibraryPath(SysBindirGetter(), subpath) + +# PCRE +if (UNAME === :Windows || UNAME === :NT) + const libpcre2_8_name = "bin/libpcre2-8-0.dll" +elseif (UNAME === :Apple || UNAME === :Darwin) + const libpcre2_8_name = "lib/libpcre2-8.0.dylib" +else + const libpcre2_8_name = "lib/libpcre2-8.so.0" +end + +const libpcre2_8 = Ref{Any}(BundledLazyLibraryPath(libpcre2_8_name)) +function get_libpcre2_8() + if isa(libpcre2_8[], LazyLibraryPath) + return string(libpcre2_8[]) + end + return libpcre2_8[] +end + +# GMP +if (UNAME === :Windows || UNAME === :NT) + const libgmp_name = "bin/libgmp-10.dll" +elseif (UNAME === :Apple || UNAME === :Darwin) + const libgmp_name = "lib/libgmp.10.dylib" +else + const libgmp_name = "lib/libgmp.so.10" +end +const libgmp = Ref{Any}(BundledLazyLibraryPath(libgmp_name)) +function get_libgmp() + if isa(libgmp[], LazyLibraryPath) + return string(libgmp[]) + end + return libgmp[] +end + + +# MPFR +if (UNAME === :Windows || UNAME === :NT) + const libmpfr_name = "bin/libmpfr-6.dll" +elseif (UNAME === :Apple || UNAME === :Darwin) + const libmpfr_name = "lib/libmpfr.6.dylib" +else + const libmpfr_name = "lib/libmpfr.so.6" +end +const libmpfr = Ref{Any}(BundledLazyLibraryPath(libmpfr_name)) +function get_libmpfr() + # Work around early bootstrap problems where we need to load `libgmp` + # when `libmpfr` is loaded. This only works if we're far enough along + # in bootstrap to be able to call `dlopen()`! Later, `libmpfr[]` + # is going to return a `LazyLibrary` that will have a dependency on + # `libgmp[]`. + if isa(libmpfr[], LazyLibraryPath) + Base.Libc.Libdl.dlopen(get_libgmp()) + return string(libmpfr[]) + end + return libmpfr[] +end + + +end # module JLLAdapters diff --git a/base/base_jll_insertion.jl b/base/base_jll_insertion.jl new file mode 100644 index 0000000000000..88a25666200a5 --- /dev/null +++ b/base/base_jll_insertion.jl @@ -0,0 +1,18 @@ +# Insert LazyLibrary for `libpcre`, although at this time this gets lazily +# on startup because `include()` calls `isdirpath()` which has a regex in it. +using Base.JLLAdapters: libpcre2_8, libpcre2_8_name +using Base.Libc.Libdl: BundledLazyLibraryPath, LazyLibrary +libpcre2_8[] = LazyLibrary(BundledLazyLibraryPath(libpcre2_8_name)) + + +# Insert LazyLibrary for `libgmp` +using Base.JLLAdapters: libgmp, libgmp_name +using Base.Libc.Libdl: BundledLazyLibraryPath, LazyLibrary +using Base.GMP: libgmp_init +libgmp[] = LazyLibrary(BundledLazyLibraryPath(libgmp_name); on_load_callback=libgmp_init) + +# Insert LazyLibrary for `libmpfr` +using Base.JLLAdapters: libgmp, libmpfr, libmpfr_name +using Base.Libc.Libdl: BundledLazyLibraryPath, LazyLibrary +using Base.MPFR: libmpfr_init +libmpfr[] = LazyLibrary(BundledLazyLibraryPath(libmpfr_name); dependencies=[libgmp[]], on_load_callback=libmpfr_init) diff --git a/base/gmp.jl b/base/gmp.jl index 8a1451be7a590..c33696e4ac5c4 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -21,16 +21,10 @@ else end const CdoubleMax = Union{Float16, Float32, Float64} -if Sys.iswindows() - const libgmp = "libgmp-10.dll" -elseif Sys.isapple() - const libgmp = "@rpath/libgmp.10.dylib" -else - const libgmp = "libgmp.so.10" -end +using .Base.JLLAdapters: get_libgmp -version() = VersionNumber(unsafe_string(unsafe_load(cglobal((:__gmp_version, libgmp), Ptr{Cchar})))) -bits_per_limb() = Int(unsafe_load(cglobal((:__gmp_bits_per_limb, libgmp), Cint))) +version() = VersionNumber(unsafe_string(unsafe_load(cglobal((:__gmp_version, get_libgmp()), Ptr{Cchar})))) +bits_per_limb() = Int(unsafe_load(cglobal((:__gmp_bits_per_limb, get_libgmp()), Cint))) const VERSION = version() const BITS_PER_LIMB = bits_per_limb() @@ -62,7 +56,7 @@ mutable struct BigInt <: Signed function BigInt(; nbits::Integer=0) b = MPZ.init2!(new(), nbits) - finalizer(cglobal((:__gmpz_clear, libgmp)), b) + finalizer(cglobal((:__gmpz_clear, get_libgmp())), b) return b end end @@ -100,6 +94,11 @@ does not abort on huge allocation and throws OutOfMemoryError instead. const ALLOC_OVERFLOW_FUNCTION = Ref(false) function __init__() + # Resuscitate GMP.ONE object + ONE.alloc, ONE.size, ONE.d = 1, 1, pointer(_ONE) +end + +function libgmp_init() try if version().major != VERSION.major || bits_per_limb() != BITS_PER_LIMB msg = """The dynamically loaded GMP library (v\"$(version())\" with __gmp_bits_per_limb == $(bits_per_limb())) @@ -108,19 +107,17 @@ function __init__() bits_per_limb() != BITS_PER_LIMB ? @error(msg) : @warn(msg) end - ccall((:__gmp_set_memory_functions, libgmp), Cvoid, + ccall((:__gmp_set_memory_functions, get_libgmp()), Cvoid, (Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid}), cglobal(:jl_gc_counted_malloc), cglobal(:jl_gc_counted_realloc_with_old_size), cglobal(:jl_gc_counted_free_with_size)) - ZERO.alloc, ZERO.size, ZERO.d = 0, 0, C_NULL - ONE.alloc, ONE.size, ONE.d = 1, 1, pointer(_ONE) catch ex Base.showerror_nostdio(ex, "WARNING: Error during initialization of module GMP") end # This only works with a patched version of GMP, ignore otherwise try - ccall((:__gmp_set_alloc_overflow_function, libgmp), Cvoid, + ccall((:__gmp_set_alloc_overflow_function, get_libgmp()), Cvoid, (Ptr{Cvoid},), cglobal(:jl_throw_out_of_memory_error)) ALLOC_OVERFLOW_FUNCTION[] = true @@ -140,20 +137,20 @@ module MPZ # - a method modifying its input has a "!" appended to its name, according to Julia's conventions # - some convenient methods are added (in addition to the pure MPZ ones), e.g. `add(a, b) = add!(BigInt(), a, b)` # and `add!(x, a) = add!(x, x, a)`. -using ..GMP: BigInt, Limb, BITS_PER_LIMB, libgmp +using ..GMP: BigInt, Limb, BITS_PER_LIMB, get_libgmp const mpz_t = Ref{BigInt} const bitcnt_t = Culong -gmpz(op::Symbol) = (Symbol(:__gmpz_, op), libgmp) +gmpz(op::Symbol) = (Symbol(:__gmpz_, op), get_libgmp()) -init!(x::BigInt) = (ccall((:__gmpz_init, libgmp), Cvoid, (mpz_t,), x); x) -init2!(x::BigInt, a) = (ccall((:__gmpz_init2, libgmp), Cvoid, (mpz_t, bitcnt_t), x, a); x) +init!(x::BigInt) = (ccall((:__gmpz_init, get_libgmp()), Cvoid, (mpz_t,), x); x) +init2!(x::BigInt, a) = (ccall((:__gmpz_init2, get_libgmp()), Cvoid, (mpz_t, bitcnt_t), x, a); x) -realloc2!(x, a) = (ccall((:__gmpz_realloc2, libgmp), Cvoid, (mpz_t, bitcnt_t), x, a); x) +realloc2!(x, a) = (ccall((:__gmpz_realloc2, get_libgmp()), Cvoid, (mpz_t, bitcnt_t), x, a); x) realloc2(a) = realloc2!(BigInt(), a) -sizeinbase(a::BigInt, b) = Int(ccall((:__gmpz_sizeinbase, libgmp), Csize_t, (mpz_t, Cint), a, b)) +sizeinbase(a::BigInt, b) = Int(ccall((:__gmpz_sizeinbase, get_libgmp()), Csize_t, (mpz_t, Cint), a, b)) for (op, nbits) in (:add => :(BITS_PER_LIMB*(1 + max(abs(a.size), abs(b.size)))), :sub => :(BITS_PER_LIMB*(1 + max(abs(a.size), abs(b.size)))), @@ -169,7 +166,7 @@ for (op, nbits) in (:add => :(BITS_PER_LIMB*(1 + max(abs(a.size), abs(b.size)))) end invert!(x::BigInt, a::BigInt, b::BigInt) = - ccall((:__gmpz_invert, libgmp), Cint, (mpz_t, mpz_t, mpz_t), x, a, b) + ccall((:__gmpz_invert, get_libgmp()), Cint, (mpz_t, mpz_t, mpz_t), x, a, b) invert(a::BigInt, b::BigInt) = invert!(BigInt(), a, b) invert!(x::BigInt, b::BigInt) = invert!(x, x, b) @@ -182,7 +179,7 @@ for op in (:add_ui, :sub_ui, :mul_ui, :mul_2exp, :fdiv_q_2exp, :pow_ui, :bin_ui) end end -ui_sub!(x::BigInt, a, b::BigInt) = (ccall((:__gmpz_ui_sub, libgmp), Cvoid, (mpz_t, Culong, mpz_t), x, a, b); x) +ui_sub!(x::BigInt, a, b::BigInt) = (ccall((:__gmpz_ui_sub, get_libgmp()), Cvoid, (mpz_t, Culong, mpz_t), x, a, b); x) ui_sub(a, b::BigInt) = ui_sub!(BigInt(), a, b) for op in (:scan1, :scan0) @@ -191,7 +188,7 @@ for op in (:scan1, :scan0) @eval $op(a::BigInt, b) = Int(signed(ccall($(gmpz(op)), Culong, (mpz_t, Culong), a, b))) end -mul_si!(x::BigInt, a::BigInt, b) = (ccall((:__gmpz_mul_si, libgmp), Cvoid, (mpz_t, mpz_t, Clong), x, a, b); x) +mul_si!(x::BigInt, a::BigInt, b) = (ccall((:__gmpz_mul_si, get_libgmp()), Cvoid, (mpz_t, mpz_t, Clong), x, a, b); x) mul_si(a::BigInt, b) = mul_si!(BigInt(), a, b) mul_si!(x::BigInt, b) = mul_si!(x, x, b) @@ -213,64 +210,63 @@ for (op, T) in ((:fac_ui, Culong), (:set_ui, Culong), (:set_si, Clong), (:set_d, end end -popcount(a::BigInt) = Int(signed(ccall((:__gmpz_popcount, libgmp), Culong, (mpz_t,), a))) +popcount(a::BigInt) = Int(signed(ccall((:__gmpz_popcount, get_libgmp()), Culong, (mpz_t,), a))) -mpn_popcount(d::Ptr{Limb}, s::Integer) = Int(ccall((:__gmpn_popcount, libgmp), Culong, (Ptr{Limb}, Csize_t), d, s)) +mpn_popcount(d::Ptr{Limb}, s::Integer) = Int(ccall((:__gmpn_popcount, get_libgmp()), Culong, (Ptr{Limb}, Csize_t), d, s)) mpn_popcount(a::BigInt) = mpn_popcount(a.d, abs(a.size)) function tdiv_qr!(x::BigInt, y::BigInt, a::BigInt, b::BigInt) - ccall((:__gmpz_tdiv_qr, libgmp), Cvoid, (mpz_t, mpz_t, mpz_t, mpz_t), x, y, a, b) + ccall((:__gmpz_tdiv_qr, get_libgmp()), Cvoid, (mpz_t, mpz_t, mpz_t, mpz_t), x, y, a, b) x, y end tdiv_qr(a::BigInt, b::BigInt) = tdiv_qr!(BigInt(), BigInt(), a, b) powm!(x::BigInt, a::BigInt, b::BigInt, c::BigInt) = - (ccall((:__gmpz_powm, libgmp), Cvoid, (mpz_t, mpz_t, mpz_t, mpz_t), x, a, b, c); x) + (ccall((:__gmpz_powm, get_libgmp()), Cvoid, (mpz_t, mpz_t, mpz_t, mpz_t), x, a, b, c); x) powm(a::BigInt, b::BigInt, c::BigInt) = powm!(BigInt(), a, b, c) powm!(x::BigInt, b::BigInt, c::BigInt) = powm!(x, x, b, c) function gcdext!(x::BigInt, y::BigInt, z::BigInt, a::BigInt, b::BigInt) - ccall((:__gmpz_gcdext, libgmp), Cvoid, (mpz_t, mpz_t, mpz_t, mpz_t, mpz_t), x, y, z, a, b) + ccall((:__gmpz_gcdext, get_libgmp()), Cvoid, (mpz_t, mpz_t, mpz_t, mpz_t, mpz_t), x, y, z, a, b) x, y, z end gcdext(a::BigInt, b::BigInt) = gcdext!(BigInt(), BigInt(), BigInt(), a, b) -cmp(a::BigInt, b::BigInt) = Int(ccall((:__gmpz_cmp, libgmp), Cint, (mpz_t, mpz_t), a, b)) -cmp_si(a::BigInt, b) = Int(ccall((:__gmpz_cmp_si, libgmp), Cint, (mpz_t, Clong), a, b)) -cmp_ui(a::BigInt, b) = Int(ccall((:__gmpz_cmp_ui, libgmp), Cint, (mpz_t, Culong), a, b)) -cmp_d(a::BigInt, b) = Int(ccall((:__gmpz_cmp_d, libgmp), Cint, (mpz_t, Cdouble), a, b)) +cmp(a::BigInt, b::BigInt) = Int(ccall((:__gmpz_cmp, get_libgmp()), Cint, (mpz_t, mpz_t), a, b)) +cmp_si(a::BigInt, b) = Int(ccall((:__gmpz_cmp_si, get_libgmp()), Cint, (mpz_t, Clong), a, b)) +cmp_ui(a::BigInt, b) = Int(ccall((:__gmpz_cmp_ui, get_libgmp()), Cint, (mpz_t, Culong), a, b)) +cmp_d(a::BigInt, b) = Int(ccall((:__gmpz_cmp_d, get_libgmp()), Cint, (mpz_t, Cdouble), a, b)) -mpn_cmp(a::Ptr{Limb}, b::Ptr{Limb}, c) = ccall((:__gmpn_cmp, libgmp), Cint, (Ptr{Limb}, Ptr{Limb}, Clong), a, b, c) +mpn_cmp(a::Ptr{Limb}, b::Ptr{Limb}, c) = ccall((:__gmpn_cmp, get_libgmp()), Cint, (Ptr{Limb}, Ptr{Limb}, Clong), a, b, c) mpn_cmp(a::BigInt, b::BigInt, c) = mpn_cmp(a.d, b.d, c) -get_str!(x, a, b::BigInt) = (ccall((:__gmpz_get_str,libgmp), Ptr{Cchar}, (Ptr{Cchar}, Cint, mpz_t), x, a, b); x) -set_str!(x::BigInt, a, b) = Int(ccall((:__gmpz_set_str, libgmp), Cint, (mpz_t, Ptr{UInt8}, Cint), x, a, b)) -get_d(a::BigInt) = ccall((:__gmpz_get_d, libgmp), Cdouble, (mpz_t,), a) +get_str!(x, a, b::BigInt) = (ccall((:__gmpz_get_str,get_libgmp()), Ptr{Cchar}, (Ptr{Cchar}, Cint, mpz_t), x, a, b); x) +set_str!(x::BigInt, a, b) = Int(ccall((:__gmpz_set_str, get_libgmp()), Cint, (mpz_t, Ptr{UInt8}, Cint), x, a, b)) +get_d(a::BigInt) = ccall((:__gmpz_get_d, get_libgmp()), Cdouble, (mpz_t,), a) function export!(a::AbstractVector{T}, n::BigInt; order::Integer=-1, nails::Integer=0, endian::Integer=0) where {T<:Base.BitInteger} stride(a, 1) == 1 || throw(ArgumentError("a must have stride 1")) ndigits = cld(sizeinbase(n, 2), 8*sizeof(T) - nails) length(a) < ndigits && resize!(a, ndigits) count = Ref{Csize_t}() - ccall((:__gmpz_export, libgmp), Ptr{T}, (Ptr{T}, Ref{Csize_t}, Cint, Csize_t, Cint, Csize_t, mpz_t), + ccall((:__gmpz_export, get_libgmp()), Ptr{T}, (Ptr{T}, Ref{Csize_t}, Cint, Csize_t, Cint, Csize_t, mpz_t), a, count, order, sizeof(T), endian, nails, n) @assert count[] ≤ length(a) return a, Int(count[]) end -limbs_write!(x::BigInt, a) = ccall((:__gmpz_limbs_write, libgmp), Ptr{Limb}, (mpz_t, Clong), x, a) -limbs_finish!(x::BigInt, a) = ccall((:__gmpz_limbs_finish, libgmp), Cvoid, (mpz_t, Clong), x, a) -import!(x::BigInt, a, b, c, d, e, f) = ccall((:__gmpz_import, libgmp), Cvoid, +limbs_write!(x::BigInt, a) = ccall((:__gmpz_limbs_write, get_libgmp()), Ptr{Limb}, (mpz_t, Clong), x, a) +limbs_finish!(x::BigInt, a) = ccall((:__gmpz_limbs_finish, get_libgmp()), Cvoid, (mpz_t, Clong), x, a) +import!(x::BigInt, a, b, c, d, e, f) = ccall((:__gmpz_import, get_libgmp()), Cvoid, (mpz_t, Csize_t, Cint, Csize_t, Cint, Csize_t, Ptr{Cvoid}), x, a, b, c, d, e, f) -setbit!(x, a) = (ccall((:__gmpz_setbit, libgmp), Cvoid, (mpz_t, bitcnt_t), x, a); x) -tstbit(a::BigInt, b) = ccall((:__gmpz_tstbit, libgmp), Cint, (mpz_t, bitcnt_t), a, b) % Bool +setbit!(x, a) = (ccall((:__gmpz_setbit, get_libgmp()), Cvoid, (mpz_t, bitcnt_t), x, a); x) +tstbit(a::BigInt, b) = ccall((:__gmpz_tstbit, get_libgmp()), Cint, (mpz_t, bitcnt_t), a, b) % Bool end # module MPZ -const ZERO = BigInt() -const ONE = BigInt() -const _ONE = Limb[1] +_ONE = Limb[1] +const ONE = BigInt() widen(::Type{Int128}) = BigInt widen(::Type{UInt128}) = BigInt @@ -917,9 +913,9 @@ module MPQ # Rational{BigInt} import .Base: unsafe_rational, __throw_rational_argerror_zero -import ..GMP: BigInt, MPZ, Limb, isneg, libgmp +import ..GMP: BigInt, MPZ, Limb, isneg, get_libgmp -gmpq(op::Symbol) = (Symbol(:__gmpq_, op), libgmp) +gmpq(op::Symbol) = (Symbol(:__gmpq_, op), get_libgmp()) mutable struct _MPQ num_alloc::Cint @@ -956,20 +952,20 @@ function Rational{BigInt}(num::BigInt, den::BigInt) return set_si(flipsign(1, num), 0) end xq = _MPQ(MPZ.set(num), MPZ.set(den)) - ccall((:__gmpq_canonicalize, libgmp), Cvoid, (mpq_t,), xq) + ccall((:__gmpq_canonicalize, get_libgmp()), Cvoid, (mpq_t,), xq) return sync_rational!(xq) end # define set, set_ui, set_si, set_z, and their inplace versions function set!(z::Rational{BigInt}, x::Rational{BigInt}) zq = _MPQ(z) - ccall((:__gmpq_set, libgmp), Cvoid, (mpq_t, mpq_t), zq, _MPQ(x)) + ccall((:__gmpq_set, get_libgmp()), Cvoid, (mpq_t, mpq_t), zq, _MPQ(x)) return sync_rational!(zq) end function set_z!(z::Rational{BigInt}, x::BigInt) zq = _MPQ(z) - ccall((:__gmpq_set_z, libgmp), Cvoid, (mpq_t, MPZ.mpz_t), zq, x) + ccall((:__gmpq_set_z, get_libgmp()), Cvoid, (mpq_t, MPZ.mpz_t), zq, x) return sync_rational!(zq) end @@ -1001,7 +997,7 @@ function add!(z::Rational{BigInt}, x::Rational{BigInt}, y::Rational{BigInt}) return set!(z, iszero(x.den) ? x : y) end zq = _MPQ(z) - ccall((:__gmpq_add, libgmp), Cvoid, + ccall((:__gmpq_add, get_libgmp()), Cvoid, (mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y)) return sync_rational!(zq) end @@ -1015,7 +1011,7 @@ function sub!(z::Rational{BigInt}, x::Rational{BigInt}, y::Rational{BigInt}) return set_si!(z, flipsign(-1, y.num), 0) end zq = _MPQ(z) - ccall((:__gmpq_sub, libgmp), Cvoid, + ccall((:__gmpq_sub, get_libgmp()), Cvoid, (mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y)) return sync_rational!(zq) end @@ -1028,7 +1024,7 @@ function mul!(z::Rational{BigInt}, x::Rational{BigInt}, y::Rational{BigInt}) return set_si!(z, ifelse(xor(isneg(x.num), isneg(y.num)), -1, 1), 0) end zq = _MPQ(z) - ccall((:__gmpq_mul, libgmp), Cvoid, + ccall((:__gmpq_mul, get_libgmp()), Cvoid, (mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y)) return sync_rational!(zq) end @@ -1049,7 +1045,7 @@ function div!(z::Rational{BigInt}, x::Rational{BigInt}, y::Rational{BigInt}) return set_si!(z, flipsign(1, x.num), 0) end zq = _MPQ(z) - ccall((:__gmpq_div, libgmp), Cvoid, + ccall((:__gmpq_div, get_libgmp()), Cvoid, (mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y)) return sync_rational!(zq) end @@ -1063,7 +1059,7 @@ for (fJ, fC) in ((:+, :add), (:-, :sub), (:*, :mul), (://, :div)) end function Base.cmp(x::Rational{BigInt}, y::Rational{BigInt}) - Int(ccall((:__gmpq_cmp, libgmp), Cint, (mpq_t, mpq_t), _MPQ(x), _MPQ(y))) + Int(ccall((:__gmpq_cmp, get_libgmp()), Cint, (mpq_t, mpq_t), _MPQ(x), _MPQ(y))) end end # MPQ module diff --git a/base/libdl.jl b/base/libdl.jl index 09f4ad4ea2159..f7ce3d84ef79f 100644 --- a/base/libdl.jl +++ b/base/libdl.jl @@ -11,6 +11,8 @@ export DL_LOAD_PATH, RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOC RTLD_NODELETE, RTLD_NOLOAD, RTLD_NOW, dlclose, dlopen, dlopen_e, dlsym, dlsym_e, dlpath, find_library, dlext, dllist, LazyLibrary, LazyLibraryPath, BundledLazyLibraryPath +using .Base.JLLAdapters: LazyLibraryPath, BundledLazyLibraryPath + """ DL_LOAD_PATH @@ -318,44 +320,6 @@ function dllist() end -""" - LazyLibraryPath - -Helper type for lazily constructed library paths for use with `LazyLibrary`. -Arguments are passed to `joinpath()`. Arguments must be able to have -`string()` called on them. - -``` -libfoo = LazyLibrary(LazyLibraryPath(prefix, "lib/libfoo.so.1.2.3")) -``` -""" -struct LazyLibraryPath - pieces::Vector - LazyLibraryPath(pieces::Vector) = new(pieces) -end -LazyLibraryPath(args...) = LazyLibraryPath(collect(args)) -Base.string(llp::LazyLibraryPath) = joinpath(string.(llp.pieces)...) -Base.cconvert(::Type{Cstring}, llp::LazyLibraryPath) = Base.cconvert(Cstring, string(llp)) -# Define `print` so that we can wrap this in a `LazyString` -Base.print(io::IO, llp::LazyLibraryPath) = print(io, string(llp)) - -# Helper to get `Sys.BINDIR` at runtime -struct SysBindirGetter; end -Base.string(::SysBindirGetter) = dirname(Sys.BINDIR) - -""" - BundledLazyLibraryPath - -Helper type for lazily constructed library paths that are stored within the -bundled Julia distribution, primarily for use by Base modules. - -``` -libfoo = LazyLibrary(BundledLazyLibraryPath("lib/libfoo.so.1.2.3")) -``` -""" -BundledLazyLibraryPath(subpath) = LazyLibraryPath(SysBindirGetter(), subpath) - - """ LazyLibrary(name, flags = , dependencies = LazyLibrary[], on_load_callback = nothing) @@ -445,7 +409,8 @@ function dlopen(ll::LazyLibrary, flags::Integer = ll.flags; kwargs...) return handle end -dlopen(x::Any) = throw(TypeError(:dlopen, "", Union{Symbol,String,LazyLibrary}, x)) +dlopen(llp::LazyLibraryPath, args...; kwargs...) = dlopen(string(llp), args...; kwargs...) +dlopen(x::Any) = throw(TypeError(:dlopen, "", Union{Symbol,String,LazyLibraryPath,LazyLibrary}, x)) dlsym(ll::LazyLibrary, args...; kwargs...) = dlsym(dlopen(ll), args...; kwargs...) dlpath(ll::LazyLibrary) = dlpath(dlopen(ll)) end # module Libdl diff --git a/base/mpfr.jl b/base/mpfr.jl index 774c87c71f3fe..e10bb89510980 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -23,23 +23,16 @@ import using .Base.Libc import ..Rounding: rounding_raw, setrounding_raw -import ..GMP: ClongMax, CulongMax, CdoubleMax, Limb, libgmp - +import ..GMP: ClongMax, CulongMax, CdoubleMax, Limb +import .Base.JLLAdapters: get_libgmp, get_libmpfr import ..FastMath.sincos_fast -if Sys.iswindows() - const libmpfr = "libmpfr-6.dll" -elseif Sys.isapple() - const libmpfr = "@rpath/libmpfr.6.dylib" -else - const libmpfr = "libmpfr.so.6" -end -version() = VersionNumber(unsafe_string(ccall((:mpfr_get_version,libmpfr), Ptr{Cchar}, ()))) -patches() = split(unsafe_string(ccall((:mpfr_get_patches,libmpfr), Ptr{Cchar}, ())),' ') +version() = VersionNumber(unsafe_string(ccall((:mpfr_get_version,get_libmpfr()), Ptr{Cchar}, ()))) +patches() = split(unsafe_string(ccall((:mpfr_get_patches,get_libmpfr()), Ptr{Cchar}, ())),' ') -function __init__() +function libmpfr_init() try # set exponent to full range by default set_emin!(get_emin_min()) @@ -47,7 +40,6 @@ function __init__() catch ex Base.showerror_nostdio(ex, "WARNING: Error during initialization of module MPFR") end - nothing end """ @@ -112,16 +104,16 @@ mutable struct BigFloat <: AbstractFloat global function _BigFloat(prec::Clong, sign::Cint, exp::Clong, d::String) # ccall-based version, inlined below #z = new(zero(Clong), zero(Cint), zero(Clong), C_NULL, d) - #ccall((:mpfr_custom_init,libmpfr), Cvoid, (Ptr{Limb}, Clong), d, prec) # currently seems to be a no-op in mpfr + #ccall((:mpfr_custom_init,get_libmpfr()), Cvoid, (Ptr{Limb}, Clong), d, prec) # currently seems to be a no-op in mpfr #NAN_KIND = Cint(0) - #ccall((:mpfr_custom_init_set,libmpfr), Cvoid, (Ref{BigFloat}, Cint, Clong, Ptr{Limb}), z, NAN_KIND, prec, d) + #ccall((:mpfr_custom_init_set,get_libmpfr()), Cvoid, (Ref{BigFloat}, Cint, Clong, Ptr{Limb}), z, NAN_KIND, prec, d) #return z return new(prec, sign, exp, pointer(d), d) end function BigFloat(; precision::Integer=DEFAULT_PRECISION[]) precision < 1 && throw(DomainError(precision, "`precision` cannot be less than 1.")) - nb = ccall((:mpfr_custom_get_size,libmpfr), Csize_t, (Clong,), precision) + nb = ccall((:mpfr_custom_get_size,get_libmpfr()), Csize_t, (Clong,), precision) nb = (nb + Core.sizeof(Limb) - 1) ÷ Core.sizeof(Limb) # align to number of Limb allocations required for this #d = Vector{Limb}(undef, nb) d = _string_n(nb * Core.sizeof(Limb)) @@ -197,7 +189,7 @@ function BigFloat(x::BigFloat, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::I return x else z = BigFloat(;precision=precision) - ccall((:mpfr_set, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), + ccall((:mpfr_set, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, r) return z end @@ -205,7 +197,7 @@ end function _duplicate(x::BigFloat) z = BigFloat(;precision=_precision(x)) - ccall((:mpfr_set, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, 0) + ccall((:mpfr_set, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32), z, x, 0) return z end @@ -214,7 +206,7 @@ for (fJ, fC) in ((:si,:Clong), (:ui,:Culong)) @eval begin function BigFloat(x::($fC), r::MPFRRoundingMode=ROUNDING_MODE[]; precision::Integer=DEFAULT_PRECISION[]) z = BigFloat(;precision=precision) - ccall(($(string(:mpfr_set_,fJ)), libmpfr), Int32, (Ref{BigFloat}, $fC, MPFRRoundingMode), z, x, r) + ccall(($(string(:mpfr_set_,fJ)), get_libmpfr()), Int32, (Ref{BigFloat}, $fC, MPFRRoundingMode), z, x, r) return z end end @@ -225,7 +217,7 @@ function BigFloat(x::Float64, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::In # punt on the hard case where we might have to deal with rounding # we could use this path in all cases, but mpfr_set_d has a lot of overhead. if precision <= Base.significand_bits(Float64) - ccall((:mpfr_set_d, libmpfr), Int32, (Ref{BigFloat}, Float64, MPFRRoundingMode), z, x, r) + ccall((:mpfr_set_d, get_libmpfr()), Int32, (Ref{BigFloat}, Float64, MPFRRoundingMode), z, x, r) if isnan(x) && signbit(x) != signbit(z) z.sign = -z.sign end @@ -265,7 +257,7 @@ end function BigFloat(x::BigInt, r::MPFRRoundingMode=ROUNDING_MODE[]; precision::Integer=DEFAULT_PRECISION[]) z = BigFloat(;precision=precision) - ccall((:mpfr_set_z, libmpfr), Int32, (Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, r) + ccall((:mpfr_set_z, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, r) return z end @@ -293,7 +285,7 @@ end function tryparse(::Type{BigFloat}, s::AbstractString; base::Integer=0, precision::Integer=DEFAULT_PRECISION[], rounding::MPFRRoundingMode=ROUNDING_MODE[]) !isempty(s) && isspace(s[end]) && return tryparse(BigFloat, rstrip(s), base = base) z = BigFloat(precision=precision) - err = ccall((:mpfr_set_str, libmpfr), Int32, (Ref{BigFloat}, Cstring, Int32, MPFRRoundingMode), z, s, base, rounding) + err = ccall((:mpfr_set_str, get_libmpfr()), Int32, (Ref{BigFloat}, Cstring, Int32, MPFRRoundingMode), z, s, base, rounding) err == 0 ? z : nothing end @@ -314,16 +306,16 @@ BigFloat(x::AbstractString, r::RoundingMode; precision::Integer=DEFAULT_PRECISIO _unchecked_cast(T, x::BigFloat, r::RoundingMode) = _unchecked_cast(T, x, convert(MPFRRoundingMode, r)) function _unchecked_cast(::Type{Int64}, x::BigFloat, r::MPFRRoundingMode) - ccall((:__gmpfr_mpfr_get_sj,libmpfr), Cintmax_t, (Ref{BigFloat}, MPFRRoundingMode), x, r) + ccall((:__gmpfr_mpfr_get_sj,get_libmpfr()), Cintmax_t, (Ref{BigFloat}, MPFRRoundingMode), x, r) end function _unchecked_cast(::Type{UInt64}, x::BigFloat, r::MPFRRoundingMode) - ccall((:__gmpfr_mpfr_get_uj,libmpfr), Cuintmax_t, (Ref{BigFloat}, MPFRRoundingMode), x, r) + ccall((:__gmpfr_mpfr_get_uj,get_libmpfr()), Cuintmax_t, (Ref{BigFloat}, MPFRRoundingMode), x, r) end function _unchecked_cast(::Type{BigInt}, x::BigFloat, r::MPFRRoundingMode) z = BigInt() - ccall((:mpfr_get_z, libmpfr), Int32, (Ref{BigInt}, Ref{BigFloat}, MPFRRoundingMode), z, x, r) + ccall((:mpfr_get_z, get_libmpfr()), Int32, (Ref{BigInt}, Ref{BigFloat}, MPFRRoundingMode), z, x, r) return z end @@ -384,11 +376,11 @@ end _cpynansgn(x::AbstractFloat, y::BigFloat) = isnan(x) && signbit(x) != signbit(y) ? -x : x Float64(x::BigFloat, r::MPFRRoundingMode=ROUNDING_MODE[]) = - _cpynansgn(ccall((:mpfr_get_d,libmpfr), Float64, (Ref{BigFloat}, MPFRRoundingMode), x, r), x) + _cpynansgn(ccall((:mpfr_get_d,get_libmpfr()), Float64, (Ref{BigFloat}, MPFRRoundingMode), x, r), x) Float64(x::BigFloat, r::RoundingMode) = Float64(x, convert(MPFRRoundingMode, r)) Float32(x::BigFloat, r::MPFRRoundingMode=ROUNDING_MODE[]) = - _cpynansgn(ccall((:mpfr_get_flt,libmpfr), Float32, (Ref{BigFloat}, MPFRRoundingMode), x, r), x) + _cpynansgn(ccall((:mpfr_get_flt,get_libmpfr()), Float32, (Ref{BigFloat}, MPFRRoundingMode), x, r), x) Float32(x::BigFloat, r::RoundingMode) = Float32(x, convert(MPFRRoundingMode, r)) function Float16(x::BigFloat) :: Float16 @@ -431,14 +423,14 @@ for (fJ, fC) in ((:+,:add), (:*,:mul)) # BigFloat function ($fJ)(x::BigFloat, y::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,fC)),libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)),get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end # Unsigned Integer function ($fJ)(x::BigFloat, c::CulongMax) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_ui)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_ui)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end ($fJ)(c::CulongMax, x::BigFloat) = ($fJ)(x,c) @@ -446,7 +438,7 @@ for (fJ, fC) in ((:+,:add), (:*,:mul)) # Signed Integer function ($fJ)(x::BigFloat, c::ClongMax) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_si)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_si)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end ($fJ)(c::ClongMax, x::BigFloat) = ($fJ)(x,c) @@ -454,7 +446,7 @@ for (fJ, fC) in ((:+,:add), (:*,:mul)) # Float32/Float64 function ($fJ)(x::BigFloat, c::CdoubleMax) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_d)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Cdouble, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_d)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Cdouble, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end ($fJ)(c::CdoubleMax, x::BigFloat) = ($fJ)(x,c) @@ -462,7 +454,7 @@ for (fJ, fC) in ((:+,:add), (:*,:mul)) # BigInt function ($fJ)(x::BigFloat, c::BigInt) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_z)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_z)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end ($fJ)(c::BigInt, x::BigFloat) = ($fJ)(x,c) @@ -474,50 +466,50 @@ for (fJ, fC) in ((:-,:sub), (:/,:div)) # BigFloat function ($fJ)(x::BigFloat, y::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,fC)),libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)),get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end # Unsigned Int function ($fJ)(x::BigFloat, c::CulongMax) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_ui)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_ui)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end function ($fJ)(c::CulongMax, x::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,:ui_,fC)), libmpfr), Int32, (Ref{BigFloat}, Culong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,:ui_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Culong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) return z end # Signed Integer function ($fJ)(x::BigFloat, c::ClongMax) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_si)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_si)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end function ($fJ)(c::ClongMax, x::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,:si_,fC)), libmpfr), Int32, (Ref{BigFloat}, Clong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,:si_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Clong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) return z end # Float32/Float64 function ($fJ)(x::BigFloat, c::CdoubleMax) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_d)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Cdouble, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_d)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Cdouble, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end function ($fJ)(c::CdoubleMax, x::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,:d_,fC)), libmpfr), Int32, (Ref{BigFloat}, Cdouble, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,:d_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Cdouble, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) return z end # BigInt function ($fJ)(x::BigFloat, c::BigInt) z = BigFloat() - ccall(($(string(:mpfr_,fC,:_z)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC,:_z)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, c, ROUNDING_MODE[]) return z end # no :mpfr_z_div function @@ -526,7 +518,7 @@ end function -(c::BigInt, x::BigFloat) z = BigFloat() - ccall((:mpfr_z_sub, libmpfr), Int32, (Ref{BigFloat}, Ref{BigInt}, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) + ccall((:mpfr_z_sub, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigInt}, Ref{BigFloat}, MPFRRoundingMode), z, c, x, ROUNDING_MODE[]) return z end @@ -534,7 +526,7 @@ inv(x::BigFloat) = one(Clong) / x # faster than fallback one(x)/x function fma(x::BigFloat, y::BigFloat, z::BigFloat) r = BigFloat() - ccall(("mpfr_fma",libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), r, x, y, z, ROUNDING_MODE[]) + ccall(("mpfr_fma",get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), r, x, y, z, ROUNDING_MODE[]) return r end @@ -544,58 +536,58 @@ muladd(x::BigFloat, y::BigFloat, z::BigFloat) = fma(x, y, z) # BigFloat function div(x::BigFloat, y::BigFloat) z = BigFloat() - ccall((:mpfr_div,libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_div,get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end # Unsigned Int function div(x::BigFloat, c::CulongMax) z = BigFloat() - ccall((:mpfr_div_ui, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, c, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_div_ui, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, c, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end function div(c::CulongMax, x::BigFloat) z = BigFloat() - ccall((:mpfr_ui_div, libmpfr), Int32, (Ref{BigFloat}, Culong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_ui_div, get_libmpfr()), Int32, (Ref{BigFloat}, Culong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end # Signed Integer function div(x::BigFloat, c::ClongMax) z = BigFloat() - ccall((:mpfr_div_si, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, c, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_div_si, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, c, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end function div(c::ClongMax, x::BigFloat) z = BigFloat() - ccall((:mpfr_si_div, libmpfr), Int32, (Ref{BigFloat}, Clong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_si_div, get_libmpfr()), Int32, (Ref{BigFloat}, Clong, Ref{BigFloat}, MPFRRoundingMode), z, c, x, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end # Float32/Float64 function div(x::BigFloat, c::CdoubleMax) z = BigFloat() - ccall((:mpfr_div_d, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Cdouble, MPFRRoundingMode), z, x, c, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_div_d, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Cdouble, MPFRRoundingMode), z, x, c, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end function div(c::CdoubleMax, x::BigFloat) z = BigFloat() - ccall((:mpfr_d_div, libmpfr), Int32, (Ref{BigFloat}, Cdouble, Ref{BigFloat}, MPFRRoundingMode), z, c, x, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_d_div, get_libmpfr()), Int32, (Ref{BigFloat}, Cdouble, Ref{BigFloat}, MPFRRoundingMode), z, c, x, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end # BigInt function div(x::BigFloat, c::BigInt) z = BigFloat() - ccall((:mpfr_div_z, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, c, RoundToZero) - ccall((:mpfr_trunc, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) + ccall((:mpfr_div_z, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, c, RoundToZero) + ccall((:mpfr_trunc, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, z) return z end @@ -605,23 +597,23 @@ for (fJ, fC, fI) in ((:+, :add, 0), (:*, :mul, 1)) @eval begin function ($fJ)(a::BigFloat, b::BigFloat, c::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, a, b, ROUNDING_MODE[]) - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, a, b, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, c, ROUNDING_MODE[]) return z end function ($fJ)(a::BigFloat, b::BigFloat, c::BigFloat, d::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, a, b, ROUNDING_MODE[]) - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, c, ROUNDING_MODE[]) - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, d, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, a, b, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, d, ROUNDING_MODE[]) return z end function ($fJ)(a::BigFloat, b::BigFloat, c::BigFloat, d::BigFloat, e::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, a, b, ROUNDING_MODE[]) - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, c, ROUNDING_MODE[]) - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, d, ROUNDING_MODE[]) - ccall(($(string(:mpfr_,fC)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, e, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, a, b, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, c, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, d, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,fC)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, e, ROUNDING_MODE[]) return z end end @@ -629,14 +621,14 @@ end function -(x::BigFloat) z = BigFloat() - ccall((:mpfr_neg, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) + ccall((:mpfr_neg, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) return z end function sqrt(x::BigFloat) isnan(x) && return x z = BigFloat() - ccall((:mpfr_sqrt, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) + ccall((:mpfr_sqrt, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) isnan(z) && throw(DomainError(x, "NaN result for non-NaN input.")) return z end @@ -645,25 +637,25 @@ sqrt(x::BigInt) = sqrt(BigFloat(x)) function ^(x::BigFloat, y::BigFloat) z = BigFloat() - ccall((:mpfr_pow, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_pow, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end function ^(x::BigFloat, y::CulongMax) z = BigFloat() - ccall((:mpfr_pow_ui, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_pow_ui, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end function ^(x::BigFloat, y::ClongMax) z = BigFloat() - ccall((:mpfr_pow_si, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_pow_si, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end function ^(x::BigFloat, y::BigInt) z = BigFloat() - ccall((:mpfr_pow_z, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_pow_z, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigInt}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end @@ -673,7 +665,7 @@ end for f in (:exp, :exp2, :exp10, :expm1, :cosh, :sinh, :tanh, :sech, :csch, :coth, :cbrt) @eval function $f(x::BigFloat) z = BigFloat() - ccall(($(string(:mpfr_,f)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,f)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) return z end end @@ -681,7 +673,7 @@ end function sincos_fast(v::BigFloat) s = BigFloat() c = BigFloat() - ccall((:mpfr_sin_cos, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), s, c, v, ROUNDING_MODE[]) + ccall((:mpfr_sin_cos, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), s, c, v, ROUNDING_MODE[]) return (s, c) end sincos(v::BigFloat) = sincos_fast(v) @@ -689,18 +681,18 @@ sincos(v::BigFloat) = sincos_fast(v) # return log(2) function big_ln2() c = BigFloat() - ccall((:mpfr_const_log2, libmpfr), Cint, (Ref{BigFloat}, MPFRRoundingMode), c, MPFR.ROUNDING_MODE[]) + ccall((:mpfr_const_log2, get_libmpfr()), Cint, (Ref{BigFloat}, MPFRRoundingMode), c, MPFR.ROUNDING_MODE[]) return c end function ldexp(x::BigFloat, n::Clong) z = BigFloat() - ccall((:mpfr_mul_2si, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, n, ROUNDING_MODE[]) + ccall((:mpfr_mul_2si, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, x, n, ROUNDING_MODE[]) return z end function ldexp(x::BigFloat, n::Culong) z = BigFloat() - ccall((:mpfr_mul_2ui, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, n, ROUNDING_MODE[]) + ccall((:mpfr_mul_2ui, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, n, ROUNDING_MODE[]) return z end ldexp(x::BigFloat, n::ClongMax) = ldexp(x, convert(Clong, n)) @@ -713,13 +705,13 @@ function factorial(x::BigFloat) end ui = convert(Culong, x) z = BigFloat() - ccall((:mpfr_fac_ui, libmpfr), Int32, (Ref{BigFloat}, Culong, MPFRRoundingMode), z, ui, ROUNDING_MODE[]) + ccall((:mpfr_fac_ui, get_libmpfr()), Int32, (Ref{BigFloat}, Culong, MPFRRoundingMode), z, ui, ROUNDING_MODE[]) return z end function hypot(x::BigFloat, y::BigFloat) z = BigFloat() - ccall((:mpfr_hypot, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_hypot, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end @@ -731,7 +723,7 @@ for f in (:log, :log2, :log10) "with a complex argument. Try ", $f, "(complex(x))."))) end z = BigFloat() - ccall(($(string(:mpfr_,f)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,f)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) return z end end @@ -743,7 +735,7 @@ function log1p(x::BigFloat) "with a complex argument. Try log1p(complex(x))."))) end z = BigFloat() - ccall((:mpfr_log1p, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) + ccall((:mpfr_log1p, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) return z end @@ -767,19 +759,19 @@ end function modf(x::BigFloat) zint = BigFloat() zfloat = BigFloat() - ccall((:mpfr_modf, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), zint, zfloat, x, ROUNDING_MODE[]) + ccall((:mpfr_modf, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), zint, zfloat, x, ROUNDING_MODE[]) return (zfloat, zint) end function rem(x::BigFloat, y::BigFloat) z = BigFloat() - ccall((:mpfr_fmod, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_fmod, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end function rem(x::BigFloat, y::BigFloat, ::RoundingMode{:Nearest}) z = BigFloat() - ccall((:mpfr_remainder, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_remainder, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end @@ -789,7 +781,7 @@ rem2pi(x::BigFloat, r::RoundingMode) = rem(x, 2*BigFloat(pi), r) function sum(arr::AbstractArray{BigFloat}) z = BigFloat(0) for i in arr - ccall((:mpfr_add, libmpfr), Int32, + ccall((:mpfr_add, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, z, i, ROUNDING_MODE[]) end return z @@ -801,7 +793,7 @@ for f in (:sin, :cos, :tan, :sec, :csc, :acos, :asin, :atan, :acosh, :asinh, :at function ($f)(x::BigFloat) isnan(x) && return x z = BigFloat() - ccall(($(string(:mpfr_,f)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,f)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, ROUNDING_MODE[]) isnan(z) && throw(DomainError(x, "NaN result for non-NaN input.")) return z end @@ -811,7 +803,7 @@ sincospi(x::BigFloat) = (sinpi(x), cospi(x)) function atan(y::BigFloat, x::BigFloat) z = BigFloat() - ccall((:mpfr_atan2, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, y, x, ROUNDING_MODE[]) + ccall((:mpfr_atan2, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, y, x, ROUNDING_MODE[]) return z end @@ -821,14 +813,14 @@ for f in (:sin, :cos, :tan) function ($(Symbol(f,:d)))(x::BigFloat) isnan(x) && return x z = BigFloat() - ccall(($(string(:mpfr_,f,:u)), :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, 360, ROUNDING_MODE[]) + ccall(($(string(:mpfr_,f,:u)), :get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, 360, ROUNDING_MODE[]) isnan(z) && throw(DomainError(x, "NaN result for non-NaN input.")) return z end function ($(Symbol(:a,f,:d)))(x::BigFloat) isnan(x) && return x z = BigFloat() - ccall(($(string(:mpfr_a,f,:u)), :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, 360, ROUNDING_MODE[]) + ccall(($(string(:mpfr_a,f,:u)), :get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, 360, ROUNDING_MODE[]) isnan(z) && throw(DomainError(x, "NaN result for non-NaN input.")) return z end @@ -836,29 +828,29 @@ for f in (:sin, :cos, :tan) end function atand(y::BigFloat, x::BigFloat) z = BigFloat() - ccall((:mpfr_atan2u, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, y, x, 360, ROUNDING_MODE[]) + ccall((:mpfr_atan2u, :get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, y, x, 360, ROUNDING_MODE[]) return z end # Utility functions -==(x::BigFloat, y::BigFloat) = ccall((:mpfr_equal_p, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 -<=(x::BigFloat, y::BigFloat) = ccall((:mpfr_lessequal_p, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 ->=(x::BigFloat, y::BigFloat) = ccall((:mpfr_greaterequal_p, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 -<(x::BigFloat, y::BigFloat) = ccall((:mpfr_less_p, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 ->(x::BigFloat, y::BigFloat) = ccall((:mpfr_greater_p, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 +==(x::BigFloat, y::BigFloat) = ccall((:mpfr_equal_p, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 +<=(x::BigFloat, y::BigFloat) = ccall((:mpfr_lessequal_p, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 +>=(x::BigFloat, y::BigFloat) = ccall((:mpfr_greaterequal_p, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 +<(x::BigFloat, y::BigFloat) = ccall((:mpfr_less_p, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 +>(x::BigFloat, y::BigFloat) = ccall((:mpfr_greater_p, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), x, y) != 0 function cmp(x::BigFloat, y::BigInt) isnan(x) && return 1 - ccall((:mpfr_cmp_z, libmpfr), Int32, (Ref{BigFloat}, Ref{BigInt}), x, y) + ccall((:mpfr_cmp_z, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigInt}), x, y) end function cmp(x::BigFloat, y::ClongMax) isnan(x) && return 1 - ccall((:mpfr_cmp_si, libmpfr), Int32, (Ref{BigFloat}, Clong), x, y) + ccall((:mpfr_cmp_si, get_libmpfr()), Int32, (Ref{BigFloat}, Clong), x, y) end function cmp(x::BigFloat, y::CulongMax) isnan(x) && return 1 - ccall((:mpfr_cmp_ui, libmpfr), Int32, (Ref{BigFloat}, Culong), x, y) + ccall((:mpfr_cmp_ui, get_libmpfr()), Int32, (Ref{BigFloat}, Culong), x, y) end cmp(x::BigFloat, y::Integer) = cmp(x,big(y)) cmp(x::Integer, y::BigFloat) = -cmp(y,x) @@ -866,7 +858,7 @@ cmp(x::Integer, y::BigFloat) = -cmp(y,x) function cmp(x::BigFloat, y::CdoubleMax) isnan(x) && return isnan(y) ? 0 : 1 isnan(y) && return -1 - ccall((:mpfr_cmp_d, libmpfr), Int32, (Ref{BigFloat}, Cdouble), x, y) + ccall((:mpfr_cmp_d, get_libmpfr()), Int32, (Ref{BigFloat}, Cdouble), x, y) end cmp(x::CdoubleMax, y::BigFloat) = -cmp(y,x) @@ -896,7 +888,7 @@ function sign(x::BigFloat) end function _precision(x::BigFloat) # precision of an object of type BigFloat - return ccall((:mpfr_get_prec, libmpfr), Clong, (Ref{BigFloat},), x) + return ccall((:mpfr_get_prec, get_libmpfr()), Clong, (Ref{BigFloat},), x) end precision(x::BigFloat; base::Integer=2) = _precision(x, base) @@ -932,7 +924,7 @@ maxintfloat(::Type{BigFloat}) = BigFloat(2)^precision(BigFloat) function copysign(x::BigFloat, y::BigFloat) z = BigFloat() - ccall((:mpfr_copysign, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) + ccall((:mpfr_copysign, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) return z end @@ -941,27 +933,27 @@ function exponent(x::BigFloat) throw(DomainError(x, "`x` must be non-zero and finite.")) end # The '- 1' is to make it work as Base.exponent - return ccall((:mpfr_get_exp, libmpfr), Clong, (Ref{BigFloat},), x) - 1 + return ccall((:mpfr_get_exp, get_libmpfr()), Clong, (Ref{BigFloat},), x) - 1 end function frexp(x::BigFloat) z = BigFloat() c = Ref{Clong}() - ccall((:mpfr_frexp, libmpfr), Int32, (Ptr{Clong}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), c, z, x, ROUNDING_MODE[]) + ccall((:mpfr_frexp, get_libmpfr()), Int32, (Ptr{Clong}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), c, z, x, ROUNDING_MODE[]) return (z, c[]) end function significand(x::BigFloat) z = BigFloat() c = Ref{Clong}() - ccall((:mpfr_frexp, libmpfr), Int32, (Ptr{Clong}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), c, z, x, ROUNDING_MODE[]) + ccall((:mpfr_frexp, get_libmpfr()), Int32, (Ptr{Clong}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), c, z, x, ROUNDING_MODE[]) # Double the significand to make it work as Base.significand - ccall((:mpfr_mul_si, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, z, 2, ROUNDING_MODE[]) + ccall((:mpfr_mul_si, get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong, MPFRRoundingMode), z, z, 2, ROUNDING_MODE[]) return z end function isinteger(x::BigFloat) - return ccall((:mpfr_integer_p, libmpfr), Int32, (Ref{BigFloat},), x) != 0 + return ccall((:mpfr_integer_p, get_libmpfr()), Int32, (Ref{BigFloat},), x) != 0 end for (f,R) in ((:roundeven, :Nearest), @@ -972,18 +964,18 @@ for (f,R) in ((:roundeven, :Nearest), @eval begin function round(x::BigFloat, ::RoundingMode{$(QuoteNode(R))}) z = BigFloat() - ccall(($(string(:mpfr_,f)), libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, x) + ccall(($(string(:mpfr_,f)), get_libmpfr()), Int32, (Ref{BigFloat}, Ref{BigFloat}), z, x) return z end end end function isinf(x::BigFloat) - return ccall((:mpfr_inf_p, libmpfr), Int32, (Ref{BigFloat},), x) != 0 + return ccall((:mpfr_inf_p, get_libmpfr()), Int32, (Ref{BigFloat},), x) != 0 end function isnan(x::BigFloat) - return ccall((:mpfr_nan_p, libmpfr), Int32, (Ref{BigFloat},), x) != 0 + return ccall((:mpfr_nan_p, get_libmpfr()), Int32, (Ref{BigFloat},), x) != 0 end isfinite(x::BigFloat) = !isinf(x) && !isnan(x) @@ -997,7 +989,7 @@ isone(x::BigFloat) = x == Clong(1) function nextfloat!(x::BigFloat, n::Integer=1) signbit(n) && return prevfloat!(x, abs(n)) for i = 1:n - ccall((:mpfr_nextabove, libmpfr), Int32, (Ref{BigFloat},), x) + ccall((:mpfr_nextabove, get_libmpfr()), Int32, (Ref{BigFloat},), x) end return x end @@ -1005,7 +997,7 @@ end function prevfloat!(x::BigFloat, n::Integer=1) signbit(n) && return nextfloat!(x, abs(n)) for i = 1:n - ccall((:mpfr_nextbelow, libmpfr), Int32, (Ref{BigFloat},), x) + ccall((:mpfr_nextbelow, get_libmpfr()), Int32, (Ref{BigFloat},), x) end return x end @@ -1051,7 +1043,7 @@ setprecision(f::Function, prec::Integer; base::Integer=2) = setprecision(f, BigF function string_mpfr(x::BigFloat, fmt::String) pc = Ref{Ptr{UInt8}}() - n = ccall((:mpfr_asprintf,libmpfr), Cint, + n = ccall((:mpfr_asprintf,get_libmpfr()), Cint, (Ptr{Ptr{UInt8}}, Ptr{UInt8}, Ref{BigFloat}...), pc, fmt, x) p = pc[] @@ -1063,7 +1055,7 @@ function string_mpfr(x::BigFloat, fmt::String) end end str = unsafe_string(p) - ccall((:mpfr_free_str, libmpfr), Cvoid, (Ptr{UInt8},), p) + ccall((:mpfr_free_str, get_libmpfr()), Cvoid, (Ptr{UInt8},), p) return str end @@ -1114,17 +1106,17 @@ function show(io::IO, b::BigFloat) end # get/set exponent min/max -get_emax() = ccall((:mpfr_get_emax, libmpfr), Clong, ()) -get_emax_min() = ccall((:mpfr_get_emax_min, libmpfr), Clong, ()) -get_emax_max() = ccall((:mpfr_get_emax_max, libmpfr), Clong, ()) +get_emax() = ccall((:mpfr_get_emax, get_libmpfr()), Clong, ()) +get_emax_min() = ccall((:mpfr_get_emax_min, get_libmpfr()), Clong, ()) +get_emax_max() = ccall((:mpfr_get_emax_max, get_libmpfr()), Clong, ()) -get_emin() = ccall((:mpfr_get_emin, libmpfr), Clong, ()) -get_emin_min() = ccall((:mpfr_get_emin_min, libmpfr), Clong, ()) -get_emin_max() = ccall((:mpfr_get_emin_max, libmpfr), Clong, ()) +get_emin() = ccall((:mpfr_get_emin, get_libmpfr()), Clong, ()) +get_emin_min() = ccall((:mpfr_get_emin_min, get_libmpfr()), Clong, ()) +get_emin_max() = ccall((:mpfr_get_emin_max, get_libmpfr()), Clong, ()) check_exponent_err(ret) = ret == 0 || throw(ArgumentError("Invalid MPFR exponent range")) -set_emax!(x) = check_exponent_err(ccall((:mpfr_set_emax, libmpfr), Cint, (Clong,), x)) -set_emin!(x) = check_exponent_err(ccall((:mpfr_set_emin, libmpfr), Cint, (Clong,), x)) +set_emax!(x) = check_exponent_err(ccall((:mpfr_set_emax, get_libmpfr()), Cint, (Clong,), x)) +set_emin!(x) = check_exponent_err(ccall((:mpfr_set_emin, get_libmpfr()), Cint, (Clong,), x)) function Base.deepcopy_internal(x::BigFloat, stackdict::IdDict) get!(stackdict, x) do @@ -1132,7 +1124,7 @@ function Base.deepcopy_internal(x::BigFloat, stackdict::IdDict) d = x._d d′ = GC.@preserve d unsafe_string(pointer(d), sizeof(d)) # creates a definitely-new String y = _BigFloat(x.prec, x.sign, x.exp, d′) - #ccall((:mpfr_custom_move,libmpfr), Cvoid, (Ref{BigFloat}, Ptr{Limb}), y, d) # unnecessary + #ccall((:mpfr_custom_move,get_libmpfr()), Cvoid, (Ref{BigFloat}, Ptr{Limb}), y, d) # unnecessary return y end end @@ -1144,7 +1136,7 @@ function decompose(x::BigFloat)::Tuple{BigInt, Int, Int} s = BigInt() s.size = cld(x.prec, 8*sizeof(Limb)) # limbs b = s.size * sizeof(Limb) # bytes - ccall((:__gmpz_realloc2, libgmp), Cvoid, (Ref{BigInt}, Culong), s, 8b) # bits + ccall((:__gmpz_realloc2, get_libgmp()), Cvoid, (Ref{BigInt}, Culong), s, 8b) # bits memcpy(s.d, x.d, b) s, x.exp - 8b, x.sign end @@ -1155,11 +1147,11 @@ function lerpi(j::Integer, d::Integer, a::BigFloat, b::BigFloat) end # flags -clear_flags() = ccall((:mpfr_clear_flags, libmpfr), Cvoid, ()) -had_underflow() = ccall((:mpfr_underflow_p, libmpfr), Cint, ()) != 0 -had_overflow() = ccall((:mpfr_underflow_p, libmpfr), Cint, ()) != 0 -had_nan() = ccall((:mpfr_nanflag_p, libmpfr), Cint, ()) != 0 -had_inexact_exception() = ccall((:mpfr_inexflag_p, libmpfr), Cint, ()) != 0 -had_range_exception() = ccall((:mpfr_erangeflag_p, libmpfr), Cint, ()) != 0 +clear_flags() = ccall((:mpfr_clear_flags, get_libmpfr()), Cvoid, ()) +had_underflow() = ccall((:mpfr_underflow_p, get_libmpfr()), Cint, ()) != 0 +had_overflow() = ccall((:mpfr_underflow_p, get_libmpfr()), Cint, ()) != 0 +had_nan() = ccall((:mpfr_nanflag_p, get_libmpfr()), Cint, ()) != 0 +had_inexact_exception() = ccall((:mpfr_inexflag_p, get_libmpfr()), Cint, ()) != 0 +had_range_exception() = ccall((:mpfr_erangeflag_p, get_libmpfr()), Cint, ()) != 0 end #module diff --git a/base/pcre.jl b/base/pcre.jl index 7597c1217ca9e..65ed728e14c44 100644 --- a/base/pcre.jl +++ b/base/pcre.jl @@ -8,18 +8,17 @@ import ..RefValue # include($BUILDROOT/base/pcre_h.jl) include(string(length(Core.ARGS) >= 2 ? Core.ARGS[2] : "", "pcre_h.jl")) - -const PCRE_LIB = "libpcre2-8" +using .Base.JLLAdapters: get_libpcre2_8 function create_match_context() JIT_STACK_START_SIZE = 32768 JIT_STACK_MAX_SIZE = 1048576 - jit_stack = ccall((:pcre2_jit_stack_create_8, PCRE_LIB), Ptr{Cvoid}, + jit_stack = ccall((:pcre2_jit_stack_create_8, get_libpcre2_8()), Ptr{Cvoid}, (Csize_t, Csize_t, Ptr{Cvoid}), JIT_STACK_START_SIZE, JIT_STACK_MAX_SIZE, C_NULL) - ctx = ccall((:pcre2_match_context_create_8, PCRE_LIB), + ctx = ccall((:pcre2_match_context_create_8, get_libpcre2_8()), Ptr{Cvoid}, (Ptr{Cvoid},), C_NULL) - ccall((:pcre2_jit_stack_assign_8, PCRE_LIB), Cvoid, + ccall((:pcre2_jit_stack_assign_8, get_libpcre2_8()), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), ctx, C_NULL, jit_stack) return ctx end @@ -128,7 +127,7 @@ const UNSET = ~Csize_t(0) # Indicates that an output vector element is unset function info(regex::Ptr{Cvoid}, what::Integer, ::Type{T}) where T buf = RefValue{T}() - ret = ccall((:pcre2_pattern_info_8, PCRE_LIB), Cint, + ret = ccall((:pcre2_pattern_info_8, get_libpcre2_8()), Cint, (Ptr{Cvoid}, UInt32, Ptr{Cvoid}), regex, what, buf) if ret != 0 @@ -141,13 +140,13 @@ function info(regex::Ptr{Cvoid}, what::Integer, ::Type{T}) where T end function ovec_length(match_data) - n = ccall((:pcre2_get_ovector_count_8, PCRE_LIB), UInt32, + n = ccall((:pcre2_get_ovector_count_8, get_libpcre2_8()), UInt32, (Ptr{Cvoid},), match_data) return 2Int(n) end function ovec_ptr(match_data) - ptr = ccall((:pcre2_get_ovector_pointer_8, PCRE_LIB), Ptr{Csize_t}, + ptr = ccall((:pcre2_get_ovector_pointer_8, get_libpcre2_8()), Ptr{Csize_t}, (Ptr{Cvoid},), match_data) return ptr end @@ -158,7 +157,7 @@ function compile(pattern::AbstractString, options::Integer) end errno = RefValue{Cint}(0) erroff = RefValue{Csize_t}(0) - re_ptr = ccall((:pcre2_compile_8, PCRE_LIB), Ptr{Cvoid}, + re_ptr = ccall((:pcre2_compile_8, get_libpcre2_8()), Ptr{Cvoid}, (Ptr{UInt8}, Csize_t, UInt32, Ref{Cint}, Ref{Csize_t}, Ptr{Cvoid}), pattern, ncodeunits(pattern), options, errno, erroff, C_NULL) if re_ptr == C_NULL @@ -168,7 +167,7 @@ function compile(pattern::AbstractString, options::Integer) end function jit_compile(regex::Ptr{Cvoid}) - errno = ccall((:pcre2_jit_compile_8, PCRE_LIB), Cint, + errno = ccall((:pcre2_jit_compile_8, get_libpcre2_8()), Cint, (Ptr{Cvoid}, UInt32), regex, JIT_COMPLETE) errno == 0 && return true errno == ERROR_JIT_BADOPTION && return false @@ -176,20 +175,20 @@ function jit_compile(regex::Ptr{Cvoid}) end free_match_data(match_data) = - ccall((:pcre2_match_data_free_8, PCRE_LIB), Cvoid, (Ptr{Cvoid},), match_data) + ccall((:pcre2_match_data_free_8, get_libpcre2_8()), Cvoid, (Ptr{Cvoid},), match_data) free_re(re) = - ccall((:pcre2_code_free_8, PCRE_LIB), Cvoid, (Ptr{Cvoid},), re) + ccall((:pcre2_code_free_8, get_libpcre2_8()), Cvoid, (Ptr{Cvoid},), re) free_jit_stack(stack) = - ccall((:pcre2_jit_stack_free_8, PCRE_LIB), Cvoid, (Ptr{Cvoid},), stack) + ccall((:pcre2_jit_stack_free_8, get_libpcre2_8()), Cvoid, (Ptr{Cvoid},), stack) free_match_context(context) = - ccall((:pcre2_match_context_free_8, PCRE_LIB), Cvoid, (Ptr{Cvoid},), context) + ccall((:pcre2_match_context_free_8, get_libpcre2_8()), Cvoid, (Ptr{Cvoid},), context) function err_message(errno::Integer) buffer = Vector{UInt8}(undef, 1024) - ret = ccall((:pcre2_get_error_message_8, PCRE_LIB), Cint, + ret = ccall((:pcre2_get_error_message_8, get_libpcre2_8()), Cint, (Cint, Ptr{UInt8}, Csize_t), errno, buffer, length(buffer)) ret == ERROR_BADDATA && error("PCRE error: invalid errno ($errno)") # TODO: seems like there should be a better way to get this string @@ -200,7 +199,7 @@ function exec(re, subject, offset, options, match_data) if !(subject isa Union{String,SubString{String}}) subject = String(subject) end - rc = ccall((:pcre2_match_8, PCRE_LIB), Cint, + rc = ccall((:pcre2_match_8, get_libpcre2_8()), Cint, (Ptr{Cvoid}, Ptr{UInt8}, Csize_t, Csize_t, UInt32, Ptr{Cvoid}, Ptr{Cvoid}), re, subject, ncodeunits(subject), offset, options, match_data, get_local_match_context()) # rc == -1 means no match, -2 means partial match. @@ -222,21 +221,21 @@ function exec_r_data(re, subject, offset, options) end function create_match_data(re) - p = ccall((:pcre2_match_data_create_from_pattern_8, PCRE_LIB), + p = ccall((:pcre2_match_data_create_from_pattern_8, get_libpcre2_8()), Ptr{Cvoid}, (Ptr{Cvoid}, Ptr{Cvoid}), re, C_NULL) p == C_NULL && error("PCRE error: could not allocate memory") return p end function substring_number_from_name(re, name) - n = ccall((:pcre2_substring_number_from_name_8, PCRE_LIB), Cint, + n = ccall((:pcre2_substring_number_from_name_8, get_libpcre2_8()), Cint, (Ptr{Cvoid}, Cstring), re, name) return Int(n) end function substring_length_bynumber(match_data, number) s = RefValue{Csize_t}() - rc = ccall((:pcre2_substring_length_bynumber_8, PCRE_LIB), Cint, + rc = ccall((:pcre2_substring_length_bynumber_8, get_libpcre2_8()), Cint, (Ptr{Cvoid}, Cint, Ref{Csize_t}), match_data, number, s) if rc < 0 rc == ERROR_UNSET && return 0 @@ -247,7 +246,7 @@ end function substring_copy_bynumber(match_data, number, buf, buf_size) s = RefValue{Csize_t}(buf_size) - rc = ccall((:pcre2_substring_copy_bynumber_8, PCRE_LIB), Cint, + rc = ccall((:pcre2_substring_copy_bynumber_8, get_libpcre2_8()), Cint, (Ptr{Cvoid}, UInt32, Ptr{UInt8}, Ref{Csize_t}), match_data, number, buf, s) rc < 0 && error("PCRE error: $(err_message(rc))") diff --git a/stdlib/GMP_jll/src/GMP_jll.jl b/stdlib/GMP_jll/src/GMP_jll.jl index fde2fc15acf90..5fb3b4cfa5848 100644 --- a/stdlib/GMP_jll/src/GMP_jll.jl +++ b/stdlib/GMP_jll/src/GMP_jll.jl @@ -4,50 +4,23 @@ baremodule GMP_jll using Base, Libdl Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - export libgmp, libgmpxx -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libgmp_handle::Ptr{Cvoid} = C_NULL -libgmp_path::String = "" -libgmpxx_handle::Ptr{Cvoid} = C_NULL -libgmpxx_path::String = "" - if Sys.iswindows() - const libgmp = "libgmp-10.dll" - const libgmpxx = "libgmpxx-4.dll" + const libgmp_name = "bin/libgmp-10.dll" + const libgmpxx_name = "bin/libgmpxx-4.dll" elseif Sys.isapple() - const libgmp = "@rpath/libgmp.10.dylib" - const libgmpxx = "@rpath/libgmpxx.4.dylib" + const libgmp_name = "lib/libgmp.10.dylib" + const libgmpxx_name = "lib/libgmpxx.4.dylib" else - const libgmp = "libgmp.so.10" - const libgmpxx = "libgmpxx.so.4" + const libgmp_name = "lib/libgmp.so.10" + const libgmpxx_name = "lib/libgmpxx.so.4" end -function __init__() - global libgmp_handle = dlopen(libgmp) - global libgmp_path = dlpath(libgmp_handle) - global libgmpxx_handle = dlopen(libgmpxx) - global libgmpxx_path = dlpath(libgmpxx_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libgmp_path) - push!(LIBPATH_list, LIBPATH[]) -end +const libgmp_path = BundledLazyLibraryPath(libgmp_name) +const libgmpxx_path = BundledLazyLibraryPath(libgmpxx_name) -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libgmp_path() = libgmp_path -get_libgmpxx_path() = libgmpxx_path +const libgmp = LazyLibrary(libgmp_path) +const libgmpxx = LazyLibrary(libgmpxx_path; dependencies=[libgmp]) end # module GMP_jll diff --git a/stdlib/MPFR_jll/src/MPFR_jll.jl b/stdlib/MPFR_jll/src/MPFR_jll.jl index c184a9801102f..97aef440d0062 100644 --- a/stdlib/MPFR_jll/src/MPFR_jll.jl +++ b/stdlib/MPFR_jll/src/MPFR_jll.jl @@ -4,42 +4,16 @@ baremodule MPFR_jll using Base, Libdl, GMP_jll Base.Experimental.@compiler_options compile=min optimize=0 infer=false - -const PATH_list = String[] -const LIBPATH_list = String[] - export libmpfr -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libmpfr_handle::Ptr{Cvoid} = C_NULL -libmpfr_path::String = "" - if Sys.iswindows() - const libmpfr = "libmpfr-6.dll" + const libmpfr_name = "bin/libmpfr-6.dll" elseif Sys.isapple() - const libmpfr = "@rpath/libmpfr.6.dylib" + const libmpfr_name = "lib/libmpfr.6.dylib" else - const libmpfr = "libmpfr.so.6" + const libmpfr_name = "lib/libmpfr.so.6" end -function __init__() - global libmpfr_handle = dlopen(libmpfr) - global libmpfr_path = dlpath(libmpfr_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libmpfr_path) - push!(LIBPATH_list, LIBPATH[]) -end - -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libmpfr_path() = libmpfr_path - +const libmpfr_path = BundledLazyLibraryPath(libmpfr_name) +const libmpfr = LazyLibrary(libmpfr_path; dependencies=[libgmp]) end # module MPFR_jll diff --git a/stdlib/PCRE2_jll/src/PCRE2_jll.jl b/stdlib/PCRE2_jll/src/PCRE2_jll.jl index e7f685820830b..cd84d948b45d6 100644 --- a/stdlib/PCRE2_jll/src/PCRE2_jll.jl +++ b/stdlib/PCRE2_jll/src/PCRE2_jll.jl @@ -5,41 +5,18 @@ baremodule PCRE2_jll using Base, Libdl Base.Experimental.@compiler_options compile=min optimize=0 infer=false -const PATH_list = String[] -const LIBPATH_list = String[] export libpcre2_8 -# These get calculated in __init__() -const PATH = Ref("") -const LIBPATH = Ref("") -artifact_dir::String = "" -libpcre2_8_handle::Ptr{Cvoid} = C_NULL -libpcre2_8_path::String = "" - if Sys.iswindows() - const libpcre2_8 = "libpcre2-8-0.dll" + const libpcre2_8_name = "bin/libpcre2-8-0.dll" elseif Sys.isapple() - const libpcre2_8 = "@rpath/libpcre2-8.0.dylib" + const libpcre2_8_name = "lib/libpcre2-8.0.dylib" else - const libpcre2_8 = "libpcre2-8.so.0" -end - -function __init__() - global libpcre2_8_handle = dlopen(libpcre2_8) - global libpcre2_8_path = dlpath(libpcre2_8_handle) - global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libpcre2_8_path) - push!(LIBPATH_list, LIBPATH[]) + const libpcre2_8_name = "lib/libpcre2-8.so.0" end -# JLLWrappers API compatibility shims. Note that not all of these will really make sense. -# For instance, `find_artifact_dir()` won't actually be the artifact directory, because -# there isn't one. It instead returns the overall Julia prefix. -is_available() = true -find_artifact_dir() = artifact_dir -dev_jll() = error("stdlib JLLs cannot be dev'ed") -best_wrapper = nothing -get_libpcre2_8_path() = libpcre2_8_path +const libpcre2_8_path = BundledLazyLibraryPath(libpcre2_8_name) +const libpcre2_8 = LazyLibrary(libpcre2_8_path) end # module PCRE2_jll