58

我正在编写一个 C++ 库(仅标头)并使用 CMake 生成我的(Visual Studio)项目和解决方案文件。我还在编写一个测试套件,它是同一个 CMake 项目的一部分。

当我在代表我的仅标头库的目标上调用 target_include_directories() 时会出现我的问题,以便我的库的使用者可以找到它的头文件。我收到以下错误消息(即使生成未中止)。

CMake Error in CMakeLists.txt:
  Target "Fonts" INTERFACE_INCLUDE_DIRECTORIES property contains path:

    "D:/Projects/GPC/fonts/include"

  which is prefixed in the source directory.

(D:/Projects/GPC/Fonts 是我的库项目的顶级目录。顺便说一句,如果我将头文件移动到顶级目录,问题仍然存在。)

我的 CMakeLists.txt 中的违规行是这样的(为简单起见而改编):

target_include_directories(Fonts INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")

我不明白我做错了什么。如果没有 target_include_directories(),消费者项目的代码根本无法包含我的头文件(除非以安装形式,但我还没有做到这一点,无论如何我希望能够从它的构建树中使用我的库,无需安装。)

我觉得我在这里缺少一些基本的东西;但是我已经搜索了几个小时而没有找到解决方案或解释。

4

1 回答 1

100

问题的根源不是target_include_directories命令本身,而是尝试install在源路径中具有公共或接口包含目录的目标(即包含目录是您的 ${PROJECT_SOURCE_DIR} 的子目录。)

虽然在从头开始构建库时使用绝对路径是非常好的和可取的,但是引入该库的预构建版本的第三方库可能希望使用不同的包含路径。毕竟,您不希望所有用户都镜像构建机器的目录结构,只是为了最终进入正确的包含路径。

CMake 的打包机制为这两个用例提供了支持:您可以直接从构建树中拉入库(即,检查源代码,构建它并指向find_package()目录),或者从安装目录(运行make INSTALL到将构建的东西复制到安装目录并指向find_package()目录)。后一种方法需要可重定位(也就是说,我在我的机器上构建和安装,将结果目录发送给您,您将能够在您的机器上从不同的目录结构使用它),而前者不是。

这是一个非常简洁的功能,但是在设置包含目录时必须考虑到它。引用手册target_include_directories

包含目录的使用要求通常在构建树和安装树之间有所不同。BUILD_INTERFACEINSTALL_INTERFACE生成器表达式可用于根据使用位置描述单独的使用要求。表达式中允许使用相对路径,INSTALL_INTERFACE并且相对于安装前缀进行解释。例如:

target_include_directories(mylib PUBLIC  
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>  
    $<INSTALL_INTERFACE:include/mylib>  # <prefix>/include/mylib
)

和生成BUILD_INTERFACEINSTALL_INTERFACE表达式做了所有的魔法:

$<INSTALL_INTERFACE:...>

...使用 导出属性时的内容,install(EXPORT)否则为空。

$<BUILD_INTERFACE:...>

...使用 导出属性export()或目标被同一构建系统中的另一个目标使用时的内容。否则扩展为空字符串。

于 2014-09-05T08:00:54.440 回答