CMake交叉编译时头文件找不到问题求助
CMake交叉编译头文件查找问题排查
原项目结构
- myproject/ |- toolchain.cmake |- tmproot/ |- app/ |- myapp/ |- CMakeLists.txt |- lib/ |- mylib1/ |- CMakeLists.txt |- mylib2/ |- CMakeLists.txt |- mylib3/ |- CMakeLists.txt |- spdlog/ |- CMakeLists.txt |- json/ |- CMakeLists.txt
工具链配置(toolchain.cmake)
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) SET(CMAKE_FIND_ROOT_PATH <path to myproject>/tmproot) set(CMAKE_C_COMPILER $ENV{XILINX_VITIS}/gnu/aarch64/lin/aarch64-linux/bin/aarch64-linux-gnu-gcc) set(CMAKE_CXX_COMPILER $ENV{XILINX_VITIS}/gnu/aarch64/lin/aarch64-linux/bin/aarch64-linux-gnu-g++) set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
编译安装流程
编译并安装所有库的命令:
/usr/bin/cmake $PWD -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="../../toolchain.cmake" make DESTDIR="$PWD/../../tmproot" install
安装后,库文件位于<path to myproject>/tmproot/usr/local/lib,头文件位于<path to myproject>/tmproot/usr/local/include/<lib_name>。编译库时编译器自动添加-isystem <path to myproject>/tmproot/usr/local/include参数,可正常找到头文件,但编译依赖这些库的应用时无该参数,报头文件缺失。
最小复现示例
项目结构
- myproject/ |- toolchain.cmake |- tmproot/ |- app/ |- app1/ |- CMakeLists.txt |- app1.cpp |- lib/ |- lib1/ |- CMakeLists.txt |- lib1.cpp |- lib1.h |- lib2/ |- CMakeLists.txt |- lib2.cpp |- lib2.h
lib1相关文件
CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(lib1 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_STATIC_LIBRARY_PREFIX "") add_library (lib1 lib1.cpp lib1.h) install(FILES lib1.h DESTINATION include/lib1 COMPONENT Development) install (TARGETS lib1 RUNTIME DESTINATION ${BINDIR} COMPONENT Applications LIBRARY DESTINATION ${LIBDIR} COMPONENT Libraries )
lib1.h
#ifndef LIB1_H #define LIB1_H int lib1_func(int param); #endif
lib1.cpp
int lib1_func(int param) { return param+42; }
lib2相关文件
CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(lib2 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_STATIC_LIBRARY_PREFIX "") add_library (lib2 lib2.cpp lib2.h) target_link_libraries (lib2 PUBLIC lib1) install(FILES lib2.h DESTINATION include/lib2 COMPONENT Development) install (TARGETS lib2 RUNTIME DESTINATION ${BINDIR} COMPONENT Applications LIBRARY DESTINATION ${LIBDIR} COMPONENT Libraries )
lib2.h
#ifndef LIB2_H #define LIB2_H int lib2_func(int param); #endif
lib2.cpp
#include "lib1/lib1.h" int lib2_func(int param) { return param+lib1_func(param); }
app1相关文件
CMakeLists.txt
cmake_minimum_required(VERSION 3.5) project(app1 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) add_executable (app1 "app1.cpp") target_link_libraries(app1 PUBLIC lib1 PUBLIC lib2)
app1.cpp
#include "lib1/lib1.h" #include "lib2/lib2.h" int main() { return lib1_func(1) + lib2_func(2); }
复现步骤及报错
cd lib/lib1 /usr/bin/cmake $PWD -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="../../toolchain.cmake" make DESTDIR="$PWD/../../tmproot" install cd ../lib2 /usr/bin/cmake $PWD -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="../../toolchain.cmake" make
报错信息:
fatal error: lib1/lib1.h: No such file or directory 1 | #include "lib1/lib1.h" | ^~~~~~~~~~~~~
确认头文件已存在:
ls ../../tmproot/usr/local/include/lib1/ lib1.h
问题原因分析
- CMake未自动识别安装的lib1:编译lib2时,CMake不知道lib1已安装在
tmproot中,仅用target_link_libraries链接静态库无法自动传递头文件路径,必须通过包查找机制导入依赖的完整配置。 - lib1未导出CMake配置文件:安装lib1时未生成
lib1Config.cmake等配置文件,导致后续项目无法通过CMake的包查找功能定位到lib1的头文件和库路径。 - 包查找路径未明确:虽然
CMAKE_FIND_ROOT_PATH指向了tmproot,但CMake默认不会自动遍历其子目录查找配置文件,需要显式指定包的查找路径或配置CMAKE_PREFIX_PATH。
解决方案
步骤1:修改lib1的CMakeLists.txt,添加配置导出
更新lib1的CMakeLists.txt,让CMake生成并导出配置文件,方便后续项目导入:
cmake_minimum_required(VERSION 3.5) project(lib1 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_STATIC_LIBRARY_PREFIX "") add_library (lib1 lib1.cpp lib1.h) # 设置头文件路径,让依赖项自动继承 target_include_directories(lib1 PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<INSTALL_INTERFACE:include/lib1> ) # 导出目标和配置文件 install(TARGETS lib1 EXPORT lib1Targets RUNTIME DESTINATION bin COMPONENT Applications LIBRARY DESTINATION lib COMPONENT Libraries ARCHIVE DESTINATION lib COMPONENT Libraries ) install(EXPORT lib1Targets FILE lib1Targets.cmake NAMESPACE lib1:: DESTINATION lib/cmake/lib1 ) install(FILES lib1.h DESTINATION include/lib1 COMPONENT Development) # 生成Config.cmake文件 include(CMakePackageConfigHelpers) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/lib1Config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/lib1Config.cmake" INSTALL_DESTINATION lib/cmake/lib1 ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/lib1Config.cmake" DESTINATION lib/cmake/lib1 )
同时在lib1目录下创建lib1Config.cmake.in文件(内容为空即可):
# 空配置模板文件
步骤2:修改lib2的CMakeLists.txt,用find_package导入lib1
更新lib2的CMakeLists.txt,通过find_package查找并导入lib1的配置:
cmake_minimum_required(VERSION 3.5) project(lib2 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_STATIC_LIBRARY_PREFIX "") # 查找lib1,指定配置文件路径 find_package(lib1 REQUIRED PATHS ${CMAKE_FIND_ROOT_PATH}/usr/local/lib/cmake/lib1) add_library (lib2 lib2.cpp lib2.h) # 链接lib1的导入目标 target_link_libraries (lib2 PUBLIC lib1::lib1) # 设置lib2的头文件路径 target_include_directories(lib2 PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<INSTALL_INTERFACE:include/lib2> ) install(FILES lib2.h DESTINATION include/lib2 COMPONENT Development) install (TARGETS lib2 EXPORT lib2Targets RUNTIME DESTINATION bin COMPONENT Applications LIBRARY DESTINATION lib COMPONENT Libraries ARCHIVE DESTINATION lib COMPONENT Libraries )
步骤3:修改app1的CMakeLists.txt,用find_package导入依赖
更新app1的CMakeLists.txt:
cmake_minimum_required(VERSION 3.5) project(app1 LANGUAGES CXX C) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # 查找依赖库 find_package(lib1 REQUIRED PATHS ${CMAKE_FIND_ROOT_PATH}/usr/local/lib/cmake/lib1) find_package(lib2 REQUIRED PATHS ${CMAKE_FIND_ROOT_PATH}/usr/local/lib/cmake/lib2) add_executable (app1 "app1.cpp") # 链接导入目标 target_link_libraries(app1 PUBLIC lib1::lib1 lib2::lib2)
步骤4:重新执行编译安装流程
- 重新编译安装lib1:
cd lib/lib1 rm -rf build && mkdir build && cd build cmake .. -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="../../toolchain.cmake" make DESTDIR="../../../tmproot" install
- 编译安装lib2:
cd ../../lib2 rm -rf build && mkdir build && cd build cmake .. -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="../../toolchain.cmake" make DESTDIR="../../../tmproot" install
- 编译app1:
cd ../../app/app1 rm -rf build && mkdir build && cd build cmake .. -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="../../toolchain.cmake" make
临时快速解决方案
如果不想修改CMake配置导出,可以在lib2和app1的CMakeLists.txt中手动添加包含路径:
# 在lib2的CMakeLists.txt中添加 target_include_directories(lib2 PUBLIC ${CMAKE_FIND_ROOT_PATH}/usr/local/include) # 在app1的CMakeLists.txt中添加 target_include_directories(app1 PUBLIC ${CMAKE_FIND_ROOT_PATH}/usr/local/include)
该方式仅适用于临时测试,推荐使用CMake的包导出机制保证依赖管理的规范性。
内容的提问来源于stack exchange,提问作者Philip Kirchhoff
相关产品推荐
相关产品推荐

