Skip to content

Commit 5c9cb31

Browse files
authored
Merge pull request #207 from JuliaMath/sf/relocatable
Make FFTW relocatable for PackageCompiler
2 parents df8f937 + e96270a commit 5c9cb31

File tree

4 files changed

+64
-48
lines changed

4 files changed

+64
-48
lines changed

src/FFTW.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,17 @@ function __init__()
2323
Base.depwarn("JULIA_FFTW_PROVIDER is deprecated; use FFTW.set_provider!() instead", :JULIA_FFTW_PROVIDER)
2424
end
2525

26-
# Hook FFTW threads up to our partr runtime
26+
# Hook FFTW threads up to our partr runtime, and re-assign the
27+
# libfftw3{,f} refs at runtime, since we may have relocated and
28+
# changed the path to the library since the last time we precompiled.
2729
@static if fftw_provider == "fftw"
2830
fftw_init_threads()
31+
libfftw3[] = FFTW_jll.libfftw3_path
32+
libfftw3f[] = FFTW_jll.libfftw3f_path
33+
end
34+
@static if fftw_provider == "mkl"
35+
libfftw3[] = MKL_jll.libmkl_rt_path
36+
libfftw3f[] = MKL_jll.libmkl_rt_path
2937
end
3038
end
3139

src/fft.jl

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function plan_r2r end
5656
## FFT: Implement fft by calling fftw.
5757

5858
const version = VersionNumber(split(unsafe_string(cglobal(
59-
(:fftw_version,libfftw3), UInt8)), ['-', ' '])[2])
59+
(:fftw_version,libfftw3[]), UInt8)), ['-', ' '])[2])
6060

6161
## Direction of FFT
6262

@@ -141,39 +141,39 @@ alignment_of(A::FakeArray) = Int32(0)
141141
@exclusive function export_wisdom(fname::AbstractString)
142142
f = ccall(:fopen, Ptr{Cvoid}, (Cstring,Cstring), fname, :w)
143143
systemerror("could not open wisdom file $fname for writing", f == C_NULL)
144-
ccall((:fftw_export_wisdom_to_file,libfftw3), Cvoid, (Ptr{Cvoid},), f)
144+
ccall((:fftw_export_wisdom_to_file,libfftw3[]), Cvoid, (Ptr{Cvoid},), f)
145145
ccall(:fputs, Int32, (Ptr{UInt8},Ptr{Cvoid}), " "^256, f) # no NUL, hence no Cstring
146-
ccall((:fftwf_export_wisdom_to_file,libfftw3f), Cvoid, (Ptr{Cvoid},), f)
146+
ccall((:fftwf_export_wisdom_to_file,libfftw3f[]), Cvoid, (Ptr{Cvoid},), f)
147147
ccall(:fclose, Cvoid, (Ptr{Cvoid},), f)
148148
end
149149

150150
@exclusive function import_wisdom(fname::AbstractString)
151151
f = ccall(:fopen, Ptr{Cvoid}, (Cstring,Cstring), fname, :r)
152152
systemerror("could not open wisdom file $fname for reading", f == C_NULL)
153-
if ccall((:fftw_import_wisdom_from_file,libfftw3),Int32,(Ptr{Cvoid},),f)==0||
154-
ccall((:fftwf_import_wisdom_from_file,libfftw3f),Int32,(Ptr{Cvoid},),f)==0
153+
if ccall((:fftw_import_wisdom_from_file,libfftw3[]),Int32,(Ptr{Cvoid},),f)==0||
154+
ccall((:fftwf_import_wisdom_from_file,libfftw3f[]),Int32,(Ptr{Cvoid},),f)==0
155155
error("failed to import wisdom from $fname")
156156
end
157157
ccall(:fclose, Cvoid, (Ptr{Cvoid},), f)
158158
end
159159

160160
@exclusive function import_system_wisdom()
161-
if ccall((:fftw_import_system_wisdom,libfftw3), Int32, ()) == 0 ||
162-
ccall((:fftwf_import_system_wisdom,libfftw3f), Int32, ()) == 0
161+
if ccall((:fftw_import_system_wisdom,libfftw3[]), Int32, ()) == 0 ||
162+
ccall((:fftwf_import_system_wisdom,libfftw3f[]), Int32, ()) == 0
163163
error("failed to import system wisdom")
164164
end
165165
end
166166

