From 2456fbddfb5d01597b4007a109997743f4395848 Mon Sep 17 00:00:00 2001
From: Tim Kaune <tim.kaune@gmx.de>
Date: Wed, 14 May 2025 10:45:50 +0200
Subject: [PATCH] Move parsing of alias files to external dependency Accelerate
 LAPACK

---
 CMakeLists.txt     |  88 +++--------------------------
 README.md          | 138 ++++++++++-----------------------------------
 src/CMakeLists.txt | 129 +++++-------------------------------------
 3 files changed, 54 insertions(+), 301 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ab98ec8..74adf71 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,86 +41,16 @@ option(BUILD_INDEX64 "Link to ILP64 version of LAPACK?" OFF)
 
 message(STATUS "Trying to link to ILP64 interface of LAPACK: ${BUILD_NEW_LAPACK}")
 
-if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
-    # The available binary Accelerate version is determined by the MacOS system
-    message(STATUS "The Darwin kernel version is: ${CMAKE_HOST_SYSTEM_VERSION}")
-
-    if (CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 24.0)
-        # Mac OS X 15.0 Sequoia or later
-        message(STATUS "The MacOS version is: >=15.0")
-        set(MINIMUM_MACOS_SDK_VERSION 15.0)
-        set(ACCELERATE_NEW_LAPACK_VERSION 3.11.0)
-    elseif (CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 22.4)
-        # Mac OS X 13.3 Ventura or later
-        message(STATUS "The MacOS version is: >=13.3,<15.0")
-        set(MINIMUM_MACOS_SDK_VERSION 13.3)
-        set(VALID_MACOS_SDK_VERSIONS 14.5 14.4 14.2 14.0 13.3)
-        set(ACCELERATE_NEW_LAPACK_VERSION 3.9.1)
-    else ()
-        # Before Mac OS X 13.3 Ventura
-        message(FATAL_ERROR "You need at least MacOS 13.3 Ventura for Accelerate with BLAS/LAPACK v3.9.1!")
-    endif ()
-
-    message(STATUS "The BLAS/LAPACK version provided by the Accelerate framework should be: ${ACCELERATE_NEW_LAPACK_VERSION}")
-else ()
-    message(FATAL_ERROR "Accelerate is only available on MacOS!")
-endif ()
-
-if (NOT DEFINED CMAKE_OSX_SYSROOT OR CMAKE_OSX_SYSROOT STREQUAL "")
-    message(FATAL_ERROR "Please provide the CMAKE_OSX_SYSROOT location! See <https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_SYSROOT.html>")
-endif ()
-
-string(REGEX MATCH [=[SDKs/MacOSX(.*)\.sdk$]=] _REGEX_DUMMY "${CMAKE_OSX_SYSROOT}")
-set(MAIN_MACOS_SDK_VERSION "${CMAKE_MATCH_1}")
-
-# The text-based .dylib stubs describing the Accelerate framework are provided
-# by the MacOS SDK, which has to match the MacOS system. Otherwise, there might
-# be newer symbols in the text-based .dylib stubs that are not provided by the
-# Accelerate binary, leading to linking errors.
-if (NOT DEFINED VALID_MACOS_SDK_VERSIONS)
-    # MacOS system supports the latest iteration of the new Accelerate
-    # BLAS/LAPACK. Use the default SDK, if it's recent enough.
-    if (MAIN_MACOS_SDK_VERSION VERSION_LESS MINIMUM_MACOS_SDK_VERSION)
-        message(STATUS "The MacOS SDK is: ${CMAKE_OSX_SYSROOT}")
-        message(STATUS "The minimum compatible MacOS SDK version is: ${MINIMUM_MACOS_SDK_VERSION}")
-        message(FATAL_ERROR "Please install a more recent XCode for a compatible MacOS SDK.")
-    endif ()
-elseif (NOT MAIN_MACOS_SDK_VERSION IN_LIST VALID_MACOS_SDK_VERSIONS)
-    # MacOS system supports one of the past iterations of the new Accelerate
-    # BLAS/LAPACK. If the latest possible XCode is installed on this older
-    # system, there might be a mismatch between the SDK and the system binary.
-    # Find a matching SDK from the Command Line Tools instead (which must be
-    # manually installed).
-    foreach (_MACOS_SDK_VERSION IN LISTS VALID_MACOS_SDK_VERSIONS)
-        find_path(VALID_MACOS_SDK NAMES "MacOSX${_MACOS_SDK_VERSION}.sdk" HINTS "/Library/Developer/CommandLineTools/SDKs" NO_CACHE)
-
-        if (VALID_MACOS_SDK)
-            set(VALID_MACOS_SDK "${VALID_MACOS_SDK}/MacOSX${_MACOS_SDK_VERSION}.sdk")
-            break ()
-        endif ()
-    endforeach ()
-
-    if (VALID_MACOS_SDK)
-        # Override CMAKE_OSX_SYSROOT with a local variable.
-        set(CMAKE_OSX_SYSROOT "${VALID_MACOS_SDK}")
-    else ()
-        message(STATUS "The MacOS SDK is: ${CMAKE_OSX_SYSROOT}")
-        message(STATUS "The compatible MacOS SDK versions are: ${VALID_MACOS_SDK_VERSIONS}")
-        message(FATAL_ERROR "Couldn't find a compatible MacOS SDK. Please install compatible XCode Command Line Tools.")
-    endif ()
-endif ()
+FetchContent_Declare(
+    AccelerateLAPACK
+    GIT_REPOSITORY "https://github.com/lepus2589/accelerate-lapack.git"
+    GIT_TAG v1.4.0
+    SYSTEM
+    FIND_PACKAGE_ARGS 1.4.0 CONFIG NAMES AccelerateLAPACK
+)
 
