Emile D.
Emile D.

Reputation: 642

Cmake: target_compile_definitions with find_package

I have a package, libtorch, that depends on libraries that use the keyword slots for some function (e.g. in Aten). In the meantime, the project that I am using is based on Qt, which use slots as a special keyword (macro), which then interferes with torchlib.

The solution to avoid such interference is to add the QT_NO_KEYWORDS definition when importing the external library that enters in conflict with Qt: Turning the no_keyword (Qt option) ON in a cmake file to work with boost::signals

It has then to be done only on the code that depends on libtorch and not the rest, so I tried several ways to add it, like CMake Add and Remove a Macro definition to compile Shared Library/Executable and Add target properties to an existing imported library in CMake, but I can't get it to work.

target_compile_definitions seems to be available after cmake 3.11 on "IMPORTED targets"(on cmake terminology).

So why the following cmakelist extract doesn't work? (in that case, the normal QT slots code are not properly recognized as a macro):

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)

Upvotes: 1

Views: 1691

Answers (1)

petwu
petwu

Reputation: 281

Possible Solutions

Option 1:

Use QT_NO_KEYWORDS and replace slots and other keywords with their equivalent uppercase macros, e.g. Q_SLOTS.

Option 2:

Don't use QT_NO_KEYWORDS and wrap the parts of your C++ code with conflicting keywords like this:

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

Explanations

The INTERFACE keyword in target_compile_definitions() tells CMake that all targets that depend on the torch library need the QT_NO_KEYWORDS macro defined as well. This is why all sources of your executable will be compiled with -DAT_NO_KEYWORDS and the slots keyword will not be defined.

I suppose you tried to fix your problem with the commented out add_definitions()/remove_definitions() calls. Several reason why those don't work as expected:

  • They only affect compilation not linking. Putting them around target_link_libraries() has no effect.
  • They manipulate the compile flags of all targets created in the current scope (current CMakeLists.txt), no matter if they were created before or after the command gets invoked, see the docs. This means calling add_definitions() and subsequently remove_definitions() with the same arguments will result in no flags being added at all no matter at which point in your CMakeLists.txt you call them.

You should also note that commands operating on the directory level (add_*/remove_*) are considered "old style" CMake. Modern CMake aims to only operate on the target level (target_* commands). Some more "Modern CMake" suggestions:

  • Use target_sources() instead of variables like header_files, source_files, etc. to add sources to your targets.
  • Always use target_link_libraries() with a PRIVATE, PUBLIC or INTERFACE keyword. Excerpt from Craig Scotts Professional CMake book:

    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.

Upvotes: 1

Related Questions