167167
@exclusive function forget_wisdom()
168-
ccall((:fftw_forget_wisdom,libfftw3), Cvoid, ())
169-
ccall((:fftwf_forget_wisdom,libfftw3f), Cvoid, ())
168+
ccall((:fftw_forget_wisdom,libfftw3[]), Cvoid, ())
169+
ccall((:fftwf_forget_wisdom,libfftw3f[]), Cvoid, ())
170170
end
171171

172172
# Threads
173173

174174
@exclusive function set_num_threads(nthreads::Integer)
175-
ccall((:fftw_plan_with_nthreads,libfftw3), Cvoid, (Int32,), nthreads)
176-
ccall((:fftwf_plan_with_nthreads,libfftw3f), Cvoid, (Int32,), nthreads)
175+
ccall((:fftw_plan_with_nthreads,libfftw3[]), Cvoid, (Int32,), nthreads)
176+
ccall((:fftwf_plan_with_nthreads,libfftw3f[]), Cvoid, (Int32,), nthreads)
177177
end
178178

179179
# pointer type for fftw_plan (opaque pointer)
@@ -187,9 +187,9 @@ const NO_TIMELIMIT = -1.0 # from fftw3.h
187187

188188
# only call these when fftwlock is held:
189189
unsafe_set_timelimit(precision::fftwTypeDouble,seconds) =
190-
ccall((:fftw_set_timelimit,libfftw3), Cvoid, (Float64,), seconds)
190+
ccall((:fftw_set_timelimit,libfftw3[]), Cvoid, (Float64,), seconds)
191191
unsafe_set_timelimit(precision::fftwTypeSingle,seconds) =
192-
ccall((:fftwf_set_timelimit,libfftw3f), Cvoid, (Float64,), seconds)
192+
ccall((:fftwf_set_timelimit,libfftw3f[]), Cvoid, (Float64,), seconds)
193193
@exclusive set_timelimit(precision, seconds) = unsafe_set_timelimit(precision, seconds)
194194

195195
# Array alignment mod 16:
@@ -210,9 +210,9 @@ unsafe_set_timelimit(precision::fftwTypeSingle,seconds) =
210210
convert(Int32, convert(Int64, pointer(A)) % 16)
211211
else
212212
alignment_of(A::StridedArray{T}) where {T<:fftwDouble} =
213-
ccall((:fftw_alignment_of, libfftw3), Int32, (Ptr{T},), A)
213+
ccall((:fftw_alignment_of, libfftw3[]), Int32, (Ptr{T},), A)
214214
alignment_of(A::StridedArray{T}) where {T<:fftwSingle} =
215-
ccall((:fftwf_alignment_of, libfftw3f), Int32, (Ptr{T},), A)
215+
ccall((:fftwf_alignment_of, libfftw3f[]), Int32, (Ptr{T},), A)
216216
end
217217

218218
# FFTWPlan (low-level)
@@ -268,9 +268,9 @@ unsafe_convert(::Type{PlanPtr}, p::FFTWPlan) = p.plan
268268

269269
# these functions should only be called while the fftwlock is held
270270
unsafe_destroy_plan(plan::FFTWPlan{<:fftwDouble}) =
271-
ccall((:fftw_destroy_plan,libfftw3), Cvoid, (PlanPtr,), plan)
271+
ccall((:fftw_destroy_plan,libfftw3[]), Cvoid, (PlanPtr,), plan)
272272
unsafe_destroy_plan(plan::FFTWPlan{<:fftwSingle}) =
273-
ccall((:fftwf_destroy_plan,libfftw3f), Cvoid, (PlanPtr,), plan)
273+
ccall((:fftwf_destroy_plan,libfftw3f[]), Cvoid, (PlanPtr,), plan)
274274

275275
const deferred_destroy_lock = ReentrantLock() # lock protecting the deferred_destroy_plans list
276276
const deferred_destroy_plans = FFTWPlan[]
@@ -331,19 +331,19 @@ end
331331
#################################################################################################
332332

333333
cost(plan::FFTWPlan{<:fftwDouble}) =
334-
ccall((:fftw_cost,libfftw3), Float64, (PlanPtr,), plan)
334+
ccall((:fftw_cost,libfftw3[]), Float64, (PlanPtr,), plan)
335335
cost(plan::FFTWPlan{<:fftwSingle}) =
336-
ccall((:fftwf_cost,libfftw3f), Float64, (PlanPtr,), plan)
336+
ccall((:fftwf_cost,libfftw3f[]), Float64, (PlanPtr,), plan)
337337

