CMake中按名称链接可执行文件到库时出现链接错误的原因
问题原因分析
你遇到的链接错误核心原因是:cpp_version_test是OBJECT类型的库,CMake对这类库的处理逻辑和常规静态/共享库完全不同:
- OBJECT库不会生成单独的归档(
.a)或共享(.so/.dll)库文件,仅会编译出目标文件(.o) - 当你在
target_link_libraries中直接引用OBJECT库名时,CMake会错误地尝试用-lcpp-version-test的方式去查找不存在的库文件,这就是链接器报错的根本原因
解决方法
提供三种可行修复方案,可根据项目需求选择:
方案1:将OBJECT库改为STATIC或SHARED库(最直观)
如果不需要单独保留目标文件,直接将库类型改为静态库即可,修改cpp-version-test/CMakeLists.txt:
if(CMAKE_CXX_STANDARD GREATER_EQUAL 20) message("C++20 choosen, building test-cpp20") add_library(cpp_version_test STATIC test-cpp20.cpp) else() message("C++20 not choosen, building test-cpp17") add_library(cpp_version_test STATIC test-cpp17.cpp) endif() target_include_directories(cpp_version_test INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
修改后CMake会生成标准静态库文件,链接阶段就能正常找到。
方案2:用生成器表达式引用OBJECT库的目标文件(CMake 3.12+)
若需保留OBJECT库的形式,可在顶层CMakeLists.txt的target_link_libraries中用生成器表达式直接引用目标文件:
add_subdirectory(cpp-version-test) add_executable(Template main.cpp) # 用$<TARGET_OBJECTS:cpp_version_test>替代直接引用库名 target_link_libraries(Template PUBLIC $<TARGET_OBJECTS:cpp_version_test> compiler_flags) target_include_directories(Template PUBLIC "${PROJECT_BINARY_DIR}" )
这种方式会直接将OBJECT库生成的.o文件传递给链接器,无需查找独立库文件。
方案3:将OBJECT库目标文件直接加入可执行文件
也可以在创建可执行文件时,直接把OBJECT库的目标文件作为源文件包含:
add_subdirectory(cpp-version-test) # 直接将OBJECT库的目标文件添加到可执行文件的源列表中 add_executable(Template main.cpp $<TARGET_OBJECTS:cpp_version_test>) target_link_libraries(Template PUBLIC compiler_flags) target_include_directories(Template PUBLIC "${PROJECT_BINARY_DIR}" )
额外提示
- OBJECT库适合需要复用目标文件但不想生成独立库的场景,否则优先使用STATIC/SHARED库更易维护
- 方案2和3要求CMake版本在3.12及以上
内容的提问来源于stack exchange,提问作者kvrier
相关产品推荐
相关产品推荐