-message(STATUS "The MacOS SDK is: ${CMAKE_OSX_SYSROOT}")
+set(AccelerateLAPACK_INCLUDE_PACKAGING FALSE)
 
-set(ENV{CMAKE_FRAMEWORK_PATH} "${CMAKE_OSX_SYSROOT}/System/Library/Frameworks")
-
-set(BLA_VENDOR "Apple")
-find_package(LAPACK MODULE)
-
-unset(ENV{CMAKE_FRAMEWORK_PATH})
-
-if (NOT LAPACK_FOUND OR NOT LAPACK_Accelerate_LIBRARY)
-    message(FATAL_ERROR "Couldn't find Accelerate framework in MacOS SDK!")
-endif ()
+FetchContent_MakeAvailable(AccelerateLAPACK)
 
 add_subdirectory(src)
diff --git a/README.md b/README.md
index 745dd0c..c0f207c 100644
--- a/README.md
+++ b/README.md
@@ -25,119 +25,24 @@ SOFTWARE.
 
 # Accelerate LAPACKE #
 
-Since MacOS 13.3 Ventura, Apple's Accelerate framework comes with a new
-[BLAS/LAPACK interface][accelerate-docs] compatible with [Reference LAPACK
-v3.9.1][lapack-v3.9.1] in addition to the quite outdated [Reference LAPACK
-v3.2.1][lapack-v3.2.1]. It also provides an ILP64 interface. On Apple Silicon
-M-processors, it utilises the [proprietary AMX co-processor][apple-amx], which
-makes it especially interesting. Unfortunately, it comes without the LAPACKE
-C-interface library.
-
-**Update**: With the release of MacOS 15.0 Sequoia, Apple updated the Accelerate
-framework to be compatible with [Reference LAPACK v3.11.0][lapack-v3.11.0].
-Unfortunately, there is no mention of it in the [MacOS 15.0 Sequoia Release
-Notes][macos15-release-notes], but the note in the [Accelerate BLAS
-docs][accelerate-docs] has been updated accordingly.
-
-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.
+Unfortunately, Apple's Accelerate framework doesn't provide the LAPACKE
+C-interface library. Since MacOS 13.3 Ventura, the [BLAS/LAPACK
+interface][accelerate-docs] provided by Accelerate is recent enough to support
+the LAPACKE library.
+
+This project uses [Accelerate LAPACK][accelerate-lapack] to build the LAPACKE
+library against the Accelerate NEWLAPACK interface. More info on BLAS/LAPACK in
+Accelerate can be found there, too.
 
 [accelerate-docs]: https://developer.apple.com/documentation/accelerate/blas-library
