Cmake:target_compile_definitions 和 find_package

Cmake: target_compile_definitions with find_package

我有一个包 libtorch,它依赖于为某些功能使用关键字 slots 的库(例如在 Aten 中)。同时,我正在使用的项目是基于Qt的,它使用 slots 作为特殊关键字(宏),然后干扰 torchlib.

避免此类干扰的解决方法是在导入与Qt冲突的外部库时添加QT_NO_KEYWORDS定义:

然后它只能在依赖于 libtorch 的代码上完成,而不是其余的代码,所以我尝试了几种添加它的方法,比如 and Add target properties to an existing imported library in CMake,但我无法得到它可以工作。

target_compile_definitions 在 cmake 3.11 之后似乎可以在“IMPORTED 目标”(在 cmake 术语上)上使用。

那么为什么下面的 cmakelist 提取不起作用? (在那种情况下,正常的 QT 插槽代码无法正确识别为宏):

find_package (Torch REQUIRED PATHS ${Torch_DIR})
add_executable( ${PROJECT_NAME} ${header_files} ${source_files} ${hpp_files} ${moc_list} ${generated_ui_files} ${generated_qrc_files} )
target_link_libraries(${PROJECT_NAME} ${Qt_LINK_LIBRARIES})
#add_definitions(-DQT_NO_KEYWORDS)
target_link_libraries(${PROJECT_NAME} ${TORCH_LIBRARIES})
#remove_definitions(-DQT_NO_KEYWORDS)
target_compile_definitions(torch INTERFACE QT_NO_KEYWORDS)

可能的解决方案

选项 1:

使用 QT_NO_KEYWORDS 并用等效的大写宏替换 slots 和其他关键字,例如Q_SLOTS.

选项 2:

不要使用 QT_NO_KEYWORDS 并将 C++ 代码的各个部分用冲突的关键字包装起来,如下所示:

#undef slots
#include <torch/torch.h>
#define slots Q_SLOTS

解释

target_compile_definitions() 中的 INTERFACE 关键字告诉 CMake 所有依赖于 torch 库的目标也需要定义 QT_NO_KEYWORDS 宏。这就是为什么您的可执行文件的所有源代码都将使用 -DAT_NO_KEYWORDS 进行编译并且不会定义 slots 关键字。

我想你试图用注释掉的 add_definitions()/remove_definitions() 调用来解决你的问题。这些无法按预期工作的几个原因:

  • 它们只影响编译而不影响链接。将它们放在 target_link_libraries() 周围没有任何效果。
  • 它们操纵在当前范围(当前 CMakeLists.txt)中创建的所有目标的编译标志,无论它们是在调用命令之前还是之后创建的,请参阅 docs。这意味着使用相同的参数调用 add_definitions() 和随后的 remove_definitions() 将导致根本不添加任何标志,无论您在 CMakeLists.txt 中的哪个点调用它们。

您还应注意,在目录级别 (add_*/remove_*) 上运行的命令被认为是“旧式”CMake。 Modern CMake 旨在仅在目标级别上操作(target_* 命令)。更多“现代 CMake”建议:

  • 使用 target_sources() 而不是 header_filessource_files 等变量来将源添加到您的目标。
  • 始终将 target_link_libraries()PRIVATEPUBLICINTERFACE 关键字一起使用。 Craig Scotts Professional CMake 书中的摘录:

    The target_link_libraries() command also has a few other forms, some of which have been part of CMake from well before version 2.8.11. [...] Their use is generally discouraged for new projects. The full form shown previously with PRIVATE, PUBLIC and INTERFACE sections should be preferred, as it expresses the nature of dependencies with more accuracy. [...] The above form [(without PRIVATE/PUBLIC/INTERFACE)] is generally equivalent to the items being defined as PUBLIC, but in certain situations, they may instead be treated as PRIVATE. In particular, if a project defines a chain of library dependencies with a mix of both old and new forms of the command, the old-style form will generally be treated as PRIVATE.