PAYATHON 2026

CMake find_package 后为何无法包含已安装的头文件?

数据阿明

结论

find_package(libproj) 会查找并加载包配置,但不会自动扫描安装目录来推断头文件路径。消费者需要通过 target_link_libraries 链接导出的导入目标,才能继承该目标导出的 INTERFACE_INCLUDE_DIRECTORIES。

这里头文件的安装位置与导出的包含目录不一致:头文件安装在 /usr/local/include/libproj-proj-lib/gen/src/def.hpp,安装接口却只声明了 ${CMAKE_INSTALL_INCLUDEDIR}。即使将包含目录设为 /usr/local/include,#include "def.hpp" 也不会递归搜索子目录。

对齐安装路径和导出路径

如果要继续使用 #include "def.hpp",需要将 gen/src 安装后的实际目录加入目标的安装接口。inc 目录中的头文件也可以用同样的方式导出:

target_include_directories(
  ${TARGET_NAME} PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/gen/src>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-${TARGET_ALIAS_NAME}/inc>
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}-${TARGET_ALIAS_NAME}/gen/src>
)

现有安装规则会保留 gen 和 inc 目录结构,因此安装后的 def.hpp 路径应为:

${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/libproj-proj-lib/gen/src/def.hpp

安装后,导出的目标会将 gen/src 加入头文件搜索路径,消费者便可以这样写:

#include "def.hpp"

也可以保留较宽的安装接口目录,并在代码中使用完整的相对路径:

#include <libproj-proj-lib/gen/src/def.hpp>

这种情况下,${CMAKE_INSTALL_INCLUDEDIR} 必须确实是编译器的搜索路径。选定布局后,确保安装位置、导出的包含目录和 #include 路径相互对应。

确认包配置文件导入了导出目标

find_package 找到包配置文件,并不代表导入目标已经加载。题目没有提供 cmake/libproj_config.cmake.in 的内容,请确认其中包含导出的 targets 文件,例如:

@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/libproj_targets.cmake")

生成并安装的配置文件名称也要与 find_package(libproj REQUIRED) 对应。配置文件加载后,消费者才能使用 libproj::proj-lib,并继承它的头文件目录等用法要求。

检查消费者目标名称

消费者配置中还有一处目标名称不一致:代码通过 set(TARGET_NAME proj_bin) 设置了目标名,却用 add_executable(${PROJECT_NAME} ${SRC}) 创建名为 binproj 的目标。后续操作引用的是 ${TARGET_NAME},也就是 proj_bin。可以统一使用 ${TARGET_NAME}:

add_executable(${TARGET_NAME} ${SRC})

target_include_directories(${TARGET_NAME} PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
)

target_link_libraries(${TARGET_NAME} PRIVATE
  libproj::proj-lib
)

如果目标名不一致,CMake 在为不存在的目标调用 target_include_directories 或 target_link_libraries 时会报错。这个问题需要与头文件搜索路径问题分开检查。

修正后,重新安装 libproj,再配置 binproj。检查安装后的头文件位置、libproj_targets.cmake 中导入目标的包含目录,以及 #include 使用的相对路径是否一致。

备注:内容仅供参考。