在CMake项目中使用Boost Multiprecision时出现mpfr_*函数未定义引用
我想在C++项目中使用Boost Multiprecision,但编译报错,怀疑是根目录CMakeLists.txt的依赖配置有误。相关配置如下:
根目录CMakeLists.txt 相关代码
cmake_minimum_required(VERSION 3.30.0) project(MyProject VERSION 1.0.0 LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_subdirectory(src) add_subdirectory(app) add_subdirectory(test) find_package(Boost REQUIRED) include_directories(${Boost_INCLUDE_DIRS}) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") find_package(MPFR REQUIRED) include(MPFR_INCLUDE_DIRS}) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack)
app/CMakeLists.txt 配置
add_executable(main main.cpp) target_link_libraries(main PRIVATE myLib) target_link_libraries(main ${Boost_LIBRARIES}) target_link_libraries(main ${MPFR_LIBRARIES})
src/CMakeLists.txt 配置
file(GLOB HEADER_LIST CONFIGURE_DEPENDS "${MyProject_SOURCE_DIR}/include/*.h") add_library(myLib SomeFile.cpp ${HEADER_LIST}) target_include_directories(myLib PUBLIC ../include) target_link_libraries(myLib ${Boost_LIBRARIES}) target_link_libraries(myLib ${MPFR_LIBRARIES})
我已通过包管理器确认系统中已安装Boost和MPFR,用Clangd检查代码时,包含必要头文件并使用boost::multiprecision::mpfr_float_100类型未报错:
#include <boost/multiprecision/mpfr.hpp> // ... int main() { IOParser<boost::multiprecision::mpfr_float_100> parser; // ... }
但编译程序时,出现多个MPFR函数的未定义引用错误,例如:
[build] /usr/bin/ld: CMakeFiles/main.dir/main.cpp.o: in function `boost::multiprecision::backends::detail::mpfr_float_imp<100u, (boost::multiprecision::mpfr_allocation_type)1>::operator=(boost::multiprecision::backends::detail::mpfr_float_imp<100u, (boost::multiprecision::mpfr_allocation_type)1>&&) [clone .isra.0]': [build] main.cpp:(.text+0x2dc): undefined reference to `mpfr_swap' [build] /usr/bin/ld: main.cpp:(.text+0x30c): undefined reference to `mpfr_set4' [build] /usr/bin/ld: main.cpp:(.text+0x386): undefined reference to `mpfr_init2'
请问哪里出错了?
问题出在CMake配置顺序和依赖传递方式上,具体原因和修复步骤如下:
1. 依赖查找顺序颠倒
你在执行add_subdirectory(src)、add_subdirectory(app)之后才运行find_package(Boost)和find_package(MPFR),导致子目录的CMake配置在读取Boost/MPFR的变量前就已执行,此时子目录里的${Boost_LIBRARIES}、${MPFR_LIBRARIES}是空值,根本没链接到实际库文件。
修复: 将find_package相关代码移到add_subdirectory之前:
cmake_minimum_required(VERSION 3.30.0) project(MyProject VERSION 1.0.0 LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 先查找依赖,确保子目录能获取到有效变量 find_package(Boost REQUIRED) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") find_package(MPFR REQUIRED) add_subdirectory(src) add_subdirectory(app) add_subdirectory(test) # 不推荐全局include_directories,改用目标级别的头文件配置 # include_directories(${Boost_INCLUDE_DIRS}) # include_directories(${MPFR_INCLUDE_DIRS}) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack)
2. 改用目标级别的依赖配置,替代全局污染
全局include_directories会影响所有目标,CMake推荐用target_include_directories和target_link_libraries配合PUBLIC/PRIVATE/INTERFACE控制依赖传递:
修改src/CMakeLists.txt:
file(GLOB HEADER_LIST CONFIGURE_DEPENDS "${MyProject_SOURCE_DIR}/include/*.h") add_library(myLib SomeFile.cpp ${HEADER_LIST}) # 配置头文件路径,PUBLIC确保依赖myLib的目标能继承Boost/MPFR的头文件 target_include_directories(myLib PUBLIC ../include ${Boost_INCLUDE_DIRS} ${MPFR_INCLUDE_DIRS} ) # 链接依赖,PUBLIC确保依赖myLib的目标能自动链接Boost/MPFR target_link_libraries(myLib PUBLIC ${Boost_LIBRARIES} ${MPFR_LIBRARIES} )
修改app/CMakeLists.txt:
由于myLib已通过PUBLIC传递了所有依赖,这里只需链接myLib即可:
add_executable(main main.cpp) target_link_libraries(main PRIVATE myLib)
3. 额外检查:确认MPFR的CMake模块有效性
如果cmake目录下的FindMPFR.cmake脚本存在问题,可能导致${MPFR_LIBRARIES}未指向正确的库文件。可以:
- 在根CMakeLists中添加
message(STATUS "MPFR Libraries: ${MPFR_LIBRARIES}"),查看输出是否为实际的MPFR库路径(如/usr/lib/libmpfr.so)。 - 如果输出异常,改用
pkg_check_modules查找MPFR:
find_package(PkgConfig REQUIRED) pkg_check_modules(MPFR REQUIRED mpfr)
总结
核心问题是依赖查找顺序颠倒导致子目录无法获取有效库变量,同时依赖配置不够规范。调整顺序并改用目标级别的依赖传递后,链接错误即可解决。
内容的提问来源于stack exchange,提问作者Kotaka Danski

