CMake子项目构建共享库遇头文件错误,如何正确配置部署?
主项目中子项目共享库构建问题解决
问题场景
现有主项目已配置好CMakeLists.txt且构建正常,需在其子项目sub_project中基于自身include目录下的interface.h创建C++共享库,供主项目链接调用。执行构建时出现头文件找不到的错误,同时对共享库的头文件组织、源文件必要性存在疑问。
项目目录结构
main_project ├── build ├── include ├── src ├── sub_project (the shared library code) │ ├── build │ ├── include │ │ ├── interface.h │ ├── src │ │ ├── interface.cpp └── CMakeLists.txt
现有代码
interface.h
#include <iostream> void zzz() { std::cout << "zzz() called" << std::endl; }
interface.cpp
#include <include/interface.h>
子项目CMakeLists.txt
cmake_minimum_required(VERSION 3.17.2) project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") add_library(mylib SHARED src/interface.cpp) set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION}) set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/interface.h) target_include_directories(mylib PRIVATE include) target_include_directories(mylib PRIVATE src) include(GNUInstallDirs) install(TARGETS mylib LIBRARY DESTINATION parent/build PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
报错信息
执行cmake ..和make时出现:
fatal error: include/interface.h: No such file or directory
解决方案
1. 修复头文件引用错误
interface.cpp中的头文件路径错误,因为已经将include目录添加到包含路径,直接引用文件名即可:
#include "interface.h"
2. 修正CMakeLists.txt的目录与配置
核心调整点:
- 公共头文件目录需用
PUBLIC而非PRIVATE,确保主项目链接库时能自动获取头文件路径 - 取消不必要的
src目录包含(当前src下无需要被包含的头文件) - 针对"仅供主项目使用"的场景,优先通过
add_subdirectory集成,而非install(更简洁高效)
修改后的子项目CMakeLists.txt:
cmake_minimum_required(VERSION 3.17.2) project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") add_library(mylib SHARED src/interface.cpp) # 合并设置目标属性 set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION} PUBLIC_HEADER include/interface.h ) # 公共头文件目录设为PUBLIC,让依赖目标继承 target_include_directories(mylib PUBLIC include) # 若坚持安装到主项目build目录,修正路径(不推荐,优先用add_subdirectory) # include(GNUInstallDirs) # install(TARGETS mylib # LIBRARY DESTINATION ${CMAKE_SOURCE_DIR}/../build/lib # PUBLIC_HEADER DESTINATION ${CMAKE_SOURCE_DIR}/../build/include # )
3. 主项目集成子项目库
在主项目的CMakeLists.txt中添加以下内容,直接集成子项目:
# 添加子项目目录 add_subdirectory(sub_project) # 链接子项目库到主项目目标(替换your_main_target为实际主项目目标名) target_link_libraries(your_main_target PRIVATE mylib)
4. 规范共享库的头文件与源文件结构
当前interface.h中直接写了函数定义,会导致主项目包含该头文件时出现多重定义错误。必须拆分声明与实现:
修改后的interface.h(仅声明):
#pragma once #include <iostream> void zzz();
修改后的interface.cpp(实现):
#include "interface.h" void zzz() { std::cout << "zzz() called" << std::endl; }
关于源文件的必要性
必须要有源文件。如果仅用头文件定义函数,当多个目标包含该头文件时,会生成多份函数定义,链接阶段触发多重定义错误;将实现放到源文件中,编译后只会生成一份二进制代码,符合共享库的设计逻辑。
内容的提问来源于stack exchange,提问作者intrigued_66
相关产品推荐
相关产品推荐

