CMake子项目add_library中第三方库头文件引用失败问题
CMake子项目头文件找不到,主项目正常的问题解决
环境
VSCode + GCC 8.1.0 x86_64-w64-mingw32,依赖libmodbus和paho-mqtt
项目结构
project |──ext | |──mqtt | | MQTTClient.h | | paho-mqtt3a.lib | | paho-mqtt3a.dll | | etc... | |──libmodbus | | modbus.h | | modbus.lib | | modbus.dll | | etc... |──model | |──model_mqtt | | CMakeLists.txt | | model_mqtt.cpp | | model_mqtt.h |──CMakeLists.txt |──main.cpp |──main.h
问题现象
主项目main.cpp包含modbus.h和MQTTClient.h编译正常,但子项目model_mqtt.cpp包含相同头文件时,报错:cannot open source file "MQTTClient.h"C/C++(1696)
代码与配置
主项目代码(main.cpp)
#include "modbus.h" #include "MQTTClient.h" int main(int argc, char *argv[]){ return 0; }
根目录CMakeLists.txt
cmake_minimum_required(VERSION 3.5.0) project(Project_Testbed VERSION 0.1.0 LANGUAGES C CXX) add_executable(${PROJECT_NAME} main.cpp) include_directories(ext/libmodbus) target_link_directories(${PROJECT_NAME} PUBLIC ext/libmodbus) target_link_libraries(${PROJECT_NAME} PUBLIC modbus) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ext/libmodbus/modbus.dll $<TARGET_FILE_DIR:${PROJECT_NAME}>) add_subdirectory(model/model_mqtt) include_directories(model/model_mqtt) target_link_libraries(${PROJECT_NAME} PUBLIC model_mqtt) include_directories(ext/mqtt) target_link_directories(${PROJECT_NAME} PUBLIC ext/mqtt) target_link_libraries(${PROJECT_NAME} PUBLIC paho-mqtt3a) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ext/mqtt/paho-mqtt3a.dll $<TARGET_FILE_DIR:${PROJECT_NAME}>)
子项目代码(model_mqtt.cpp)
#include "modbus.h" #include "MQTTClient.h" int test(int argc, char *argv[]){ return 0; }
子项目CMakeLists.txt
project(model_mqtt) set(mqtt_files model_mqtt.cpp model_mqtt.h ) add_library(model_mqtt ${mqtt_files}) target_link_libraries(${PROJECT_NAME} PUBLIC modbus) target_link_libraries(${PROJECT_NAME} PUBLIC paho-mqtt3a)
原因
- include_directories执行顺序错误:根目录里
include_directories(ext/mqtt)是在add_subdirectory(model/model_mqtt)之后执行的,这条路径设置无法作用到子项目的库上,子项目编译时自然找不到MQTTClient.h。 - 子项目未配置头文件路径:子项目的CMakeLists中完全没有添加
ext/libmodbus和ext/mqtt的头文件包含路径,依赖根目录全局设置的可靠性低。 - 全局配置的局限性:
include_directories是全局生效,但CMake子项目目标不会自动继承后续的全局路径,且这种全局方式不够模块化,项目规模变大后容易引发路径冲突。
解决方法
方法一:目标级配置(推荐)
这种方式符合CMake模块化设计,每个目标独立管理依赖,关系清晰。
修改根目录CMakeLists.txt
将全局include_directories替换为target_include_directories,调整顺序确保子项目能获取依赖:
cmake_minimum_required(VERSION 3.5.0) project(Project_Testbed VERSION 0.1.0 LANGUAGES C CXX) add_executable(${PROJECT_NAME} main.cpp) # 配置libmodbus的头文件与链接 target_include_directories(${PROJECT_NAME} PUBLIC ext/libmodbus) target_link_directories(${PROJECT_NAME} PUBLIC ext/libmodbus) target_link_libraries(${PROJECT_NAME} PUBLIC modbus) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ext/libmodbus/modbus.dll $<TARGET_FILE_DIR:${PROJECT_NAME}>) # 配置paho-mqtt的头文件与链接 target_include_directories(${PROJECT_NAME} PUBLIC ext/mqtt) target_link_directories(${PROJECT_NAME} PUBLIC ext/mqtt) target_link_libraries(${PROJECT_NAME} PUBLIC paho-mqtt3a) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ext/mqtt/paho-mqtt3a.dll $<TARGET_FILE_DIR:${PROJECT_NAME}>) # 添加子目录 add_subdirectory(model/model_mqtt) include_directories(model/model_mqtt) target_link_libraries(${PROJECT_NAME} PUBLIC model_mqtt)
修改子项目CMakeLists.txt
给子项目添加自身需要的头文件路径:
project(model_mqtt) set(mqtt_files model_mqtt.cpp model_mqtt.h ) add_library(model_mqtt ${mqtt_files}) # 添加依赖库的头文件路径 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../ext/libmodbus ${CMAKE_CURRENT_SOURCE_DIR}/../../ext/mqtt ) target_link_libraries(${PROJECT_NAME} PUBLIC modbus paho-mqtt3a)
方法二:调整全局include_directories顺序
若不想大幅修改配置,可将根目录的全局包含目录移至add_subdirectory之前,让子项目继承这些路径:
cmake_minimum_required(VERSION 3.5.0) project(Project_Testbed VERSION 0.1.0 LANGUAGES C CXX) # 先设置所有需要的全局包含目录 include_directories(ext/libmodbus ext/mqtt model/model_mqtt) add_executable(${PROJECT_NAME} main.cpp) target_link_directories(${PROJECT_NAME} PUBLIC ext/libmodbus) target_link_libraries(${PROJECT_NAME} PUBLIC modbus) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ext/libmodbus/modbus.dll $<TARGET_FILE_DIR:${PROJECT_NAME}>) # 添加子目录,子项目会继承前面的全局路径 add_subdirectory(model/model_mqtt) target_link_libraries(${PROJECT_NAME} PUBLIC model_mqtt) target_link_directories(${PROJECT_NAME} PUBLIC ext/mqtt) target_link_libraries(${PROJECT_NAME} PUBLIC paho-mqtt3a) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/ext/mqtt/paho-mqtt3a.dll $<TARGET_FILE_DIR:${PROJECT_NAME}>)
这种方法适合小型项目,优点是改动小,但灵活性和模块化程度较低。
总结
- 优先使用
target_include_directories替代include_directories,PUBLIC修饰符可让依赖该目标的其他项目自动继承头文件路径,模块化更强。 - 子项目的CMakeLists应自行配置所需的依赖路径,避免完全依赖根目录的全局设置。
内容的提问来源于stack exchange,提问作者Brown 22307713
相关产品推荐
相关产品推荐

