Since MacOS 13.3 Ventura, Apple's Accelerate framework comes with a new BLAS/LAPACK interface compatible with Reference LAPACK v3.9.1 in addition to the quite outdated Reference LAPACK v3.2.1. It also provides an ILP64 interface. On Apple Silicon M-processors, it utilises the proprietary AMX co-processor, which makes it especially interesting.
Update: With the release of MacOS 15.0 Sequoia, Apple updated the Accelerate framework to be compatible with Reference LAPACK v3.11.0. Unfortunately, there is no mention of it in the MacOS 15.0 Sequoia Release Notes, but the note in the Accelerate BLAS docs has been updated accordingly.
Update2: With the release of MacOS 15.5 Sequoia, Apple updated the Accelerate framework to be compatible with Reference LAPACK v3.12.0. Unfortunately, there is no mention of it in the MacOS 15.5 Sequoia Release Notes, but the note in the Accelerate BLAS docs has been updated accordingly, even though it erroneously says, v3.12.0 will be supported with MacOS 26.
These new interfaces are hidden behind the preprocessor defines
ACCELERATE_NEW_LAPACK and ACCELERATE_LAPACK_ILP64 and they only work, if you
include the Accelerate C/C++ headers.
But what if you have to or just want to link against the Accelerate framework without including the C/C++ headers, e. g. when compiling Fortran code or a third-party project, that uses the standard BLAS/LAPACK API? Well, you're out of luck. The binary symbols for the new LAPACK version exported by the Accelerate framework do not adhere to the BLAS/LAPACK API. Thus, they cannot be resolved by the linker, when linking any program or library that uses the standard BLAS/LAPACK API.
Take, for example, the dgeqrt LAPACK routine, that is used by the Reference
LAPACK CMake script to determine, if the user provided LAPACK
version is recent enough. When the Fortran test executable is compiled, the
gfortran compiler creates a function call with the binary symbol _dgeqrt_,
which results in the following error when linking to Accelerate (ld is the
Apple system linker, here):
ld: Undefined symbols:
_dgeqrt_, referenced from:
_MAIN__ in testFortranCompiler.f.o
The reason for this is, that the binary symbol provided by the Accelerate
framework is called _dgeqrt$NEWLAPACK, literally. This is a symbol, that no
Fortran compiler will probably ever emit voluntarily. So, what to do?
According to its man page, the Apple system linker ld provides the options
-alias and -alias_list, which let you create alias names for existing binary
symbols. Calling the linker with -alias '_dgeqrt$NEWLAPACK' _dgeqrt_ makes the
linking of the above Fortran test executable finish successfully.
Because BLAS and LAPACK contain quite a number of subroutines and functions,
this CMake scipt uses the -alias_list option, which loads a plaintext file
listing all the aliases.
To generate the full alias list for the Accelerate NEWLAPACK interface, it
parses the symbols listed in the BLAS and LAPACK text-based .dylib stubs. For
every symbol that ends in $NEWLAPACK (or $NEWLAPACK$ILP64 for the ILP64
interface), an alias is added to the alias file.
The additional linker options get attached to new interface library targets, which are in turn attached to the BLAS::BLAS and LAPACK::LAPACK targets.
After building and installing, the alias files can be found in
<install prefix>/share/cmake/AccelerateLAPACK-<version>:
share/cmake/AccelerateLAPACK-<version>
├── new-blas-ilp64.alias
├── new-blas.alias
├── new-lapack-ilp64.alias
└── new-lapack.alias
These files can be used to link any project against Accelerate! For CMake projects, you can just import this project.
It is recommended to use the Apple System C Compiler /usr/bin/cc. You can also
use a more recent Clang compiler provided by Homebrew or MacPorts. If you have
other compilers installed on your system, make sure CMake finds the correct one.
Otherwise, help CMake by setting the environment variable $ export CC=/usr/bin/cc in your terminal window.
It is also recommended to use at least CMake v3.25 with presets, but the CMake script also works down to CMake v3.12, if you set the required variables on the command line.
Obviously, your operating system must be Mac OS X >=v13.3 Ventura with XCode installed. Additionally, you'll need the following software (easily obtainable via Homebrew or MacPorts):
- CMake
To build the project you must provide the CMAKE_OSX_SYSROOT
variable. Prior to CMake v4, this was computed automatically, if empty. Since
CMake v4, this is empty by default and won't be populated automatically.
In any case, it is strongly recommended to explicitly select a matching SDK for your MacOS system. Matching in this case means, that the Accelerate framework's API in the SDK must match the Accelerate framework's binary in the MacOS system. The API in the SDK could either be too old (if you upgraded your system but didn't update your XCode/Command Line Tools yet) or too recent (if you're on an older system but installed the latest XCode/Command Line Tools). In both cases, you risk errors, so the build script checks and prevents this.
It's recommended to provide the CMAKE_OSX_SYSROOT via the SDKROOT
environment variable, which in turn can be provided by MacOS tooling (xcrun).
If you start cmake via xcrun, xcrun will provide the currently selected
SDK in the SDKROOT environment variable to cmake (macosx selects the
latest macosx SDK in the active developer directory):
$ xcrun --sdk macosx cmake ...To check, which SDK this is, use:
$ xcrun --sdk macosx --show-sdk-pathIf the build fails due to a mismatch between SDK and MacOS system, check your available SDKs in the active developer directory with
$ xcodebuild -showsdksand use a different SDK version macosx<XX.X>. If the SDK version you're
looking for can't be found in the active developer directory, change it using
$ xcode-select --switch <path>This way, you can switch between /Applications/Xcode.app/Contents/Developer
and /Library/Developer/CommandLineTools, for example, or between different
XCode versions.
Alternatively, you can directly provide the CMAKE_OSX_SYSROOT cache variable
in your CMakeUserPresets.json. Both the user-accelerate-lapack32 and
user-accelerate-lapack64 presets should additionally have the cache variable
"CMAKE_OSX_SYSROOT": "macosx" or "CMAKE_OSX_SYSROOT": "<path>".
Use the accelerate-lapack32-install preset (or the
accelerate-lapack64-install preset for the ILP64 interface) with CMake (prefix
all of the following commands with xcrun, see above):
$ cmake --workflow --preset accelerate-lapack32-installThis will configure and install Accelerate LAPACK in your ~/.local
directory by default. If you prefer a different install location (e. g.
/opt/custom), you can change it using a CMakeUserPresets.json file, for
which a template file is provided:
$ cmake --workflow --preset user-accelerate-lapack32-installI wouldn't recommend installing to /usr/local (used by Homebrew on Intel Macs)
or /opt/local (used by MacPorts).
If your install location is write protected, use the accelerate-lapack32 and
accelerate-lapack64 workflow presets to configure and build the project only
and then install with:
$ sudo cmake --build --preset user-accelerate-lapack32-installand
$ sudo cmake --build --preset user-accelerate-lapack64-installYou can use Accelerate LAPACK in other CMake projects as a drop-in replacement
for FindLAPACK like this:
if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin" AND BLA_VENDOR STREQUAL "Apple")
include(FetchContent)
FetchContent_Declare(
AccelerateLAPACK
GIT_REPOSITORY "https://github.com/lepus2589/accelerate-lapack.git"
GIT_TAG v2.0.0
SYSTEM
FIND_PACKAGE_ARGS 2.0.0 CONFIG NAMES AccelerateLAPACK
)
set(AccelerateLAPACK_INCLUDE_PACKAGING TRUE)
FetchContent_MakeAvailable(AccelerateLAPACK)
else ()
find_package(LAPACK MODULE)
endif ()and optionally providing the above install location via the CMAKE_PREFIX_PATH
variable from the command line:
$ cmake -S . -B ./build -D "CMAKE_PREFIX_PATH=~/.local"This makes the modified BLAS::BLAS and LAPACK::LAPACK targets available in the
other project's CMakeLists.txt.
BLA_SIZEOF_INTEGER: This is the same variable name that is used in theFindBLASandFindLAPACKmodules and selects the 32 bit or 64 bit interface, respectively.
-
BLAS::NEW_BLAStarget: This target links against the 32 bit interface of Accelerate's NewBLAS interface. -
BLAS::NEW_BLAS64target: This target links against the 64 bit interface of Accelerate's NewBLAS interface. -
LAPACK::NEW_LAPACKtarget: This target links against the 32 bit interface of Accelerate's NewLAPACK interface. -
LAPACK::NEW_LAPACK64target: This target links against the 64 bit interface of Accelerate's NewLAPACK interface. -
BLAS::BLAStarget, interface depends onBLA_SIZEOF_INTEGER -
LAPACK::LAPACKtarget, interface depends onBLA_SIZEOF_INTEGER -
ACCELERATE_LAPACK_ILAVER_VERSION: Accelerate's LAPACK version -
BLAS32_LIBRARIES: link libraries for Accelerate's NewBLAS 32 bit interface -
BLAS32_LINKER_FLAGS: link flags for Accelerate's NewBLAS 32 bit interface -
BLAS64_LIBRARIES: link libraries for Accelerate's NewBLAS 64 bit interface -
BLAS64_LINKER_FLAGS: link flags for Accelerate's NewBLAS 64 bit interface -
BLAS_LIBRARIES: patched link libraries for Accelerate's NewBLAS interface depending onBLA_SIZEOF_INTEGER -
BLAS_LINKER_FLAGS: patched link flags for Accelerate's NewBLAS interface depending onBLA_SIZEOF_INTEGER -
LAPACK32_LIBRARIES: link libraries for Accelerate's NewLAPACK 32 bit interface -
LAPACK32_LINKER_FLAGS: link flags for Accelerate's NewLAPACK 32 bit interface -
LAPACK64_LIBRARIES: link libraries for Accelerate's NewLAPACK 64 bit interface -
LAPACK64_LINKER_FLAGS: link flags for Accelerate's NewLAPACK 64 bit interface -
LAPACK_LIBRARIES: patched link libraries for Accelerate's NewLAPACK interface depending onBLA_SIZEOF_INTEGER -
LAPACK_LINKER_FLAGS: patched link flags for Accelerate's NewLAPACK interface depending onBLA_SIZEOF_INTEGER