Cmake: target_compile_definitions with find_package - c++

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)

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.

Related

CMake doesn't link the actual object to the resulting dll [duplicate]

How do I define a preprocessor variable through CMake?
The equivalent code would be #define foo.
For a long time, CMake had the add_definitions command for this purpose. However, recently the command has been superseded by a more fine grained approach (separate commands for compile definitions, include directories, and compiler options).
An example using the new add_compile_definitions:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION})
add_compile_definitions(WITH_OPENCV2)
Or:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION} WITH_OPENCV2)
The good part about this is that it circumvents the shabby trickery CMake has in place for add_definitions. CMake is such a shabby system, but they are finally finding some sanity.
Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html
Likewise, you can do this per-target as explained in Jim Hunziker's answer.
To do this for a specific target, you can do the following:
target_compile_definitions(my_target PRIVATE FOO=1 BAR=1)
You should do this if you have more than one target that you're building and you don't want them all to use the same flags. Also see the official documentation on target_compile_definitions.
The other solutions proposed on this page are useful for some versions of Cmake > 3.3.2. Here the solution for the version I am using (i.e., 3.3.2). Check the version of your Cmake by using $ cmake --version and pick the solution that fits your needs. The cmake documentation can be found on the official page.
With CMake version 3.3.2, in order to create
#define foo
I needed to use:
add_definitions(-Dfoo) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
and, in order to have a preprocessor macro definition like this other one:
#define foo=5
the line is so modified:
add_definitions(-Dfoo=5) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
PLEASE NOTE (as #squareskittles suggests in one of the comment): "if you are using CMake 3.3.2, you have to use add_definitions() or target_compile_definitions(). The more modern command, add_compile_definitions(), was not added until CMake 3.12."
1.) target_compile_definitions
If you are using CMake 3.X your first choice for adding a preprocessor macro should be target_compile_definitions.
The reason you should prefer this approach over any other approach is because it granularity is target based. IE the macro will only be added to your exe/library.
Here is a common example:
if (WIN32)
target_compile_definitions(my_lib PRIVATE
# Prevents Windows.h from adding unnecessary includes
WIN32_LEAN_AND_MEAN
# Prevents Windows.h from defining min/max as macros
NOMINMAX
)
endif()
2.) add_compile_definitions
New in version 3.12.
Find more explanation on which commands to use for compiler flags here: https://cmake.org/cmake/help/latest/command/add_definitions.html
add_compile_definitions applies macros to any targets that are defined after the call.
Here is the same logic as above with add_compile_definitions.
add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX)
add_library(my_lib)
If you use this approach be careful if you are the top level project.
Otherwise if users consume your library using add_subdirectory they may have issues.
3.) The other less recommended ways
These approaches really aren't recommended anymore. Due to not being modular, not scaling well, not supporting generator expressions, etc.
add_definitions
CMAKE_LANG_FLAGS
Why is target_compile_definitions better/preferred?
It's much more clear to readers of your CMake code how it works.
Allows usage of PRIVATE/PUBLIC/INTERFACE if needed. Which can make life easier for consumers of your library.
It's much more modular.
Applying pre-processor flags (Or any compiler flag) globally can create hidden dependencies in your build.
Essentially think of add_compile_definitions as globals in C/C++. Sometimes you need them, but be careful.
i'd like to recommend use target_*** operations instead of add_*** operations when your solution include many projects.
here is an example where you can pass values from CMAKE to C++ code. Say, you want to pass:
flag, here: BOOST ("true" or "false")
software version string (e.g.: "1.0.0")
I recommend to pass them as strings.
So, when you build software with CMAKE, you can pass parameters like for example if it was built using boost library, software version pulled from CMAKE variable (so that you change that number only in one place)
See below.
In CMakeLists.txt:
add_compile_definitions(
BOOST="${BOOST}"
Software_VERSION="${PROJECT_VERSION}"
)
In your .cpp code:
std::cout << "Software version is: " << Software_VERSION << " BOOST: " << BOOST << "\n";
Hope this helps. Regards.

Why does AUTOMOC fail, if both find_package() and qt5_use_modules() are called from functions?

