From a6e2f38b9fb2213415dfcab475f8187eed45a34c Mon Sep 17 00:00:00 2001 From: Marco Barbone Date: Thu, 23 Oct 2025 14:54:28 -0400 Subject: [PATCH] Fix symbol visibility so shared libs export Fortran wrappers consistently Resolved inconsistent symbol exports for Fortran wrapper entry points and test helpers across Windows and macOS. Adjusted default visibility in the makefile, added FINUFFT_EXPORT_TEST for test-only APIs, and linked FFT backends via a new finufft_fftlibs interface target. It also adds the LTO option to makefile to achieve parity with cmake. Co-authored-by: Marco Barbone mbarbone@flatironinstitute.org Co-authored-by: Martin Reinecke martin@mpa-garching.mpg.de --- CHANGELOG | 6 +++- cmake/setupDUCC.cmake | 4 +++ cmake/setupFFTW.cmake | 3 ++ cmake/toolchain.cmake | 1 + cmake/utils.cmake | 3 +- fortran/finufftfort.cpp | 48 +++++++++++++++++++++++++++++++ include/finufft/finufft_utils.hpp | 13 ++++----- include/finufft/spreadinterp.h | 39 +++++++++++-------------- include/finufft_common/defines.h | 8 +++++- include/finufft_common/utils.h | 2 +- makefile | 21 ++++++++++++++ src/CMakeLists.txt | 17 ++++------- src/spreadinterp.cpp | 13 +++++---- test/CMakeLists.txt | 1 - 14 files changed, 126 insertions(+), 53 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f46e5d5c9..ba137a1f1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,7 +24,11 @@ Master (working towards v2.5.0), 8/13/25 * cmake: cache query and result for supported compiler flags to speed up configuration (Stanimirov #725). * move include/common to include/finufft_common (Stanimirov #734) - +* Fixed symbol visibility issues so shared libraries export the Fortran wrapper + entry points and test helpers consistently on Windows and macOS. This + included tightening default visibility in the makefile, introducing + `FINUFFT_EXPORT_TEST` for test-only APIs, and ensuring FFT backends are linked + through a dedicated `finufft_fftlibs` interface target. (Barbone, Reinecke #737) V 2.4.1 7/8/25 diff --git a/cmake/setupDUCC.cmake b/cmake/setupDUCC.cmake index 15804a2d9..15e1fed03 100644 --- a/cmake/setupDUCC.cmake +++ b/cmake/setupDUCC.cmake @@ -37,4 +37,8 @@ if(ducc0_ADDED) target_link_libraries(ducc0 PRIVATE Threads::Threads) endif() enable_asan(ducc0) + set_target_properties(ducc0 PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN YES) + + add_library(finufft_fftlibs INTERFACE) + target_link_libraries(finufft_fftlibs INTERFACE ducc0) endif() diff --git a/cmake/setupFFTW.cmake b/cmake/setupFFTW.cmake index 8fe95e8ae..a6b84b33e 100644 --- a/cmake/setupFFTW.cmake +++ b/cmake/setupFFTW.cmake @@ -89,3 +89,6 @@ if(FINUFFT_FFTW_LIBRARIES STREQUAL DEFAULT OR FINUFFT_FFTW_LIBRARIES STREQUAL DO endif() endif() endif() + +add_library(finufft_fftlibs INTERFACE) +target_link_libraries(finufft_fftlibs INTERFACE ${FINUFFT_FFTW_LIBRARIES}) diff --git a/cmake/toolchain.cmake b/cmake/toolchain.cmake index a562aca23..e4f329ede 100644 --- a/cmake/toolchain.cmake +++ b/cmake/toolchain.cmake @@ -21,6 +21,7 @@ set(FINUFFT_CXX_FLAGS_RELEASE -ftree-vectorize -fimplicit-constexpr -fcx-limited-range + -fno-semantic-interposition -O3 /Ox /fp:contract diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 57fb2fdcf..3eb4806a6 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -4,7 +4,7 @@ include(CheckCXXCompilerFlag) function(filter_supported_compiler_flags input_flags_var output_flags_var) string(MD5 input_hash "${${input_flags_var}}") if(DEFINED SUPPORTED_FLAGS_${input_hash}) - message(STATUS "Using cached flags for ${input_flags_var}: ${SUPPORTED_FLAGS_${input_hash}}") + message(STATUS "Using cached flags for ${input_flags_var}: ${SUPPORTED_FLAGS_${input_hash}}") set(${output_flags_var} ${SUPPORTED_FLAGS_${input_hash}} PARENT_SCOPE) return() endif() @@ -113,4 +113,5 @@ function(finufft_link_test target) if(FINUFFT_HAS_NO_DEPRECATED_DECLARATIONS) target_compile_options(${target} PRIVATE -Wno-deprecated-declarations) endif() + target_link_libraries(${target} PRIVATE finufft_fftlibs) endfunction() diff --git a/fortran/finufftfort.cpp b/fortran/finufftfort.cpp index c623df8b2..c77781583 100644 --- a/fortran/finufftfort.cpp +++ b/fortran/finufftfort.cpp @@ -32,6 +32,7 @@ extern "C" { #endif // --------------------- guru interface from fortran ------------------------ +FINUFFT_EXPORT void finufft_makeplan_(int *type, int *n_dims, i64 *n_modes, int *iflag, int *n_transf, f64 *tol, finufft_plan *plan, finufft_opts *o, int *ier) { if (!plan) @@ -45,6 +46,7 @@ void finufft_makeplan_(int *type, int *n_dims, i64 *n_modes, int *iflag, int *n_ } } +FINUFFT_EXPORT void finufft_setpts_(finufft_plan *plan, i64 *M, f64 *xj, f64 *yj, f64 *zj, i64 *nk, f64 *s, f64 *t, f64 *u, int *ier) { if (!*plan) { @@ -56,6 +58,7 @@ void finufft_setpts_(finufft_plan *plan, i64 *M, f64 *xj, f64 *yj, f64 *zj, i64 *ier = finufft_setpts(*plan, *M, xj, yj, zj, nk_safe, s, t, u); } +FINUFFT_EXPORT void finufft_execute_(finufft_plan *plan, c128 *weights, c128 *result, int *ier) { if (!plan) fprintf(stderr, "%s fortran: finufft_plan unallocated!", __func__); @@ -63,6 +66,7 @@ void finufft_execute_(finufft_plan *plan, c128 *weights, c128 *result, int *ier) *ier = finufft_execute(*plan, weights, result); } +FINUFFT_EXPORT void finufft_execute_adjoint_(finufft_plan *plan, c128 *weights, c128 *result, int *ier) { if (!plan) fprintf(stderr, "%s fortran: finufft_plan unallocated!", __func__); @@ -70,6 +74,7 @@ void finufft_execute_adjoint_(finufft_plan *plan, c128 *weights, c128 *result, i *ier = finufft_execute_adjoint(*plan, weights, result); } +FINUFFT_EXPORT void finufft_destroy_(finufft_plan *plan, int *ier) { if (!plan) fprintf(stderr, "%s fortran: finufft_plan unallocated!", __func__); @@ -79,6 +84,7 @@ void finufft_destroy_(finufft_plan *plan, int *ier) { // ------------ use FINUFFT to set the default options --------------------- // (Note the finufft_opts is created in f90-style derived types, not here) +FINUFFT_EXPORT void finufft_default_opts_(finufft_opts *o) { if (!o) fprintf(stderr, "%s fortran: opts must be allocated!\n", __func__); @@ -89,71 +95,85 @@ void finufft_default_opts_(finufft_opts *o) { // -------------- simple and many-vector interfaces -------------------- // --- 1D --- +FINUFFT_EXPORT void finufft1d1_(i64 *nj, f64 *xj, c128 *cj, int *iflag, f64 *eps, i64 *ms, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft1d1(*nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufft1d1many_(int *ntransf, i64 *nj, f64 *xj, c128 *cj, int *iflag, f64 *eps, i64 *ms, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft1d1many(*ntransf, *nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufft1d2_(i64 *nj, f64 *xj, c128 *cj, int *iflag, f64 *eps, i64 *ms, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft1d2(*nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufft1d2many_(int *ntransf, i64 *nj, f64 *xj, c128 *cj, int *iflag, f64 *eps, i64 *ms, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft1d2many(*ntransf, *nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufft1d3_(i64 *nj, f64 *x, c128 *c, int *iflag, f64 *eps, i64 *nk, f64 *s, c128 *f, finufft_opts *o, int *ier) { *ier = finufft1d3(*nj, x, c, *iflag, *eps, *nk, s, f, o); } +FINUFFT_EXPORT void finufft1d3many_(int *ntransf, i64 *nj, f64 *x, c128 *c, int *iflag, f64 *eps, i64 *nk, f64 *s, c128 *f, finufft_opts *o, int *ier) { *ier = finufft1d3many(*ntransf, *nj, x, c, *iflag, *eps, *nk, s, f, o); } // --- 2D --- +FINUFFT_EXPORT void finufft2d1_(i64 *nj, f64 *xj, f64 *yj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft2d1(*nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufft2d1many_(int *ntransf, i64 *nj, f64 *xj, f64 *yj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft2d1many(*ntransf, *nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufft2d2_(i64 *nj, f64 *xj, f64 *yj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft2d2(*nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufft2d2many_(int *ntransf, i64 *nj, f64 *xj, f64 *yj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft2d2many(*ntransf, *nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufft2d3_(i64 *nj, f64 *x, f64 *y, c128 *c, int *iflag, f64 *eps, i64 *nk, f64 *s, f64 *t, c128 *f, finufft_opts *o, int *ier) { *ier = finufft2d3(*nj, x, y, c, *iflag, *eps, *nk, s, t, f, o); } +FINUFFT_EXPORT void finufft2d3many_(int *ntransf, i64 *nj, f64 *x, f64 *y, c128 *c, int *iflag, f64 *eps, i64 *nk, f64 *s, f64 *t, c128 *f, finufft_opts *o, int *ier) { *ier = finufft2d3many(*ntransf, *nj, x, y, c, *iflag, *eps, *nk, s, t, f, o); } // --- 3D --- +FINUFFT_EXPORT void finufft3d1_(i64 *nj, f64 *xj, f64 *yj, f64 *zj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, i64 *mu, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft3d1(*nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufft3d1many_(int *ntransf, i64 *nj, f64 *xj, f64 *yj, f64 *zj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, i64 *mu, c128 *fk, finufft_opts *o, int *ier) { @@ -161,11 +181,13 @@ void finufft3d1many_(int *ntransf, i64 *nj, f64 *xj, f64 *yj, f64 *zj, c128 *cj, finufft3d1many(*ntransf, *nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufft3d2_(i64 *nj, f64 *xj, f64 *yj, f64 *zj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, i64 *mu, c128 *fk, finufft_opts *o, int *ier) { *ier = finufft3d2(*nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufft3d2many_(int *ntransf, i64 *nj, f64 *xj, f64 *yj, f64 *zj, c128 *cj, int *iflag, f64 *eps, i64 *ms, i64 *mt, i64 *mu, c128 *fk, finufft_opts *o, int *ier) { @@ -173,11 +195,13 @@ void finufft3d2many_(int *ntransf, i64 *nj, f64 *xj, f64 *yj, f64 *zj, c128 *cj, finufft3d2many(*ntransf, *nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufft3d3_(i64 *nj, f64 *x, f64 *y, f64 *z, c128 *c, int *iflag, f64 *eps, i64 *nk, f64 *s, f64 *t, f64 *u, c128 *f, finufft_opts *o, int *ier) { *ier = finufft3d3(*nj, x, y, z, c, *iflag, *eps, *nk, s, t, u, f, o); } +FINUFFT_EXPORT void finufft3d3many_(int *ntransf, i64 *nj, f64 *x, f64 *y, f64 *z, c128 *c, int *iflag, f64 *eps, i64 *nk, f64 *s, f64 *t, f64 *u, c128 *f, finufft_opts *o, int *ier) { @@ -185,6 +209,7 @@ void finufft3d3many_(int *ntransf, i64 *nj, f64 *x, f64 *y, f64 *z, c128 *c, int } // --------------------- guru interface from fortran ------------------------ +FINUFFT_EXPORT void finufftf_makeplan_(int *type, int *n_dims, i64 *n_modes, int *iflag, int *n_transf, f32 *tol, finufftf_plan *plan, finufft_opts *o, int *ier) { if (!plan) @@ -198,6 +223,7 @@ void finufftf_makeplan_(int *type, int *n_dims, i64 *n_modes, int *iflag, int *n } } +FINUFFT_EXPORT void finufftf_setpts_(finufftf_plan *plan, i64 *M, f32 *xj, f32 *yj, f32 *zj, i64 *nk, f32 *s, f32 *t, f32 *u, int *ier) { if (!*plan) { @@ -209,6 +235,7 @@ void finufftf_setpts_(finufftf_plan *plan, i64 *M, f32 *xj, f32 *yj, f32 *zj, i6 *ier = finufftf_setpts(*plan, *M, xj, yj, zj, nk_safe, s, t, u); } +FINUFFT_EXPORT void finufftf_execute_(finufftf_plan *plan, c64 *weights, c64 *result, int *ier) { if (!plan) fprintf(stderr, "%s fortran: finufft_plan unallocated!", __func__); @@ -216,6 +243,7 @@ void finufftf_execute_(finufftf_plan *plan, c64 *weights, c64 *result, int *ier) *ier = finufftf_execute(*plan, weights, result); } +FINUFFT_EXPORT void finufftf_execute_adjoint_(finufftf_plan *plan, c64 *weights, c64 *result, int *ier) { if (!plan) fprintf(stderr, "%s fortran: finufft_plan unallocated!", __func__); @@ -223,6 +251,7 @@ void finufftf_execute_adjoint_(finufftf_plan *plan, c64 *weights, c64 *result, i *ier = finufftf_execute_adjoint(*plan, weights, result); } +FINUFFT_EXPORT void finufftf_destroy_(finufftf_plan *plan, int *ier) { if (!plan) fprintf(stderr, "%s fortran: finufft_plan unallocated!", __func__); @@ -232,6 +261,7 @@ void finufftf_destroy_(finufftf_plan *plan, int *ier) { // ------------ use FINUFFT to set the default options --------------------- // (Note the finufft_opts is created in f90-style derived types, not here) +FINUFFT_EXPORT void finufftf_default_opts_(finufft_opts *o) { if (!o) fprintf(stderr, "%s fortran: opts must be allocated!\n", __func__); @@ -242,71 +272,85 @@ void finufftf_default_opts_(finufft_opts *o) { // -------------- simple and many-vector interfaces -------------------- // --- 1D --- +FINUFFT_EXPORT void finufftf1d1_(i64 *nj, f32 *xj, c64 *cj, int *iflag, f32 *eps, i64 *ms, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf1d1(*nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufftf1d1many_(int *ntransf, i64 *nj, f32 *xj, c64 *cj, int *iflag, f32 *eps, i64 *ms, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf1d1many(*ntransf, *nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufftf1d2_(i64 *nj, f32 *xj, c64 *cj, int *iflag, f32 *eps, i64 *ms, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf1d2(*nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufftf1d2many_(int *ntransf, i64 *nj, f32 *xj, c64 *cj, int *iflag, f32 *eps, i64 *ms, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf1d2many(*ntransf, *nj, xj, cj, *iflag, *eps, *ms, fk, o); } +FINUFFT_EXPORT void finufftf1d3_(i64 *nj, f32 *x, c64 *c, int *iflag, f32 *eps, i64 *nk, f32 *s, c64 *f, finufft_opts *o, int *ier) { *ier = finufftf1d3(*nj, x, c, *iflag, *eps, *nk, s, f, o); } +FINUFFT_EXPORT void finufftf1d3many_(int *ntransf, i64 *nj, f32 *x, c64 *c, int *iflag, f32 *eps, i64 *nk, f32 *s, c64 *f, finufft_opts *o, int *ier) { *ier = finufftf1d3many(*ntransf, *nj, x, c, *iflag, *eps, *nk, s, f, o); } // --- 2D --- +FINUFFT_EXPORT void finufftf2d1_(i64 *nj, f32 *xj, f32 *yj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf2d1(*nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufftf2d1many_(int *ntransf, i64 *nj, f32 *xj, f32 *yj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf2d1many(*ntransf, *nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufftf2d2_(i64 *nj, f32 *xj, f32 *yj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf2d2(*nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufftf2d2many_(int *ntransf, i64 *nj, f32 *xj, f32 *yj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf2d2many(*ntransf, *nj, xj, yj, cj, *iflag, *eps, *ms, *mt, fk, o); } +FINUFFT_EXPORT void finufftf2d3_(i64 *nj, f32 *x, f32 *y, c64 *c, int *iflag, f32 *eps, i64 *nk, f32 *s, f32 *t, c64 *f, finufft_opts *o, int *ier) { *ier = finufftf2d3(*nj, x, y, c, *iflag, *eps, *nk, s, t, f, o); } +FINUFFT_EXPORT void finufftf2d3many_(int *ntransf, i64 *nj, f32 *x, f32 *y, c64 *c, int *iflag, f32 *eps, i64 *nk, f32 *s, f32 *t, c64 *f, finufft_opts *o, int *ier) { *ier = finufftf2d3many(*ntransf, *nj, x, y, c, *iflag, *eps, *nk, s, t, f, o); } // --- 3D --- +FINUFFT_EXPORT void finufftf3d1_(i64 *nj, f32 *xj, f32 *yj, f32 *zj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, i64 *mu, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf3d1(*nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufftf3d1many_(int *ntransf, i64 *nj, f32 *xj, f32 *yj, f32 *zj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, i64 *mu, c64 *fk, finufft_opts *o, int *ier) { @@ -314,11 +358,13 @@ void finufftf3d1many_(int *ntransf, i64 *nj, f32 *xj, f32 *yj, f32 *zj, c64 *cj, finufftf3d1many(*ntransf, *nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufftf3d2_(i64 *nj, f32 *xj, f32 *yj, f32 *zj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, i64 *mu, c64 *fk, finufft_opts *o, int *ier) { *ier = finufftf3d2(*nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufftf3d2many_(int *ntransf, i64 *nj, f32 *xj, f32 *yj, f32 *zj, c64 *cj, int *iflag, f32 *eps, i64 *ms, i64 *mt, i64 *mu, c64 *fk, finufft_opts *o, int *ier) { @@ -326,11 +372,13 @@ void finufftf3d2many_(int *ntransf, i64 *nj, f32 *xj, f32 *yj, f32 *zj, c64 *cj, finufftf3d2many(*ntransf, *nj, xj, yj, zj, cj, *iflag, *eps, *ms, *mt, *mu, fk, o); } +FINUFFT_EXPORT void finufftf3d3_(i64 *nj, f32 *x, f32 *y, f32 *z, c64 *c, int *iflag, f32 *eps, i64 *nk, f32 *s, f32 *t, f32 *u, c64 *f, finufft_opts *o, int *ier) { *ier = finufftf3d3(*nj, x, y, z, c, *iflag, *eps, *nk, s, t, u, f, o); } +FINUFFT_EXPORT void finufftf3d3many_(int *ntransf, i64 *nj, f32 *x, f32 *y, f32 *z, c64 *c, int *iflag, f32 *eps, i64 *nk, f32 *s, f32 *t, f32 *u, c64 *f, finufft_opts *o, int *ier) { diff --git a/include/finufft/finufft_utils.hpp b/include/finufft/finufft_utils.hpp index d2b272c96..70bed01da 100644 --- a/include/finufft/finufft_utils.hpp +++ b/include/finufft/finufft_utils.hpp @@ -10,8 +10,7 @@ namespace finufft::utils { template -FINUFFT_EXPORT FINUFFT_ALWAYS_INLINE void FINUFFT_CDECL arrayrange(BIGINT n, const T *a, - T *lo, T *hi) +FINUFFT_ALWAYS_INLINE void arrayrange(BIGINT n, const T *a, T *lo, T *hi) // With a a length-n array, writes out min(a) to lo and max(a) to hi, // so that all a values lie in [lo,hi]. // If n==0, lo and hi are not finite. @@ -24,8 +23,7 @@ FINUFFT_EXPORT FINUFFT_ALWAYS_INLINE void FINUFFT_CDECL arrayrange(BIGINT n, con } } template -FINUFFT_EXPORT FINUFFT_ALWAYS_INLINE void FINUFFT_CDECL arraywidcen(BIGINT n, const T *a, - T *w, T *c) +FINUFFT_ALWAYS_INLINE void arraywidcen(BIGINT n, const T *a, T *w, T *c) // Writes out w = half-width and c = center of an interval enclosing all a[n]'s // Only chooses a nonzero center if this increases w by less than fraction // ARRAYWIDCEN_GROWFRAC defined in finufft_common/constants.h. @@ -43,10 +41,9 @@ FINUFFT_EXPORT FINUFFT_ALWAYS_INLINE void FINUFFT_CDECL arraywidcen(BIGINT n, co } // routines in finufft_utils.cpp ... -FINUFFT_EXPORT BIGINT next235even(BIGINT n); - +FINUFFT_EXPORT_TEST BIGINT next235even(BIGINT n); // jfm's timer class -class FINUFFT_EXPORT CNTime { +class FINUFFT_EXPORT_TEST CNTime { public: FINUFFT_NEVER_INLINE void start(); FINUFFT_NEVER_INLINE double restart(); @@ -67,7 +64,7 @@ FINUFFT_NEVER_INLINE unsigned getOptimalThreadCount(); #include namespace finufft { namespace utils { -FINUFFT_EXPORT int FINUFFT_CDECL rand_r(unsigned int *seedp); +FINUFFT_EXPORT_TEST int rand_r(unsigned int *seedp); } // namespace utils } // namespace finufft #endif diff --git a/include/finufft/spreadinterp.h b/include/finufft/spreadinterp.h index cf0b71cae..b47d02ec6 100644 --- a/include/finufft/spreadinterp.h +++ b/include/finufft/spreadinterp.h @@ -30,33 +30,26 @@ enum { namespace finufft { namespace spreadinterp { -// things external (spreadinterp) interface needs... template -FINUFFT_EXPORT int FINUFFT_CDECL spreadinterp( - UBIGINT N1, UBIGINT N2, UBIGINT N3, T *data_uniform, UBIGINT M, T *kx, T *ky, T *kz, - T *data_nonuniform, const finufft_spread_opts &opts); - -FINUFFT_EXPORT int FINUFFT_CDECL spreadcheck(UBIGINT N1, UBIGINT N2, UBIGINT N3, - const finufft_spread_opts &opts); -template -FINUFFT_EXPORT int FINUFFT_CDECL indexSort(std::vector &sort_indices, UBIGINT N1, - UBIGINT N2, UBIGINT N3, UBIGINT N, T *kx, - T *ky, T *kz, const finufft_spread_opts &opts); -template -FINUFFT_EXPORT int FINUFFT_CDECL spreadinterpSorted( - const std::vector &sort_indices, const UBIGINT N1, const UBIGINT N2, - const UBIGINT N3, T *data_uniform, const UBIGINT M, T *FINUFFT_RESTRICT kx, - T *FINUFFT_RESTRICT ky, T *FINUFFT_RESTRICT kz, T *FINUFFT_RESTRICT data_nonuniform, - const finufft_spread_opts &opts, int did_sort, bool adjoint); +FINUFFT_EXPORT_TEST int spreadinterp(UBIGINT N1, UBIGINT N2, UBIGINT N3, T *data_uniform, + UBIGINT M, T *kx, T *ky, T *kz, T *data_nonuniform, + const finufft_spread_opts &opts); template -FINUFFT_EXPORT T FINUFFT_CDECL evaluate_kernel(T x, const finufft_spread_opts &opts); +FINUFFT_EXPORT_TEST int setup_spreader(finufft_spread_opts &opts, T eps, double upsampfac, + int kerevalmeth, int debug, int showwarn, int dim, + int spreadinterponly); +int spreadcheck(UBIGINT N1, UBIGINT N2, UBIGINT N3, const finufft_spread_opts &opts); template -FINUFFT_EXPORT T FINUFFT_CDECL evaluate_kernel_horner(T x, - const finufft_spread_opts &opts); +int indexSort(std::vector &sort_indices, UBIGINT N1, UBIGINT N2, UBIGINT N3, + UBIGINT N, T *kx, T *ky, T *kz, const finufft_spread_opts &opts); template -FINUFFT_EXPORT int FINUFFT_CDECL setup_spreader( - finufft_spread_opts &opts, T eps, double upsampfac, int kerevalmeth, int debug, - int showwarn, int dim, int spreadinterponly); +int spreadinterpSorted(const std::vector &sort_indices, const UBIGINT N1, + const UBIGINT N2, const UBIGINT N3, T *data_uniform, + const UBIGINT M, T *FINUFFT_RESTRICT kx, T *FINUFFT_RESTRICT ky, + T *FINUFFT_RESTRICT kz, T *FINUFFT_RESTRICT data_nonuniform, + const finufft_spread_opts &opts, int did_sort, bool adjoint); +template T evaluate_kernel(T x, const finufft_spread_opts &opts); +template T evaluate_kernel_horner(T x, const finufft_spread_opts &opts); } // namespace spreadinterp } // namespace finufft diff --git a/include/finufft_common/defines.h b/include/finufft_common/defines.h index f26e3a7c6..d976c3fad 100644 --- a/include/finufft_common/defines.h +++ b/include/finufft_common/defines.h @@ -26,12 +26,18 @@ #define FINUFFT_EXPORT #endif +#ifdef FINUFFT_BUILD_TESTS +#define FINUFFT_EXPORT_TEST FINUFFT_EXPORT +#else +#define FINUFFT_EXPORT_TEST +#endif + /* specify calling convention (Windows only) The cdecl calling convention is actually not the default in all but a very few C/C++ compilers. If the user code changes the default compiler calling convention, may need this when generating DLL. */ -#if defined(_WIN32) || defined(__WIN32__) +#if defined(_WIN32) || defined(_MSC_VER) #define FINUFFT_CDECL __cdecl #else #define FINUFFT_CDECL diff --git a/include/finufft_common/utils.h b/include/finufft_common/utils.h index 2d03786d4..e8f8682db 100644 --- a/include/finufft_common/utils.h +++ b/include/finufft_common/utils.h @@ -10,7 +10,7 @@ namespace finufft { namespace common { -FINUFFT_EXPORT void FINUFFT_CDECL gaussquad(int n, double *xgl, double *wgl); +FINUFFT_EXPORT_TEST void gaussquad(int n, double *xgl, double *wgl); std::tuple leg_eval(int n, double x); // helper to generate the integer sequence in range [Start, End] diff --git a/makefile b/makefile index 23e394d79..0397f54a7 100644 --- a/makefile +++ b/makefile @@ -32,8 +32,24 @@ PYTHON = python3 CFLAGS := -O3 -funroll-loops -march=native -fcx-limited-range -ffp-contract=fast\ -fno-math-errno -fno-signed-zeros -fno-trapping-math -fassociative-math\ -freciprocal-math -fmerge-all-constants -ftree-vectorize $(CFLAGS) -Wfatal-errors +# do not allow semantic interposition. We do not want the users to override any of the internals +# it's default in clang but GCC is ELF compliant by default +CFLAGS += -fno-semantic-interposition FFLAGS := $(CFLAGS) $(FFLAGS) CXXFLAGS := $(CFLAGS) $(CXXFLAGS) + +# fix for exported symbols in test +OBJFLAGS := -DFINUFFT_BUILD_TESTS -fvisibility=hidden -DFINUFFT_DLL -Ddll_EXPORTS + +# Link Time Optimization +# Works with GCC and Clang. Increases link time, reduces binary size, can speed up hot paths. +ifneq ($(LTO),OFF) + LTOFLAGS := -flto + CFLAGS += $(LTOFLAGS) + CXXFLAGS += $(LTOFLAGS) + FFLAGS += $(LTOFLAGS) + LDFLAGS += $(LTOFLAGS) +endif # FFTW base name, and math linking... FFTWNAME = fftw3 # linux default is fftw3_omp, since 10% faster than fftw3_threads... @@ -169,6 +185,7 @@ usage: @echo "Make options:" @echo " 'make [task] OMP=OFF' for single-threaded (no refs to OpenMP)" @echo " 'make [task] FFT=DUCC' for DUCC0 FFT (otherwise uses FFTW3)" + @echo " 'make [task] LTO=OFF' disable link time optimization" @echo " You must at least 'make objclean' before changing such options!" @echo "" @echo "Also see docs/install.rst and docs/README" @@ -179,6 +196,10 @@ HEADERS = $(wildcard include/*.h include/finufft/*.h include/finufft_common/*.h) # implicit rules for objects (note -o ensures writes to correct dir) %.o: %.cpp $(HEADERS) $(CXX) -c $(CXXFLAGS) $< -o $@ +src/%.o: src/%.cpp $(HEADERS) + $(CXX) $(OBJFLAGS) -c $(CXXFLAGS) $< -o $@ +fortran/%.o: fortran/%.cpp $(HEADERS) + $(CXX) $(OBJFLAGS) -c $(CXXFLAGS) $< -o $@ %.o: %.c $(HEADERS) $(CC) -c $(CFLAGS) $< -o $@ %.o: %.f diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 64778517d..b60d66385 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,11 +12,7 @@ if(FINUFFT_USE_DUCC0) else() include(setupFFTW) endif() -if(FINUFFT_USE_DUCC0) - set(FINUFFT_FFTLIBS ducc0) -else() - set(FINUFFT_FFTLIBS ${FINUFFT_FFTW_LIBRARIES}) -endif() + if(FINUFFT_USE_OPENMP) find_package(OpenMP COMPONENTS C CXX REQUIRED) endif() @@ -40,6 +36,10 @@ else() add_library(finufft SHARED ${FINUFFT_SOURCES}) endif() +if(FINUFFT_BUILD_TESTS) + target_compile_definitions(finufft PRIVATE FINUFFT_BUILD_TESTS) +endif() + enable_static_analysis(finufft) add_iwyu_fix_target(finufft) add_library(finufft::finufft ALIAS finufft) @@ -48,9 +48,7 @@ if(FINUFFT_USE_DUCC0) target_compile_definitions(finufft PRIVATE FINUFFT_USE_DUCC0) endif() -target_link_libraries(finufft PUBLIC $) - -target_link_libraries(finufft PRIVATE $) +target_link_libraries(finufft PRIVATE $) if(FINUFFT_USE_OPENMP) target_link_libraries(finufft PRIVATE OpenMP::OpenMP_CXX) if(NOT FINUFFT_STATIC_LINKING) @@ -96,9 +94,6 @@ if(FINUFFT_ENABLE_INSTALL) set_target_properties(finufft PROPERTIES PUBLIC_HEADER "${FINUFFT_PUBLIC_HEADERS}") endif() -set(FINUFFT_FFTW_LIBRARIES "${FINUFFT_FFTW_LIBRARIES}" PARENT_SCOPE) -set(FINUFFT_FFTLIBS "${FINUFFT_FFTLIBS}" PARENT_SCOPE) - set(_targets ${INSTALL_TARGETS}) list(APPEND _targets finufft) set(INSTALL_TARGETS "${_targets}" PARENT_SCOPE) diff --git a/src/spreadinterp.cpp b/src/spreadinterp.cpp index 59c9d8d34..4b5613b95 100644 --- a/src/spreadinterp.cpp +++ b/src/spreadinterp.cpp @@ -1561,7 +1561,7 @@ static void get_subgrid(BIGINT &offset1, BIGINT &offset2, BIGINT &offset3, // ========================================================================== template -FINUFFT_EXPORT int FINUFFT_CDECL spreadinterp( +int spreadinterp( UBIGINT N1, UBIGINT N2, UBIGINT N3, T *data_uniform, UBIGINT M, T *kx, T *ky, T *kz, T *data_nonuniform, const finufft_spread_opts &opts) /* ------------Spreader/interpolator for 1, 2, or 3 dimensions -------------- @@ -1638,10 +1638,10 @@ FINUFFT_EXPORT int FINUFFT_CDECL spreadinterp( return 0; } -template FINUFFT_EXPORT int FINUFFT_CDECL spreadinterp( +template FINUFFT_EXPORT_TEST int spreadinterp( UBIGINT N1, UBIGINT N2, UBIGINT N3, float *data_uniform, UBIGINT M, float *kx, float *ky, float *kz, float *data_nonuniform, const finufft_spread_opts &opts); -template FINUFFT_EXPORT int FINUFFT_CDECL spreadinterp( +template FINUFFT_EXPORT_TEST int spreadinterp( UBIGINT N1, UBIGINT N2, UBIGINT N3, double *data_uniform, UBIGINT M, double *kx, double *ky, double *kz, double *data_nonuniform, const finufft_spread_opts &opts); @@ -2072,7 +2072,7 @@ template int spreadinterpSorted( /////////////////////////////////////////////////////////////////////////// template -FINUFFT_EXPORT int FINUFFT_CDECL setup_spreader( +int setup_spreader( finufft_spread_opts &opts, T eps, double upsampfac, int kerevalmeth, int debug, int showwarn, int dim, int spreadinterponly) /* Initializes spreader kernel parameters given desired NUFFT tolerance eps, @@ -2171,10 +2171,11 @@ FINUFFT_EXPORT int FINUFFT_CDECL setup_spreader( return ier; } -template FINUFFT_EXPORT int FINUFFT_CDECL setup_spreader( + +template FINUFFT_EXPORT_TEST int setup_spreader( finufft_spread_opts &opts, float eps, double upsampfac, int kerevalmeth, int debug, int showwarn, int dim, int spreadinterponly); -template FINUFFT_EXPORT int FINUFFT_CDECL setup_spreader( +template FINUFFT_EXPORT_TEST int setup_spreader( finufft_spread_opts &opts, double eps, double upsampfac, int kerevalmeth, int debug, int showwarn, int dim, int spreadinterponly); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 45a6b8eb9..d71a5ed53 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,6 @@ foreach(TEST ${TESTS}) add_executable(${TEST} ${TEST}.cpp) target_compile_features(${TEST} PRIVATE cxx_std_17) finufft_link_test(${TEST}) - add_executable(${TEST}f ${TEST}.cpp) target_compile_definitions(${TEST}f PRIVATE -DSINGLE) target_compile_features(${TEST}f PRIVATE cxx_std_17)