如何在CMake中同时引入并链接Kokkos与Eigen库
问题背景
现有一个依赖Eigen的C++代码库,需集成Kokkos库添加GPU功能,因此要在CMake中同时找到并链接这两个库。Eigen已启用BLAS和LAPACK依赖,单独链接其中一个依赖时编译正常,但同时链接两者时编译失败。
错误信息
In file included from /main.cpp:6:
In file included from /bask/apps/live/EL8-ice/software/Eigen/3.4.0-GCCcore-11.3.0/include/Eigen/Dense:7:
In file included from /bask/apps/live/EL8-ice/software/Eigen/3.4.0-GCCcore-11.3.0/include/Eigen/Eigenvalues:55:
/bask/apps/live/EL8-ice/software/Eigen/3.4.0-GCCcore-11.3.0/include/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h:80:1: error: host function 'compute' cannot overload host device function 'compute'
80 | EIGEN_LAPACKE_EIG_SELFADJ(double, double, double, dsyev)
| ^
/bask/apps/live/EL8-ice/software/Eigen/3.4.0-GCCcore-11.3.0/include/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h:77:9: note: expanded from macro 'EIGEN_LAPACKE_EIG_SELFADJ'
77 | EIGEN_LAPACKE_EIG_SELFADJ_2(EIGTYPE, LAPACKE_TYPE, LAPACKE_RTYPE, LAPACKE_NAME, ColMajor )
| ^
/bask/apps/live/EL8-ice/software/Eigen/3.4.0-GCCcore-11.3.0/include/Eigen/src/Eigenvalues/SelfAdjointEigenSolver_LAPACKE.h:43:72: note: expanded from macro 'EIGEN_LAPACKE_EIG_SELFADJ_2'
43 | SelfAdjointEigenSolver<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW> >::compute(const EigenBase& matrix, int options)
| ^
/bask/apps/live/EL8-ice/software/Eigen/3.4.0-GCCcore-11.3.0/include/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h:216:29: note: previous declaration is here
216 | SelfAdjointEigenSolver& compute(const EigenBase& matrix, int options = ComputeEigenvectors);
| ^
冲突原因:Kokkos链接后引入的CUDA编译选项,让编译器识别到Eigen中存在两个compute函数重载——一个是仅标记__host__的LAPACKE实现版本,另一个是带有__host__ __device__标记的通用版本,两者无法共存。
最小复现代码
main.cpp
#define lapack_complex_float std::complex<float> #define lapack_complex_double std::complex<double> #define EIGEN_USE_BLAS #define EIGEN_USE_LAPACKE #include <Eigen/Dense> int main(void){ Eigen::Matrix3d::Zero(); }
CMakeLists.txt
cmake_minimum_required (VERSION 3.8) set(CMAKE_CXX_STANDARD 20) project ("trial") find_package(Kokkos REQUIRED) find_package(BLAS REQUIRED) find_package(LAPACK REQUIRED) find_package(Eigen3 REQUIRED NO_MODULE) add_executable(main "main.cpp") target_link_libraries( main Kokkos::kokkos Eigen3::Eigen BLAS::BLAS LAPACK::LAPACK )
注:Kokkos、BLAS和Eigen已安装且可被CMake找到,移除Kokkos::kokkos链接时编译正常,仅添加该链接(即使未调用Kokkos代码)就会触发错误。
环境信息
- Clang 18.1.8
- CUDA/11.8.0
- OpenBLAS-0.3.20
- Eigen-3.4.0
- kokkos-4.3.01
- openmp=libomp
解决方案
方案1:禁用Eigen设备代码生成
在包含Eigen头文件前添加宏定义,强制Eigen仅生成__host__标记的函数,避免重载冲突:
#define EIGEN_NO_DEVICE_CODE #define lapack_complex_float std::complex<float> #define lapack_complex_double std::complex<double> #define EIGEN_USE_BLAS #define EIGEN_USE_LAPACKE #include <Eigen/Dense>
方案2:隔离Eigen编译单元
若代码中部分模块需Kokkos GPU功能,部分仅用Eigen+BLAS/LAPACK,可将Eigen相关代码编译为独立静态库(不链接Kokkos),主程序再链接该库和Kokkos:
- 创建
eigen_wrapper.cpp封装Eigen操作:
#define lapack_complex_float std::complex<float> #define lapack_complex_double std::complex<double> #define EIGEN_USE_BLAS #define EIGEN_USE_LAPACKE #include <Eigen/Dense> Eigen::Matrix3d create_zero_matrix() { return Eigen::Matrix3d::Zero(); }
- 修改CMakeLists.txt:
cmake_minimum_required (VERSION 3.8) set(CMAKE_CXX_STANDARD 20) project ("trial") find_package(Kokkos REQUIRED) find_package(BLAS REQUIRED) find_package(LAPACK REQUIRED) find_package(Eigen3 REQUIRED NO_MODULE) # 编译Eigen静态库,不链接Kokkos add_library(eigen_lib STATIC eigen_wrapper.cpp) target_link_libraries(eigen_lib Eigen3::Eigen BLAS::BLAS LAPACK::LAPACK) # 主程序链接Kokkos和Eigen静态库 add_executable(main "main.cpp") target_link_libraries(main Kokkos::kokkos eigen_lib)
- 修改main.cpp调用封装函数:
Eigen::Matrix3d create_zero_matrix(); int main(void){ auto mat = create_zero_matrix(); }
方案3:升级Eigen版本
Eigen 3.4.0存在该兼容性问题,升级到3.4.1及以上版本,官方已修复Kokkos/CUDA环境下的函数重载冲突。
内容的提问来源于stack exchange,提问作者Neil Butcher

