关于MPI::MPI_C别名的使用及参数设置疑问
关于CMake中MPI::MPI_C目标的疑问与解答
背景
我使用CMake 3.20.1构建ScaLAPACK(提交哈希:7e4e07070a489686287c36ab473d21cf29a54bdd),通过find_package(MPI)工具获取MPI编译所需的库、包含目录及编译选项。
两种链接方式出现不同结果:
- 使用
MPI::MPI_C导入目标链接:
target_link_libraries(scalapack ${LAPACK_LIBRARIES} ${BLAS_LIBRARIES} MPI::MPI_C)
构建并安装的共享库(DSO)带有RUNPATH条目:
$ readelf -d ~/opt/scalapack/lib/libscalapack.so | grep RUNPATH 0x000000000000001d (RUNPATH) Library runpath: [/opt/apps/resif/aion/2020b/epyc/software/UCX/1.9.0-GCCcore-10.2.0/lib64:/usr/lib64:/opt/apps/resif/aion/2020b/epyc/software/OpenMPI/4.0.5-GCC-10.2.0/lib]
- 使用
MPI_C_LIBRARIES变量链接:
target_link_libraries(scalapack ${LAPACK_LIBRARIES} ${BLAS_LIBRARIES} ${MPI_C_LIBRARIES})
安装后的DSO无RUNPATH条目。对比CMake生成的Makefile,发现使用MPI::MPI_C时会添加额外的系统选项。
问题
MPI::MPI_C是什么,应如何使用?- 为何该目标会设置大量参数,而非仅配置链接ScaLAPACK DSO与MPI所需的变量?
解答
1. MPI::MPI_C是什么,如何使用?
MPI::MPI_C是CMake通过find_package(MPI)生成的导入目标(Imported Target),属于CMake现代目标导向构建体系的一部分,不是简单的别名。
使用方式非常简洁:直接在target_link_libraries中引用该目标即可,不需要手动处理MPI_C_INCLUDE_DIRS、MPI_C_COMPILE_FLAGS这类零散变量——CMake会自动将该目标关联的包含目录、编译选项、链接库、链接选项等全部传递给你的目标(比如这里的scalapack)。
标准使用流程示例:
find_package(MPI REQUIRED) add_library(scalapack ...) # 无需手动添加include目录,链接时自动处理 target_link_libraries(scalapack PRIVATE ${LAPACK_LIBRARIES} ${BLAS_LIBRARIES} MPI::MPI_C)
2. 为何MPI::MPI_C会设置大量参数?
这是因为导入目标MPI::MPI_C封装了MPI库的完整依赖链和构建配置,不止是单纯的链接库:
- 包含MPI的头文件目录,会自动添加到目标的编译包含路径中;
- 携带MPI编译所需的预定义宏、编译标志(比如针对特定MPI实现的专属编译选项);
- 包含MPI库的间接依赖(比如你看到的UCX库路径,这是OpenMPI依赖的底层通信库);
- 自动处理共享库的运行时路径(RPATH/RUNPATH):CMake会确保你的库在运行时能找到MPI及其依赖库,这就是使用
MPI::MPI_C时生成的库带有RUNPATH的原因。而MPI_C_LIBRARIES只是单纯的库文件路径列表,不会传递RPATH相关配置,所以不会生成RUNPATH。
CMake默认在构建阶段会设置RPATH,安装时通常会清理,但部分MPI实现的导入目标会强制保留RUNPATH,或者CMake在处理导入目标的依赖时自动添加了这些路径,以保证运行时的依赖查找正常。
内容的提问来源于stack exchange,提问作者gkaf
相关产品推荐
相关产品推荐

