如何指定同时适配本地编译与Yocto的CMake头文件包含路径?
我开发了一款读取Optris热像仪图像数据的C++应用,基于Optris Direct SDK(.deb包形式)实现设备通信,在Linux开发机上用CMake构建可正常运行——SDK将库文件安装至/usr/lib,头文件安装至/usr/include/libirimager。
但尝试将该应用构建到Nvidia Jetson板的Yocto镜像时,因CMakeLists.txt中使用了头文件的绝对路径,导致编译时无法找到头文件。
最小复现示例
main.cpp
#include "IRImager.h" int main() { return 0; }
CMakeLists.txt(本地正常,Yocto构建失败)
cmake_minimum_required(VERSION 3.14) project(libir-example) add_executable(libir-example main.cpp ) target_include_directories(libir-example PRIVATE /usr/include/libirimager ) target_link_libraries(libir-example PUBLIC irdirectsdk )
Yocto配方libir-example.bb
DESCRIPTION = "Example of trying to build for libir" LICENSE = "BSD" SRCREV = "0.1" PV = "0.1" SRC_URI = "file://main.cpp file://CMakeLists.txt" S = "${WORKDIR}" DEPENDS += "optris-directsdk" deltask do_populate_lic inherit cmake
编译报错
| /home/foo/build/tmp/work/armv8a-oe4t-linux/libir-example/0.1-r0/main.cpp:1:10: fatal error: IRImager.h: No such file or directory | 1 | #include "IRImager.h" | | ^~~~~~~~~~~~
已确认IRImager.h存在于recipe-sysroot的/usr/include/libirimager目录下,尝试过${CMAKE_SYSROOT}无效,用${CMAKE_BINARY_DIR}相关路径虽能工作,但写法不优雅且无法支持本地编译。
附optris-directsdk_8.8.5.bb配方:
SUMMARY = "Optris DirestSDK" DESCRIPTION = "SDK for talking to Optris thermal cameras" HOMEPAGE = "https://www.optris.co.uk/optris-pi-sdks" LICENSE = "CLOSED" inherit bin_package SRC_URI += " \ https://ftp.evocortex.org/libirimager-latest?arch=arm64&type=deb;subdir=optris-directsdk-8.8.5;downloadfilename=libirimager-8.8.5.deb \ " SRC_URI[sha256sum] = "97661cd4c258c1dde55938b7d18d7be5fa9a1480e0f0b0bb96268ad62089905f" # Force the .so files into the regular package (not the -dev one) FILES:${PN} += "/usr/lib/lib*.so" FILES:${PN}-dev = "" RDEPENDS:${PN} = "libudev libusb1" # Need this because the libraries in the SDK are already stripped, which # bitbake does not expect INSANE_SKIP:${PN} = "already-stripped" # Remove the parts of the SDK that we don't need (e.g. udev rules), otherwise # bitbake complains about things existing that are not installed. do_install:append() { rm -rf ${D}/lib rm -rf ${D}/usr/lib/libirextras.so }
要同时支持本地编译和Yocto构建,需要让CMake自动适配不同环境的头文件路径,推荐两种方案:
方案一:使用CMake的find_path自动查找头文件
修改CMakeLists.txt,用find_path定位IRImager.h的路径,无论是本地环境还是Yocto的sysroot环境,CMake都会自动搜索:
cmake_minimum_required(VERSION 3.14) project(libir-example) add_executable(libir-example main.cpp ) # 查找IRImager.h所在的目录,本地默认路径作为备选 find_path(LIBIRIMAGER_INCLUDE_DIR NAMES IRImager.h PATHS /usr/include/libirimager ) # 添加头文件目录 target_include_directories(libir-example PRIVATE ${LIBIRIMAGER_INCLUDE_DIR} ) target_link_libraries(libir-example PUBLIC irdirectsdk )
find_path会优先在Yocto构建时的sysroot路径中搜索,找不到再用指定的备选路径,完美兼容两种环境。
方案二:利用Yocto的pkg-config支持(需调整SDK配方)
如果SDK提供了.pc文件,CMake可以用pkg_check_modules直接获取头文件和库路径。但当前optris-directsdk配方没有处理开发文件,需要先修改配方:
调整optris-directsdk_8.8.5.bb
恢复-dev包的内容,确保头文件被正确打包:
# 移除原来的FILES:${PN}-dev = "",替换为: FILES:${PN}-dev += "/usr/include/libirimager/*" # 如果SDK有pkg-config文件,还要加上: # FILES:${PN}-dev += "/usr/lib/pkgconfig/*.pc"
然后修改CMakeLists.txt使用pkg_check_modules:
cmake_minimum_required(VERSION 3.14) project(libir-example) find_package(PkgConfig REQUIRED) pkg_check_modules(LIBIRIMAGER REQUIRED IMPORTED_TARGET irdirectsdk) add_executable(libir-example main.cpp ) target_link_libraries(libir-example PRIVATE PkgConfig::LIBIRIMAGER)
这种方式更符合CMake的标准实践,Yocto构建时会自动通过pkg-config获取正确的路径,本地编译也能正常工作(只要SDK的.pc文件在系统pkg-config搜索路径中)。
补充说明
方案一无需修改optris-directsdk配方,适合快速适配;方案二需要确保SDK的开发文件(头文件、.pc文件)被正确安装到-dev包中,Yocto构建时会自动依赖optris-directsdk-dev,从而将头文件路径加入构建环境。
内容的提问来源于stack exchange,提问作者pmacfarlane

