diff --git a/Project.toml b/Project.toml index e53ebb6..65dbd37 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "FFTW" uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" -version = "1.7.1" +version = "1.7.2" [deps] AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c" diff --git a/src/providers.jl b/src/providers.jl index 58817b1..1fbaff6 100644 --- a/src/providers.jl +++ b/src/providers.jl @@ -1,17 +1,44 @@ +const valid_fftw_providers = let + # Hardcoded list of supported platforms + # In principle, we could check FFTW_jll.is_available() and MKL_jll.is_available() + # but then we would have to load MKL_jll which we want to avoid (lazy artifacts!) + platforms_providers = Dict( + Base.BinaryPlatforms.Platform("aarch64", "macos") => ("fftw",), + Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("aarch64", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv6l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "glibc", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("armv7l", "linux"; libc = "musl", call_abi = "eabihf") => ("fftw",), + Base.BinaryPlatforms.Platform("i686", "linux"; libc = "glibc") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("i686", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("i686", "windows") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("powerpc64le", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "macos") => ("fftw", "mkl"), + Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "glibc") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "linux"; libc = "musl") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "freebsd") => ("fftw",), + Base.BinaryPlatforms.Platform("x86_64", "windows") => ("fftw", "mkl"), + ) + Base.BinaryPlatforms.select_platform(platforms_providers, Base.BinaryPlatforms.HostPlatform()) +end +if valid_fftw_providers === nothing + error("no valid FFTW library available") +end function get_provider() # Note: we CANNOT do something like have the `default` value be `get(ENV, "JULIA_FFTW_PROVIDER", "fftw")` here. # This is because the only way the Julia knows that a default has changed is if the values on-disk change; so # if your "default" value can be changed from the outside, you quickly run into cache invalidation issues. # So the default here _must_ be a constant. - default_provider = "fftw" + default_provider = first(valid_fftw_providers) # Load the preference provider = @load_preference("provider", default_provider) # Ensure the provider matches one of the ones we support - if provider ∉ ("fftw", "mkl") - @error("Invalid provider setting \"$(provider)\"; valid settings include [\"fftw\", \"mkl\"], defaulting to \"fftw\"") + if provider ∉ valid_fftw_providers + @error("Invalid provider setting \"$(provider)\"; valid settings include [$(join(map(x -> '"' * x * '"', valid_fftw_providers), ", "))]") provider = default_provider end return provider @@ -34,8 +61,8 @@ Also supports `Preferences` sentinel values `nothing` and `missing`; see the doc `Preferences.set_preferences!()` for more information on what these values mean. """ function set_provider!(provider; export_prefs::Bool = false) - if provider !== nothing && provider !== missing && provider ∉ ("fftw", "mkl") - throw(ArgumentError("Invalid provider value '$(provider)'")) + if provider !== nothing && provider !== missing && provider ∉ valid_fftw_providers + throw(ArgumentError("Invalid provider value \"$(provider)\"; valid settings include [$(join(map(x -> '"' * x * '"', valid_fftw_providers), ", "))]")) end set_preferences!(@__MODULE__, "provider" => provider; export_prefs, force = true) if provider != fftw_provider @@ -48,6 +75,11 @@ end # If we're using fftw_jll, load it in @static if fftw_provider == "fftw" import FFTW_jll + if !FFTW_jll.is_available() + # more descriptive error message if FFTW is not available + # (should not be possible to reach this) + @error("FFTW library cannot be loaded: Run `FFTW.set_provider!(\"mkl\")` to switch to MKL") + end libfftw3[] = FFTW_jll.libfftw3_path libfftw3f[] = FFTW_jll.libfftw3f_path @@ -83,6 +115,11 @@ end # If we're using MKL, load it in and set library paths appropriately. @static if fftw_provider == "mkl" import MKL_jll + if !MKL_jll.is_available() + # more descriptive error message if MKL is not available + # (should not be possible to reach this) + @error("MKL cannot be loaded: Run `FFTW.set_provider!(\"fftw\")` to switch to the FFTW library") + end libfftw3[] = MKL_jll.libmkl_rt_path libfftw3f[] = MKL_jll.libmkl_rt_path const _last_num_threads = Ref(Cint(1))