diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b592d98..393e17c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +Unreleased + - Added `blas_symbol_suffix` option (and `BLAS_FORTRAN_SUFFIX` compile + define) for linking against BLAS libraries whose Fortran symbols carry + a suffix, e.g. OpenBLAS built with `INTERFACE64=1 SYMBOLSUFFIX=64_` + exports `dgemm_64_`. Empty (default) preserves existing behavior. When + set, the OpenBLAS search probe links `-lopenblas${blas_symbol_suffix}`. + Supported by both the CMake and Make (`configure.py`) builds. + - The OpenBLAS search now also probes `-lopenblas64`, so the ILP64 build + Debian/Ubuntu ship as `libopenblas64` is found automatically. + 2025.05.28 (ABI 2.0.0) - Added Level 1 BLAS GPU wrappers - Added is_complex_v diff --git a/CMakeLists.txt b/CMakeLists.txt index cbb96243..88e63972 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,9 @@ set_property( CACHE blas_int PROPERTY STRINGS "auto" "int (LP64)" "int64_t (ILP64)" ) +set( blas_symbol_suffix "" CACHE STRING + "Suffix appended to BLAS symbol names after Fortran mangling, e.g. '64_' for OpenBLAS built with INTERFACE64=1 SYMBOLSUFFIX=64_. Empty (default) preserves existing behavior." ) + set( blas_threaded "auto" CACHE STRING "Multi-threaded BLAS?" ) set_property( @@ -146,6 +149,7 @@ BLA_VENDOR = ${BLA_VENDOR} blas = ${blas} blas_fortran = ${blas_fortran} blas_int = ${blas_int} +blas_symbol_suffix = ${blas_symbol_suffix} blas_threaded = ${blas_threaded} lapack = ${lapack} build_tests = ${build_tests} diff --git a/cmake/BLASFinder.cmake b/cmake/BLASFinder.cmake index 2994f855..1237d104 100644 --- a/cmake/BLASFinder.cmake +++ b/cmake/BLASFinder.cmake @@ -382,6 +382,17 @@ if (test_openblas) # todo: OPENBLAS_?(ROOT|DIR) list( APPEND blas_name_list "OpenBLAS" ) list( APPEND blas_libs_list "-lopenblas" ) + # Debian/Ubuntu ship the ILP64 build as libopenblas64, with standard + # (unsuffixed) dgemm_ symbols, so it needs only the -lopenblas64 name. + list( APPEND blas_name_list "OpenBLAS (ILP64, -lopenblas64)" ) + list( APPEND blas_libs_list "-lopenblas64" ) + # OpenBLAS built with SYMBOLSUFFIX (e.g. conda-forge's libopenblas64_, + # exporting dgemm_64_) follows the same naming; blas_symbol_suffix adds + # both the suffixed link name and the BLAS_FORTRAN_SUFFIX define (below). + if (blas_symbol_suffix) + list( APPEND blas_name_list "OpenBLAS (symbol suffix '${blas_symbol_suffix}')" ) + list( APPEND blas_libs_list "-lopenblas${blas_symbol_suffix}" ) + endif() debug_print_list( "openblas" ) endif() @@ -420,6 +431,14 @@ endif() set( BLAS_FOUND false ) unset( blaspp_defs_ CACHE ) +# Extra define to forward to the link/run probes when the user has +# requested a BLAS symbol suffix. Kept separate from the mangling +# loop because it is orthogonal to UPPER/LOWER/ADD_. +set( blas_symbol_suffix_def "" ) +if (blas_symbol_suffix) + set( blas_symbol_suffix_def "-DBLAS_FORTRAN_SUFFIX=${blas_symbol_suffix}" ) +endif() + set( i 0 ) foreach (blas_name IN LISTS blas_name_list) message( TRACE "i: ${i}" ) @@ -454,7 +473,7 @@ foreach (blas_name IN LISTS blas_name_list) LINK_LIBRARIES ${blas_libs} ${openmp_lib} # not "..." quoted; screws up OpenMP COMPILE_DEFINITIONS - "${mangling} ${int_size}" + "${mangling} ${int_size} ${blas_symbol_suffix_def}" OUTPUT_VARIABLE link_output ) @@ -475,7 +494,7 @@ foreach (blas_name IN LISTS blas_name_list) LINK_LIBRARIES ${blas_libs} ${openmp_lib} # not "..." quoted; screws up OpenMP COMPILE_DEFINITIONS - "${mangling} ${int_size}" + "${mangling} ${int_size} ${blas_symbol_suffix_def}" COMPILE_OUTPUT_VARIABLE compile_output RUN_OUTPUT_VARIABLE @@ -518,6 +537,9 @@ foreach (blas_name IN LISTS blas_name_list) if (int_size MATCHES "[^ ]") # non-empty list( APPEND blaspp_defs_ "${int_size}" ) endif() + if (blas_symbol_suffix_def MATCHES "[^ ]") # non-empty + list( APPEND blaspp_defs_ "${blas_symbol_suffix_def}" ) + endif() if (int_size MATCHES "ILP64") set( blaspp_int "int64" ) else() diff --git a/config/config.h b/config/config.h index 37b0b680..b303fb83 100644 --- a/config/config.h +++ b/config/config.h @@ -15,7 +15,15 @@ #define FORTRAN_NAME( lower, UPPER ) lower #else // default is ADD_ - #define FORTRAN_NAME( lower, UPPER ) lower ## _ + #ifdef BLAS_FORTRAN_SUFFIX + // Suffix-aware variant for libraries like OpenBLAS with SYMBOLSUFFIX=64_. + #define FORTRAN_CONCAT_( a, b ) a##b + #define FORTRAN_CONCAT( a, b ) FORTRAN_CONCAT_( a, b ) + #define FORTRAN_NAME( lower, UPPER ) \ + FORTRAN_CONCAT( lower##_, BLAS_FORTRAN_SUFFIX ) + #else + #define FORTRAN_NAME( lower, UPPER ) lower ## _ + #endif #endif //------------------------------------------------------------------------------ diff --git a/config/lapack.py b/config/lapack.py index 057dcef3..4435793e 100644 --- a/config/lapack.py +++ b/config/lapack.py @@ -319,6 +319,19 @@ def blas(): #-------------------- OpenBLAS if (test_openblas): choices.append( ['OpenBLAS', {'LIBS': '-lopenblas'}]) + # Debian/Ubuntu ship the ILP64 build as libopenblas64, with standard + # (unsuffixed) dgemm_ symbols, so it needs only the -lopenblas64 name. + choices.append( ['OpenBLAS (ILP64, -lopenblas64)', + {'LIBS': '-lopenblas64'}]) + # OpenBLAS built with SYMBOLSUFFIX (e.g. conda-forge's libopenblas64_, + # exporting dgemm_64_) needs both the suffixed name and the matching + # BLAS_FORTRAN_SUFFIX so blaspp mangles its calls to dgemm_64_. + blas_symbol_suffix = config.environ['blas_symbol_suffix'] + if (blas_symbol_suffix): + choices.append( + ['OpenBLAS (symbol suffix ' + blas_symbol_suffix + ')', + {'LIBS': '-lopenblas' + blas_symbol_suffix, + 'CXXFLAGS': define( 'FORTRAN_SUFFIX', blas_symbol_suffix )}]) #-------------------- BLIS (also used by AMD AOCL) if (test_blis): diff --git a/include/blas/mangling.h b/include/blas/mangling.h index 7e556742..fcbecece 100644 --- a/include/blas/mangling.h +++ b/include/blas/mangling.h @@ -14,13 +14,33 @@ // define FORTRAN_LOWER for lowercase (IBM xlf), // else the default is lowercase with appended underscore // (GNU gcc, Intel icc, PGI pgfortan, Cray ftn). +// +// BLAS_FORTRAN_SUFFIX, if defined, is appended to every mangled symbol. +// Used to link against BLAS libraries that suffix their symbols, e.g., +// OpenBLAS built with INTERFACE64=1 SYMBOLSUFFIX=64_ exports `dgemm_64_`. +// Pass via CMake's `blas_symbol_suffix` option. #ifndef BLAS_FORTRAN_NAME - #if defined(BLAS_FORTRAN_UPPER) - #define BLAS_FORTRAN_NAME( lower, UPPER ) UPPER - #elif defined(BLAS_FORTRAN_LOWER) - #define BLAS_FORTRAN_NAME( lower, UPPER ) lower + #ifdef BLAS_FORTRAN_SUFFIX + #define BLAS_FORTRAN_CONCAT_( a, b ) a##b + #define BLAS_FORTRAN_CONCAT( a, b ) BLAS_FORTRAN_CONCAT_( a, b ) + #if defined(BLAS_FORTRAN_UPPER) + #define BLAS_FORTRAN_NAME( lower, UPPER ) \ + BLAS_FORTRAN_CONCAT( UPPER, BLAS_FORTRAN_SUFFIX ) + #elif defined(BLAS_FORTRAN_LOWER) + #define BLAS_FORTRAN_NAME( lower, UPPER ) \ + BLAS_FORTRAN_CONCAT( lower, BLAS_FORTRAN_SUFFIX ) + #else + #define BLAS_FORTRAN_NAME( lower, UPPER ) \ + BLAS_FORTRAN_CONCAT( lower##_, BLAS_FORTRAN_SUFFIX ) + #endif #else - #define BLAS_FORTRAN_NAME( lower, UPPER ) lower##_ + #if defined(BLAS_FORTRAN_UPPER) + #define BLAS_FORTRAN_NAME( lower, UPPER ) UPPER + #elif defined(BLAS_FORTRAN_LOWER) + #define BLAS_FORTRAN_NAME( lower, UPPER ) lower + #else + #define BLAS_FORTRAN_NAME( lower, UPPER ) lower##_ + #endif #endif #endif