I am trying to compile some Qt project, including the QCustomPlot library. As a minimum example, i set up a project consisting of:
qcustomplot.h
qcustomplot.cpp
CMakeLists.txt
../cmake/QCustomPlot.cmake
The original project is bigger, but the problem is already reproducible with only those files.
The CMakeLists.txt contains this code:
cmake_minimum_required(VERSION 3.6)
set(CMAKE_AUTOMOC ON)
include(../cmake/QCustomPlot.cmake)
function(findqt) #(1)
find_package(Qt5Core)
find_package(Qt5Gui)
find_package(Qt5Widgets)
find_package(Qt5PrintSupport)
endfunction() #(1)
findqt() #(1)
#find_package(Qt5Core) #(2)
add_library(
Plots
src/qcustomplot.h
src/qcustomplot.cpp
)
function(linkqt) #(3)
qt5_use_modules(Plots Core Gui Widgets PrintSupport)
endfunction() #(3)
linkqt() #(3)
If either all lines marked (1) or all lines marked (3) are commented out, that means calling find_package() or qt5_use_modules() at file scope, i get a project containing the two qcustomplot files and an additional Plots_automoc.cpp. The additional file is autogenerated and contains the necessary #include "moc_qcustomplot.cpp" and the project compiles and links properly.
However as soon as i move all qt related commands into functions, the automoc.cpp file is no longer generated and no longer part of the project, which leads to quite a few unresolved external symbol during linking.
Calling only a single find_package() on files scope (like line (2)) resolves the issue and generates the automoc file again.
Why does simply moving the calls into a function change the automoc behaviour like this and how can i achieve to still move them into functions?
A little bit background: I already have quite a few targets in my project, expect the number to grow rapidly and want to avoid code redundancy. Also people not really trained with CMake are supposed to use it. Thats why i'm trying to move all those Qt related commands into functions and provide a command like this:
add_my_target(
targetName
SOURCES qcustomplot.h qcustomplot.cpp
QT Core Gui Widgets PrintSupport
BOOST filesystem
)
With the exception of Qt, i already achieved this...
I also tried using
target_link_libraries(${projectName} ${Qt5_Core_LIBRARIES} ...
//or
target_link_libraries(${projectName} Qt5::Core ...
it leads to the same result, as long as not at least one find_package() call is directly on files scope, no automoc is generated.
I am using CMake 3.6.2, Qt 5.7, Visual Studio 2015 and Win 10.
Additional example
oLen got most of my underlying confusion sorted out with his answer, but one case remains:
cmake_minimum_required(VERSION 3.6)
set(CMAKE_AUTOMOC ON)
function(doit) #(4)
find_package(Qt5Core)
add_library(
Plots
qcustomplot.h
qcustomplot.cpp
)
qt5_use_modules(Plots Core Gui Widgets PrintSupport)
endfunction() #(4)
doit() #(4)
Using the lines marked with (4) to put all the generation of the target into a function allows CMake to run properly, i.e. qt5_use_modules() is defined, able to find all the modules and link them (e.g. include directories are set properly). Nowhere outside the function do i rely on variables set by any of the Qt functions. But still automoc does not generate the needed .cpp file. Commenting the marked lines out runs automoc again.
The problem is that CMake functions introduce a scope, so that the variables defined in the find_package are not available outside the function.
An easy solution to your problem is to use CMake macros - you can think of them as the CMake equivalent of C macros. The variables declared there will also be available outside the macro scope.
In your case, this means replacing function by macro and endfunction by endmacro.

What to use instead of `qt5_use_modules`?

The Qt 5 CMake manual states that the qt5_use_modules macro is deprecated:
This macro is obsolete. Use target_link_libraries with IMPORTED targets instead.
... But qt5_use_modules does more than simply specify link libraries: it specifies include directories, necessary compile flags, and more (see the full description in the linked documentation above).
Assuming, then, that the variable QTMODULES contains some list of Qt modules that should be used for a project, what is the "recommended" way to replace the following "deprecated" CMake line?
qt5_use_modules(${myProjectName} ${QTMODULES})
The following does NOT work, primarily because it does not add any Qt include paths:
target_link_libraries(${myProjectName} IMPORTED ${QTMODULES})
Does the QTMODULES variable need to be manually iterated over, so that include_directories can be called for each individual module name? This seems like a major step backward from qt5_use_modules, which is simple and "just works." Am I missing something?
The message about using IMPORTED targets actually refers to the generated targets that Qt5's CMake modules provide for you, not that you should be setting the IMPORTED property on the target_link_libraries macro. For example, something like:
target_link_libraries(${myProjectName} Qt5::Core Qt5::Widgets)
will take care of adding all the necessary include paths, link paths, and libraries for using the Qt5Core and Qt5Widgets modules.

using cmake's target_compile_features with biicode

I'm trying to use target_compile_feature in my biicode block.
As far as I know, this is currently the best way to ask cmake for a specific c++ standard version, since it will know what (if any) flags to add to the compilation, and fail with an error if the compiler being used does not support the features we requested.
I added this line to my very simple CMakeLists.txt (no changes from the boost example in biicode's blog):
target_compile_features(${BII_BLOCK_TARGET} PRIVATE cxx_auto_type)
When running bii build, I'm greeted with this error:
CMake Error at bii_test/alchemist/blocks/sennin/deckbox_loader/CMakeLists.txt:13 (target_compile_features):
target_compile_features may only be set INTERFACE properties on INTERFACE
targets
Setting the cxx_auto_type at a PUBLIC or PRIVATE scope has exactly the same result.
I want to avoid using the CXX_STANDARD and CXX_STANDARD_REQUIRED because the first is a soft request (if the requested standard is not supported cmake will still allow us to attempt to build the code) and the second enforces that there is someway to request full support for the whole requested standard standard (and in the case of Visual Studio, fail, because there is no such flag).
I don't know anything about bii, but presumably BII_BLOCK_TARGET is something it provides? And you're supposed to use it with target_link_libraries or something?
Anyway, try the INTERFACE keyword.
target_compile_features(${BII_BLOCK_TARGET} INTERFACE cxx_auto_type)
http://www.cmake.org/cmake/help/v3.2/manual/cmake-compile-features.7.html
http://www.cmake.org/cmake/help/v3.2/manual/cmake-buildsystem.7.html#transitive-usage-requirements

CMake - Project level macro add to application level target_link_libraries

I have a lot of libraries in my project, and a LOT of individual applications. A few of the my libraries have dependency libraries, some of them external ones, and I'd like a way for the application CMakeList.txt files to be simpler. I'm hoping to use macros to simplify.
Below is a much reduced test case. For example, in my project, including one of my libraries requires also include_directories, link_directories, and target_link_libraries for ImageMagick, pugixml, jsoncpp, liboauthcpp, etc... And, some of these third party libraries require compiler flags. My project's version of the _LIB() macro below will be much longer...
Question: Is there a way I can have the _LIB() macro below automatically add something to the target_link_libraries that invoke the macro?
I'm not sure how to do that because target_link_libraries argument 1 is the target name, which changes per application.
~/codeTest/CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(codeTest)
macro(_LIB)
include_directories(~/codeTest/lib)
link_directories(~/codeTest/lib)
endmacro()
add_subdirectory(lib)
add_subdirectory(app)
~/codeTest/lib/CMakeLists.txt
include_directories(~/codeTest/lib)
add_library(lib lib.cpp)
~/codeTest/lib/lib.h
#ifndef __LIB__
#define __LIB__
namespace LIB {
unsigned long libFunc(unsigned long inValue);
}
#endif
~/codeTest/lib/lib.cpp
#include <lib.h>
namespace LIB {
unsigned long libFunc(unsigned long inValue) {
return inValue+1;
}
}
~/codeTest/app/CMakeLists.txt
_LIB()
add_executable(app app.cpp)
target_link_libraries(app lib)
~/codeTest/app/app.cpp
#include <lib.h>
using namespace LIB;
int main() {
unsigned long x = 1;
unsigned long y = libFunc(x);
}
With the growth of your project's complexity, you will soon find out that multiple {link,include}_directories directives, gathered in a macro, is inflexible solution, and they should be specified explicitly.
I recommend you to take into consideration an idea of modules (/usr/share/cmake/Modules/): for each of your external dependencies use a Find*.cmake file that can be found in cmake modules directory (see above) or in the package's one (if its authors have written an according module). Or you can write it yourself.
That modules usually define a number of variables, (e.g., Boost_INCLUDE_DIRS, Boost_LIBRARY_DIRS), that you will use only in those subprojects, that really need ones.
So, for each subproject you specify include_.../link_... directives explicitly referencing variables defined in modules or in your other subprojects (for internal dependencies).
Moreover, macros and functions in cmake are really very unpredictable for users, that expect them to behave like traditional functions in well-known programming languages (C, Java, Ruby, ...) when you start adding arguments to them; read about variable caching, scoping, and conversions between strings and lists.
Consider encoding the usage requirements into the targets themselves instead of using macros.
This would be 'modern cmake':
http://www.cmake.org/cmake/help/git-next/manual/cmake-buildsystem.7.html
http://www.kdab.com/modern-cmake-with-qt-and-boost/
http://www.steveire.com/WhatWhyHowCMake.pdf
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
I might recommend creating an INTERFACE library, if you can group some of your dependencies into 1 target this way.
For example,
add_library(ImageMagick ...)
#...etc gather all library targets however is conviennt
add_library(CoreDependencies INTERFACE)
target_link_libraries(CoreDependencies PUBLIC ImageMagick ...)
Then in your app(s) you can just
target_link_libraries(MyApp PRIVATE CoreDependencies)
and this will bring in everything you need. You could create several subsets of libraries if you really have so many different use cases.
Of note, this approach requires CMake 3.
https://cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#interface-libraries