338338
@exclusive function arithmetic_ops(plan::FFTWPlan{<:fftwDouble})
339339
add, mul, fma = Ref(0.0), Ref(0.0), Ref(0.0)
340-
ccall((:fftw_flops,libfftw3), Cvoid,
340+
ccall((:fftw_flops,libfftw3[]), Cvoid,
341341
(PlanPtr,Ref{Float64},Ref{Float64},Ref{Float64}), plan, add, mul, fma)
342342
return (round(Int64, add[]), round(Int64, mul[]), round(Int64, fma[]))
343343
end
344344
@exclusive function arithmetic_ops(plan::FFTWPlan{<:fftwSingle})
345345
add, mul, fma = Ref(0.0), Ref(0.0), Ref(0.0)
346-
ccall((:fftwf_flops,libfftw3f), Cvoid,
346+
ccall((:fftwf_flops,libfftw3f[]), Cvoid,
347347
(PlanPtr,Ref{Float64},Ref{Float64},Ref{Float64}), plan, add, mul, fma)
348348
return (round(Int64, add[]), round(Int64, mul[]), round(Int64, fma[]))
349349
end
@@ -374,9 +374,9 @@ const has_sprint_plan = version >= v"3.3.4" && fftw_provider == "fftw"
374374

375375
@static if has_sprint_plan
376376
sprint_plan_(plan::FFTWPlan{<:fftwDouble}) =
377-
ccall((:fftw_sprint_plan,libfftw3), Ptr{UInt8}, (PlanPtr,), plan)
377+
ccall((:fftw_sprint_plan,libfftw3[]), Ptr{UInt8}, (PlanPtr,), plan)
378378
sprint_plan_(plan::FFTWPlan{<:fftwSingle}) =
379-
ccall((:fftwf_sprint_plan,libfftw3f), Ptr{UInt8}, (PlanPtr,), plan)
379+
ccall((:fftwf_sprint_plan,libfftw3f[]), Ptr{UInt8}, (PlanPtr,), plan)
380380
function sprint_plan(plan::FFTWPlan)
381381
p = sprint_plan_(plan)
382382
str = unsafe_string(p)
@@ -457,49 +457,49 @@ _colmajorstrides(p) = ()
457457
# Execute
458458

459459
unsafe_execute!(plan::FFTWPlan{<:fftwDouble}) =
460-
ccall((:fftw_execute,libfftw3), Cvoid, (PlanPtr,), plan)
460+
ccall((:fftw_execute,libfftw3[]), Cvoid, (PlanPtr,), plan)
461461

462462
unsafe_execute!(plan::FFTWPlan{<:fftwSingle}) =
463-
ccall((:fftwf_execute,libfftw3f), Cvoid, (PlanPtr,), plan)
463+
ccall((:fftwf_execute,libfftw3f[]), Cvoid, (PlanPtr,), plan)
464464

465465
unsafe_execute!(plan::cFFTWPlan{T},
466466
X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwDouble} =
467-
ccall((:fftw_execute_dft,libfftw3), Cvoid,
467+
ccall((:fftw_execute_dft,libfftw3[]), Cvoid,
468468
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
469469

470470
unsafe_execute!(plan::cFFTWPlan{T},
471471
X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwSingle} =
472-
ccall((:fftwf_execute_dft,libfftw3f), Cvoid,
472+
ccall((:fftwf_execute_dft,libfftw3f[]), Cvoid,
473473
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
474474

475475
unsafe_execute!(plan::rFFTWPlan{Float64,FORWARD},
476476
X::StridedArray{Float64}, Y::StridedArray{Complex{Float64}}) =
477-
ccall((:fftw_execute_dft_r2c,libfftw3), Cvoid,
477+
ccall((:fftw_execute_dft_r2c,libfftw3[]), Cvoid,
478478
(PlanPtr,Ptr{Float64},Ptr{Complex{Float64}}), plan, X, Y)
479479

480480
unsafe_execute!(plan::rFFTWPlan{Float32,FORWARD},
481481
X::StridedArray{Float32}, Y::StridedArray{Complex{Float32}}) =
482-
ccall((:fftwf_execute_dft_r2c,libfftw3f), Cvoid,
482+
ccall((:fftwf_execute_dft_r2c,libfftw3f[]), Cvoid,
483483
(PlanPtr,Ptr{Float32},Ptr{Complex{Float32}}), plan, X, Y)
484484

485485
unsafe_execute!(plan::rFFTWPlan{Complex{Float64},BACKWARD},
486486
X::StridedArray{Complex{Float64}}, Y::StridedArray{Float64}) =
487-
ccall((:fftw_execute_dft_c2r,libfftw3), Cvoid,
487+
ccall((:fftw_execute_dft_c2r,libfftw3[]), Cvoid,
488488
(PlanPtr,Ptr{Complex{Float64}},Ptr{Float64}), plan, X, Y)
489489

490490
unsafe_execute!(plan::rFFTWPlan{Complex{Float32},BACKWARD},
491491
X::StridedArray{Complex{Float32}}, Y::StridedArray{Float32}) =
492-
ccall((:fftwf_execute_dft_c2r,libfftw3f), Cvoid,
492+
ccall((:fftwf_execute_dft_c2r,libfftw3f[]), Cvoid,
493493
(PlanPtr,Ptr{Complex{Float32}},Ptr{Float32}), plan, X, Y)
494494

495495
unsafe_execute!(plan::r2rFFTWPlan{T},
496496
X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwDouble} =
497-
ccall((:fftw_execute_r2r,libfftw3), Cvoid,
497+
ccall((:fftw_execute_r2r,libfftw3[]), Cvoid,
498498
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
499499

500500
unsafe_execute!(plan::r2rFFTWPlan{T},
501501
X::StridedArray{T}, Y::StridedArray{T}) where {T<:fftwSingle} =
502-
ccall((:fftwf_execute_r2r,libfftw3f), Cvoid,
502+
ccall((:fftwf_execute_r2r,libfftw3f[]), Cvoid,
503503
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
504504

505505
# NOTE ON GC (garbage collection):
@@ -565,7 +565,7 @@ for (Tr,Tc,fftw,lib) in ((:Float64,:(Complex{Float64}),"fftw",:libfftw3),
565565
unsafe_set_timelimit($Tr, timelimit)
566566
R = isa(region, Tuple) ? region : copy(region)
567567
dims, howmany = dims_howmany(X, Y, [size(X)...], R)
568-
plan = ccall(($(string(fftw,"_plan_guru64_dft")),$lib),
568+
plan = ccall(($(string(fftw,"_plan_guru64_dft")),$lib[]),
569569
PlanPtr,
570570
(Int32, Ptr{Int}, Int32, Ptr{Int},
571571
Ptr{$Tc}, Ptr{$Tc}, Int32, UInt32),
@@ -585,7 +585,7 @@ for (Tr,Tc,fftw,lib) in ((:Float64,:(Complex{Float64}),"fftw",:libfftw3),
585585
region = circshift(Int[region...],-1) # FFTW halves last dim
586586
unsafe_set_timelimit($Tr, timelimit)
587587
dims, howmany = dims_howmany(X, Y, [size(X)...], region)
588-
plan = ccall(($(string(fftw,"_plan_guru64_dft_r2c")),$lib),
588+
plan = ccall(($(string(fftw,"_plan_guru64_dft_r2c")),$lib[]),
589589
PlanPtr,
590590
(Int32, Ptr{Int}, Int32, Ptr{Int},
591591
Ptr{$Tr}, Ptr{$Tc}, UInt32),
@@ -605,7 +605,7 @@ for (Tr,Tc,fftw,lib) in ((:Float64,:(Complex{Float64}),"fftw",:libfftw3),
605605
region = circshift(Int[region...],-1) # FFTW halves last dim
606606
unsafe_set_timelimit($Tr, timelimit)
607607
dims, howmany = dims_howmany(X, Y, [size(Y)...], region)
608-
plan = ccall(($(string(fftw,"_plan_guru64_dft_c2r")),$lib),
608+
plan = ccall(($(string(fftw,"_plan_guru64_dft_c2r")),$lib[]),
609609
PlanPtr,
610610
(Int32, Ptr{Int}, Int32, Ptr{Int},
611611
Ptr{$Tc}, Ptr{$Tr}, UInt32),
@@ -626,7 +626,7 @@ for (Tr,Tc,fftw,lib) in ((:Float64,:(Complex{Float64}),"fftw",:libfftw3),
626626
knd = fix_kinds(region, kinds)
627627
unsafe_set_timelimit($Tr, timelimit)
628628
dims, howmany = dims_howmany(X, Y, [size(X)...], region)
629-
plan = ccall(($(string(fftw,"_plan_guru64_r2r")),$lib),
629+
plan = ccall(($(string(fftw,"_plan_guru64_r2r")),$lib[]),
630630
PlanPtr,
631631
(Int32, Ptr{Int}, Int32, Ptr{Int},
632632
Ptr{$Tr}, Ptr{$Tr}, Ptr{Int32}, UInt32),
@@ -651,7 +651,7 @@ for (Tr,Tc,fftw,lib) in ((:Float64,:(Complex{Float64}),"fftw",:libfftw3),
651651
dims[2:3, 1:size(dims,2)] *= 2
652652
howmany[2:3, 1:size(howmany,2)] *= 2
653653
howmany = [howmany [2,1,1]] # append loop over real/imag parts
654-
plan = ccall(($(string(fftw,"_plan_guru64_r2r")),$lib),
654+
plan = ccall(($(string(fftw,"_plan_guru64_r2r")),$lib[]),
655655
PlanPtr,
656656
(Int32, Ptr{Int}, Int32, Ptr{Int},
657657
Ptr{$Tc}, Ptr{$Tc}, Ptr{Int32}, UInt32),

src/providers.jl

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ end
2020
# Read in preferences, see if any users have requested a particular backend
2121
const fftw_provider = get_provider()
2222

23+
# We'll initialize `libfftw3` here (in the conditionals below), and
24+
# it will get overwritten again in `__init__()`. This allows us to
25+
# `ccall` at build time, and also be relocatable for PackageCompiler.
26+
const libfftw3 = Ref{String}()
27+
const libfftw3f = Ref{String}()
28+
2329
"""
2430
set_provider!(provider; export_prefs::Bool = false)
2531
@@ -41,7 +47,9 @@ end
4147

4248
# If we're using fftw_jll, load it in
4349
@static if fftw_provider == "fftw"
44-
using FFTW_jll
50+
import FFTW_jll
51+
libfftw3[] = FFTW_jll.libfftw3_path
52+
libfftw3f[] = FFTW_jll.libfftw3f_path
4553

4654
# callback function that FFTW uses to launch `num` parallel
4755
# tasks (FFTW/fftw3#175):
@@ -58,23 +66,23 @@ end
5866
# (Previously, we called fftw_cleanup, but this invalidated existing
5967
# plans, causing Base Julia issue #19892.)
6068
function fftw_init_threads()
61-
stat = ccall((:fftw_init_threads, libfftw3), Int32, ())
62-
statf = ccall((:fftwf_init_threads, libfftw3f), Int32, ())
69+
stat = ccall((:fftw_init_threads, libfftw3[]), Int32, ())
70+
statf = ccall((:fftwf_init_threads, libfftw3f[]), Int32, ())
6371
if stat == 0 || statf == 0
6472
error("could not initialize FFTW threads")
6573
end
6674

6775
if nthreads() > 1
6876
cspawnloop = @cfunction(spawnloop, Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t, Cint, Ptr{Cvoid}))
69-
ccall((:fftw_threads_set_callback, libfftw3), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cspawnloop, C_NULL)
70-
ccall((:fftwf_threads_set_callback, libfftw3f), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cspawnloop, C_NULL)
77+
ccall((:fftw_threads_set_callback, libfftw3[]), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cspawnloop, C_NULL)
78+
ccall((:fftwf_threads_set_callback, libfftw3f[]), Cvoid, (Ptr{Cvoid}, Ptr{Cvoid}), cspawnloop, C_NULL)
7179
end
7280
end
7381
end
7482

7583
# If we're using MKL, load it in and set library paths appropriately.
7684
@static if fftw_provider == "mkl"
77-
using MKL_jll
78-
const libfftw3 = MKL_jll.libmkl_rt_path
79-
const libfftw3f = libfftw3
85+
import MKL_jll
86+
libfftw3[] = MKL_jll.libmkl_rt_path
87+
libfftw3f[] = MKL_jll.libmkl_rt_path
8088
end

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ end # fftw_provider == "fftw"
507507
end
508508

509509
# check whether FFTW on this architecture has nontrivial alignment requirements
510-
nontrivial_alignment = FFTW.fftw_provider == "fftw" && ccall((:fftwf_alignment_of, FFTW.libfftw3f), Int32, (Int,), 8) != 0
510+
nontrivial_alignment = FFTW.fftw_provider == "fftw" && ccall((:fftwf_alignment_of, FFTW.libfftw3f[]), Int32, (Int,), 8) != 0
511511
if nontrivial_alignment
512512
@test_throws ArgumentError plan_rfft(Array{Float32}(undef, 32)) * view(A, 2:33)
513513
@test_throws ArgumentError plan_fft(Array{Complex{Float32}}(undef, 32)) * view(Ac, 2:33)

0 commit comments

Comments
 (0)