-[apple-amx]: https://github.com/corsix/amx
-[lapack-v3.2.1]: https://netlib.org/lapack/#_lapack_version_3_2_1
-[lapack-v3.9.1]: https://github.com/Reference-LAPACK/lapack/releases/tag/v3.9.1
-[lapack-v3.11.0]: https://github.com/Reference-LAPACK/lapack/releases/tag/v3.11.0
-[macos15-release-notes]: https://developer.apple.com/documentation/macos-release-notes/macos-15-release-notes
-
-- [The Problem](#the-problem)
-- [The Solution](#the-solution)
-  - [The alias files (to use in other projects)](#the-alias-files-to-use-in-other-projects)
+[accelerate-lapack]: https://github.com/lepus2589/accelerate-lapack
+
 - [How to compile](#how-to-compile)
   - [Prerequisites](#prerequisites)
   - [Workflow with CMake](#workflow-with-cmake)
     - [CMake v4 compatibility](#cmake-v4-compatibility)
   - [Using LAPACKE in another project](#using-lapacke-in-another-project)
 
-## The Problem ##
-
-But what if you have to or just want to link against the Accelerate framework
-without including the C/C++ headers, e.&nbsp;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][dgeqrt-ref] 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):
-
-```plaintext
-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?
-
-[dgeqrt-ref]: https://github.com/Reference-LAPACK/lapack/blob/v3.11.0/CMakeLists.txt#L365-L366
-
-## The Solution ##
-
-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 injected into the Reference LAPACK configure process using the
-`CMAKE_REQUIRED_LIBRARIES` variable for the Fortran test compiles and the
-`LINK_LIBRARIES` target property for the shared LAPACKE library.
-
-This enables the compilation of the LAPACKE C-interface library for the
-Accelerate framework (e.&nbsp;g. to be used in the `Eigen3` library). Analyzing
-the resulting `.dylib` with `otool`, you can see:
-
-```shell
-$ otool -L ./build/32/_deps/reference-lapack-build/lib/liblapacke.dylib
-./build/32/_deps/reference-lapack-build/lib/liblapacke.dylib:
-    @rpath/liblapacke.3.dylib (compatibility version 3.0.0, current version 3.11.0)
-    /System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate (compatibility version 1.0.0, current version 4.0.0)
-    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
-```
-
-Only the Accelerate framework and the System library are linked into the
-`.dylib`. No `libgfortran` or other libraries are needed.
-
-### The alias files (to use in other projects) ###
-
-After the CMake configuration, the alias files can be found in `./build/<32|64>/src`:
-
-```plaintext
-./build/<32|64>/src
-├── new-blas-ilp64.alias
-├── new-blas.alias
-├── new-lapack-ilp64.alias
-└── new-lapack.alias
-```
-
-These files can be used to link other projects against Accelerate, too, of course!
-
 ## How to compile ##
 
 It is recommended to use the Apple System C Compiler `/usr/bin/cc`. You can also
@@ -181,6 +86,19 @@ $ cmake --workflow --preset user-accelerate-lapacke32
 I wouldn't recommend installing to `/usr/local` (used by Homebrew on Intel Macs)
 or `/opt/local` (used by MacPorts).
 
+Analyzing the resulting `.dylib` with `otool`, you can see:
+
+```shell
+$ otool -L ./build/32/_deps/reference-lapack-build/lib/liblapacke.dylib
+./build/32/_deps/reference-lapack-build/lib/liblapacke.dylib:
+    @rpath/liblapacke.3.dylib (compatibility version 3.0.0, current version 3.11.0)
+    /System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate (compatibility version 1.0.0, current version 4.0.0)
+    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)
+```
+
+Only the Accelerate framework and the System library are linked into the
+`.dylib`. No `libgfortran` or other libraries are needed.
+
 #### CMake v4 compatibility ####
 
 To build the project with CMake v4 or higher, you must explicitly provide the
@@ -198,6 +116,12 @@ the CMake package in the other project's `CMakeLists.txt` file:
 find_package(LAPACKE CONFIG)
 ```
 
+or
+
+```cmake
+find_package(LAPACKE64 CONFIG)
+```
+
 and providing the above install location via the `CMAKE_PREFIX_PATH` variable
 from the command line:
 
@@ -205,5 +129,5 @@ from the command line:
 $ cmake -S . -B ./build -D "CMAKE_PREFIX_PATH=~/.local"
 ```
 
-This makes the imported `lapacke` shared library target available in the other
-project's `CMakeLists.txt`.
+This makes the imported `lapacke`/`lapacke64` shared library target available in
+the other project's `CMakeLists.txt`.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1b126d6..0791892 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -23,114 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 ]]
 
-include("../cmake/ParseTBDMacros.cmake")
-
-# Paths to text-based .dylib stubs
-set(BLAS_TBD_PATH "${LAPACK_Accelerate_LIBRARY}/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.tbd")
-set(LAPACK_TBD_PATH "${LAPACK_Accelerate_LIBRARY}/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.tbd")
-
-parse_tbd_symbols(BLAS "${BLAS_TBD_PATH}")
-filter_new_lapack_symbols(BLAS)
-filter_new_lapack_ilp64_symbols(BLAS)
-
-parse_tbd_symbols(LAPACK "${LAPACK_TBD_PATH}")
-filter_new_lapack_symbols(LAPACK)
-filter_new_lapack_ilp64_symbols(LAPACK)
-
-build_aliases(BLAS_NEWLAPACK_SYMBOLS)
-build_aliases(BLAS_NEWLAPACK_ILP64_SYMBOLS)
-build_aliases(LAPACK_NEWLAPACK_SYMBOLS)
-build_aliases(LAPACK_NEWLAPACK_ILP64_SYMBOLS)
-
-configure_file(
-    "${CMAKE_CURRENT_SOURCE_DIR}/new-blas.alias.in"
-    "${CMAKE_CURRENT_BINARY_DIR}/new-blas.alias"
-    @ONLY
-)
-
-configure_file(
-    "${CMAKE_CURRENT_SOURCE_DIR}/new-lapack.alias.in"
-    "${CMAKE_CURRENT_BINARY_DIR}/new-lapack.alias"
-    @ONLY
-)
-
-configure_file(
-    "${CMAKE_CURRENT_SOURCE_DIR}/new-blas-ilp64.alias.in"
-    "${CMAKE_CURRENT_BINARY_DIR}/new-blas-ilp64.alias"
-    @ONLY
-)
-
-configure_file(
-    "${CMAKE_CURRENT_SOURCE_DIR}/new-lapack-ilp64.alias.in"
-    "${CMAKE_CURRENT_BINARY_DIR}/new-lapack-ilp64.alias"
-    @ONLY
-)
-
-add_library(NEW_BLAS INTERFACE IMPORTED GLOBAL)
-target_link_libraries(NEW_BLAS INTERFACE ${BLAS_LIBRARIES})
-
-add_library(NEW_LAPACK INTERFACE IMPORTED GLOBAL)
-target_link_libraries(NEW_LAPACK INTERFACE ${LAPACK_LIBRARIES} NEW_BLAS)
-
-# Add the $NEWLAPACK symbols to the linker flags of the NEW_BLAS and NEW_LAPACK
-# targets
-target_link_options(
-    NEW_BLAS
-    INTERFACE
-    ${BLAS_LINKER_FLAGS}
-    "LINKER:-alias_list,${CMAKE_CURRENT_BINARY_DIR}/new-blas.alias"
-)
-target_link_options(
-    NEW_LAPACK
-    INTERFACE
-    ${LAPACK_LINKER_FLAGS}
-    "LINKER:-alias_list,${CMAKE_CURRENT_BINARY_DIR}/new-lapack.alias"
-)
-
-add_library(NEW_BLAS64 INTERFACE IMPORTED GLOBAL)
-target_link_libraries(NEW_BLAS64 INTERFACE ${BLAS_LIBRARIES})
-
-add_library(NEW_LAPACK64 INTERFACE IMPORTED GLOBAL)
-target_link_libraries(NEW_LAPACK64 INTERFACE ${LAPACK_LIBRARIES} NEW_BLAS64)
-
-# Add the $NEWLAPACK$ILP64 symbols to the linker flags of the NEW_BLAS64 and
-# NEW_LAPACK64 targets
-target_link_options(
-    NEW_BLAS64
-    INTERFACE
-    ${BLAS_LINKER_FLAGS}
-    "LINKER:-alias_list,${CMAKE_CURRENT_BINARY_DIR}/new-blas-ilp64.alias"
-)
-target_link_options(
-    NEW_LAPACK64
-    INTERFACE
-    ${LAPACK_LINKER_FLAGS}
-    "LINKER:-alias_list,${CMAKE_CURRENT_BINARY_DIR}/new-lapack-ilp64.alias"
-)
-
-if (BUILD_INDEX64)
-    # Add the $NEWLAPACK$ILP64 symbols to the BLAS and LAPACK libraries.
-    set(BLAS_LIBRARIES "NEW_BLAS64")
-    set(LAPACK_LIBRARIES "NEW_LAPACK64")
-    set(CHECK_LAPACK_VERSION_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/lapack64_version.c")
-else ()
-    # Add the $NEWLAPACK symbols to the linker flags of the lapacke target
-    set(BLAS_LIBRARIES "NEW_BLAS")
-    set(LAPACK_LIBRARIES "NEW_LAPACK")
-    set(CHECK_LAPACK_VERSION_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/lapack_version.c")
-endif ()
-
-set_target_properties(BLAS::BLAS PROPERTIES INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARIES}")
-set_target_properties(LAPACK::LAPACK PROPERTIES INTERFACE_LINK_LIBRARIES "${LAPACK_LIBRARIES}")
-
-try_run(
-    HAS_RUN_ILAVER HAS_ILAVER
-    SOURCES ${CHECK_LAPACK_VERSION_SOURCE}
-    LINK_LIBRARIES ${LAPACK_LIBRARIES}
-    RUN_OUTPUT_VARIABLE ACCELERATE_LAPACK_ILAVER_VERSION
-)
-
-message(STATUS "The BLAS/LAPACK version provided by the Accelerate framework is confirmed to be: ${ACCELERATE_LAPACK_ILAVER_VERSION}")
+get_target_property(ACCELERATE_NEW_LAPACK_VERSION LAPACK::NEW_LAPACK VERSION)
 
 FetchContent_Declare(
     reference-lapack
@@ -150,14 +43,14 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 4)
     set(ENV{CMAKE_POLICY_VERSION_MINIMUM} 3.5)
 endif ()
 
-set(BLAS_LIBRARIES_BACKUP "${BLAS_LIBRARIES}")
-set(LAPACK_LIBRARIES_BACKUP "${LAPACK_LIBRARIES}")
+set(BLAS_LIBRARIES_BACKUP "BLAS::BLAS")
+set(LAPACK_LIBRARIES_BACKUP "LAPACK::LAPACK")
 
 # Set the BLAS and LAPACK libraries to the new 32bit targets. This helps the
 # Reference LAPACK CMake script to pass the CheckFortranFunctionExists tests for
 # `dgemm` and `dgeqrt`.
-set(BLAS_LIBRARIES "NEW_BLAS")
-set(LAPACK_LIBRARIES "NEW_LAPACK")
+set(BLAS_LIBRARIES "BLAS::NEW_BLAS_IMPORTED")
+set(LAPACK_LIBRARIES "LAPACK::NEW_LAPACK_IMPORTED")
 
 FetchContent_MakeAvailable(reference-lapack)
 
@@ -171,8 +64,14 @@ endif ()
 
 if (BUILD_INDEX64)
     # Replace the LINK_LIBRARIES of the lapacke64 target with the ILP64 ones.
-    # The lapacke64 target was created linking to the NEW_LAPACK target, which
-    # we had to add to satisfy the Check... tests, that the Reference LAPACK
-    # build script does.
+    # The lapacke64 target was created linking to the NEW_LAPACK_IMPORTED
+    # target, which we had to add to satisfy the Check... tests, that the
+    # Reference LAPACK build script does.
     set_target_properties(lapacke64 PROPERTIES LINK_LIBRARIES "${LAPACK_LIBRARIES}")
+else ()
+    # Replace the LINK_LIBRARIES of the lapacke target with the NEWLAPACK ones.
+    # The lapacke target was created linking to the NEW_LAPACK_IMPORTED target,
+    # which we had to add to satisfy the Check... tests, that the Reference
+    # LAPACK build script does.
+    set_target_properties(lapacke PROPERTIES LINK_LIBRARIES "${LAPACK_LIBRARIES}")
 endif ()
-- 
GitLab