如何无需静态库全路径构建静态可执行文件?解决target_link_directories异常
构建静态可执行文件时CMake链接动态库的解决方法
问题背景
我用CMake构建静态可执行文件,原CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 3.25) project(tmp2) set(CMAKE_CXX_STANDARD 20) set(BUILD_SHARED_LIBS OFF) set(CMAKE_EXE_LINKER_FLAGS "-static") set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") add_executable(tmp2 main.cpp) set(GCC_CXX_FLAGS ${GCC_CXX_FLAGS} "-static-libgcc -static-libstdc++") target_link_libraries(${PROJECT_NAME} PUBLIC /usr/lib/x86_64-linux-gnu/libboost_chrono.a PUBLIC /usr/lib/x86_64-linux-gnu/libboost_date_time.a PUBLIC /usr/lib/x86_64-linux-gnu/libboost_filesystem.a PUBLIC /usr/lib/x86_64-linux-gnu/libboost_thread.a PUBLIC /usr/lib/x86_64-linux-gnu/libboost_atomic.a ) target_include_directories(${PROJECT_NAME} PUBLIC /usr/local/include PUBLIC /usr/include/ PUBLIC /usr/include/opencv4 )
因为target_link_libraries里写全路径太繁琐,我添加了target_link_directories来省略静态库全路径:
target_link_directories(${PROJECT_NAME} PUBLIC /usr/lib/x86_64-linux-gnu/ PUBLIC /usr/local/lib/ )
但添加后CMake尝试链接动态库,报错如下:
/usr/bin/ld: attempted static link of dynamic object `/usr/lib/gcc/x86_64-linux-gnu/13/libstdc++.so' /usr/bin/ld: attempted static link of dynamic object `/lib/x86_64-linux-gnu/libm.so.6' /usr/bin/ld: attempted static link of dynamic object `/lib/x86_64-linux-gnu/libmvec.so.1' /usr/bin/ld: attempted static link of dynamic object `/lib/x86_64-linux-gnu/libc.so.6' /usr/bin/ld: attempted static link of dynamic object `/lib64/ld-linux-x86-64.so.2' collect2: error: ld returned 1 exit status
请问如何无需指定静态库全路径,成功构建静态可执行文件?
解决方案
1. 调整链接器选项的设置方式
把全局的CMAKE_EXE_LINKER_FLAGS替换为目标专属的链接选项,避免全局设置干扰其他目标:
# 替换原有的set(CMAKE_EXE_LINKER_FLAGS "-static") target_link_options(${PROJECT_NAME} PRIVATE "-static")
同时确保CMAKE_FIND_LIBRARY_SUFFIXES的设置顺序正确,放在project之后、add_executable之前,保证CMake查找库时优先选择静态库。
2. 使用find_library定位静态库
用find_library逐个查找Boost静态库,既避免全路径,又能强制限定查找.a文件:
# 查找Boost静态库,指定路径并禁用默认查找路径 find_library(BOOST_CHRONO_LIB NAMES boost_chrono PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_DATE_TIME_LIB NAMES boost_date_time PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_FILESYSTEM_LIB NAMES boost_filesystem PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_THREAD_LIB NAMES boost_thread PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_ATOMIC_LIB NAMES boost_atomic PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) # 链接找到的静态库 target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_CHRONO_LIB} PUBLIC ${BOOST_DATE_TIME_LIB} PUBLIC ${BOOST_FILESYSTEM_LIB} PUBLIC ${BOOST_THREAD_LIB} PUBLIC ${BOOST_ATOMIC_LIB} )
NO_DEFAULT_PATH参数确保CMake只在指定路径查找,不会误找到动态库版本。
3. 优化编译选项设置
原有的GCC_CXX_FLAGS写法存在覆盖风险,改用目标专属的编译选项:
target_compile_options(${PROJECT_NAME} PRIVATE "-static-libgcc" "-static-libstdc++")
这些选项本质是链接时生效,也可以合并到target_link_options中。
4. 移除冗余的target_link_directories
如果已经通过find_library指定了库路径,target_link_directories可以直接移除,避免CMake在查找库时混淆静态和动态版本。如果必须保留,要确保CMAKE_FIND_LIBRARY_SUFFIXES的设置优先生效。
完整修改后的CMakeLists.txt
cmake_minimum_required(VERSION 3.25) project(tmp2) set(CMAKE_CXX_STANDARD 20) set(BUILD_SHARED_LIBS OFF) # 优先查找静态库 set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") add_executable(tmp2 main.cpp) # 设置目标专属的链接与编译选项 target_link_options(${PROJECT_NAME} PRIVATE "-static") target_compile_options(${PROJECT_NAME} PRIVATE "-static-libgcc" "-static-libstdc++") # 查找Boost静态库 find_library(BOOST_CHRONO_LIB NAMES boost_chrono PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_DATE_TIME_LIB NAMES boost_date_time PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_FILESYSTEM_LIB NAMES boost_filesystem PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_THREAD_LIB NAMES boost_thread PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) find_library(BOOST_ATOMIC_LIB NAMES boost_atomic PATHS /usr/lib/x86_64-linux-gnu/ NO_DEFAULT_PATH) # 链接库 target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_CHRONO_LIB} PUBLIC ${BOOST_DATE_TIME_LIB} PUBLIC ${BOOST_FILESYSTEM_LIB} PUBLIC ${BOOST_THREAD_LIB} PUBLIC ${BOOST_ATOMIC_LIB} ) target_include_directories(${PROJECT_NAME} PUBLIC /usr/local/include PUBLIC /usr/include/ PUBLIC /usr/include/opencv4 )
内容的提问来源于stack exchange,提问作者user22343737
相关产品推荐
相关产品推荐

