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
Related
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.
I am trying to prepare CMakeLists.txt for closed properietary toolchain and curretly I am stuck in some problems. Build environment is linux so created Makefile have unix makefile style (e.g. library pre/suffixes).
Compiler and linker unfortunatelly have nonstandard syntax and some conventions is in unix some windows and some custom style.
I partially solved this problem by re-defining variable:
CMAKE_C_LINK_EXECUTABLE and CMAKE_C_COMPILE_OBJECT
One of problem is linker expect to provide standard library name like: libc.lib libm.lib etc.
but when I use: target_link_libraries(my_target_name PRIVATE libc.lib libm.lib) finally created makefile caused call compiler with parameter -llibc.lib and it cause error.
I tried manipulate suffixes and prefixes by setting: CMAKE_STATIC_LIBRARY_SUFFIX and CMAKE_STATIC_LIBRARY_PREFIX but I see no influence.
I've also tried to use call cmake with such define: -DCMAKE_TOOLCHAIN_FILE=../cmake/mytoolchain.cmake but as side effect I observed that some intrnal variables was reset to defaults (e.g. object file extension change from source.c.o to source.c.obj in case of c sources) and it's not acceptable for platform linker and cause linking error.
From my perspective looks like I have to create new custom configuration for platform I use but I have no idea how to start. I see that MSVC have different configuration than unix makefiles but which files determine it's behavior?
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.
I'm currently trying to setup a project that will make use of multiple compilers (including Clang, MSVC, and GCC) using Visual Studio 2019's new CMake functionalities (notably using Clang and Ninja in conjunction with CMake and VS2019).
I'm using CMake to configure the project to be "compiler-agnostic", so that I don't need to edit the code itself to handle different compilers via pre-processor instructions or #pragma instructions.
This project needs to be configured to have a high warning level (/W4 for MSVC, -Wall, -Wextra, and -Wpedantic for Clang), and must treat warnings as errors.
I don't have any issues when it comes to configuring the MSVC portion of the project. A lot of these settings have "sane" defaults that "just work" as I'd expect them to. When it comes to Clang, however, I've encountered a problem:
I can't seem to disable warnings for third-party library header files. I'm currently using the Dear Imgui and SFML libraries. Since Dear Imgui isn't pre-compiled, I simply do the following in my CMakeLists.txt file to include it:
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui
)
I use the statically linked version of SFML, so I do the following to include it:
# Find SFML and link statically to it.
# Note: We need to set the SFML_DIR variable manually.
set(SFML_STATIC_LIBRARIES TRUE)
set(SFML_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs/SFML-2.5.1/lib/cmake/SFML")
find_package(SFML 2.5.1 COMPONENTS system audio window graphics REQUIRED)
target_link_libraries(${PROJECT_NAME}
PRIVATE
sfml-system
sfml-audio
sfml-window
sfml-graphics
)
Sadly, SFML doesn't currently follow the current CMake standard way of adding libraries, so it's kind of weird to work with or configure it via CMake.
Now, the above works just fine when it comes to including the libraries in my project (but it might be something I need to change, so I've included it in the post). The problems come when I try to impose the warnings and warnings-as-errors configurations to them when using Clang.
Here are the parts of my CMakeLists.txt file which handle Clang and my C++ configurations:
# Set project to use C++ 17 standard.
set_target_properties(
${PROJECT_NAME}
PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
target_compile_options(${PROJECT_NAME} PRIVATE
# All warnings, warnings as errors, be pedantic.
-Wall
-Wextra
-Werror
-Wpedantic
# Disable warnings about C++98 incompatibility. We're using C++17 features...
-Wno-c++98-compat
-Wno-c++98-compat-pedantic
)
Using the above configuration results in hundreds of warnings/errors in Dear Imgui's source files (due to the usage of "old-school" C++/C-style code), as well as a whole bunch of them in SFML's own source files and header files.
I've been looking for ways to get around this for nearly a week, before settling on the following solution (which doesn't entirely work, more on that later):
set(LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/libs")
set(IMGUI_FOLDER "${LIBS_FOLDER}/imgui")
set(SFML_FOLDER "${LIBS_FOLDER}/SFML-2.5.1/include/SFML")
file(GLOB LIBRARY_FILES
# Dear-imgui
"${IMGUI_FOLDER}/*.cpp"
"${IMGUI_FOLDER}/misc/freetype/*.cpp"
"${IMGUI_FOLDER}/misc/fonts/*.cpp"
"${IMGUI_FOLDER}/misc/cpp/*.cpp"
# SFML
"${SFML_FOLDER}/Audio/*.cpp"
"${SFML_FOLDER}/Graphics/*.cpp"
"${SFML_FOLDER}/Network/*.cpp"
"${SFML_FOLDER}/System/*.cpp"
"${SFML_FOLDER}/Window/*.cpp"
)
set_source_files_properties(
${LIBRARY_FILES}
PROPERTIES
COMPILE_FLAGS
"-Wno-everything"
)
I begin by GLOB-ing my library source files (NOTE: I know GLOB is usually looked down upon, but I felt like using it with third-party library files was fine since they're not supposed to change anyway). I then pass them to the set_source_files_properties function to apply the -Wno-everything flag, which seems to properly suppress all errors and warnings from those files.
Everything seems to work just fine, except for one warning which I can't seem to disable without using a #pragma instruction in my code (which I want to avoid). When compiling an empty main function that includes SFML headers, I get warnings about their .hpp files (which can't be passed to the set_source_files_properties function).
This:
#include <SFML/Graphics.hpp>
int main()
{
}
Results in the following warnings/errors:
zero as null pointer constant [-Werror,-Wzero-as-null-pointer-constant]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
In these respective SFML files:
ThreadLocal.hpp (57)
Keyboard.hpp (161)
Event.hpp (105)
PrimitiveType.hpp (52)
Other things I've tried that didn't work:
Putting the .h/.hpp files in the set_source_files_properties CMake function (alongside the .cpp files). Works for Dear Imgui, but all its errors were in .cpp files, not its headers. Doesn't work for SFML's headers.
(Not for SFML, but for Dear Imgui) Including the directories as SYSTEM includes to suppress the warnings. Doesn't appear to work on Windows. Can't really do this with SFML, since I'm using CMake's find_package function instead of doing everything manually.
Using #pragma instructions. While this worked, every SFML file has dozens of different errors, and I want to avoid using #pragmas everywhere (or wrapping SFML's headers in my own headers that just wrap the #include instruction in #pragmas).
Is it even possible to suppress these warnings for my library headers without #pragmas? I've never really used Clang before, so apologies if this seems like a simple question, but searching online hasn't really given me anything that would work:
Outside of a commandline (I'm using Visual Studio with CMake).
On Windows (the system flag doesn't seem to work with this setup).
That would work with CMake specifically.
You can mark the include paths as SYSTEM. Most compilers will not report warnings in system headers. In your case that might look something like this:
include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui)
set_target_properties(sfml-system PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-system,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-audio PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-audio,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-window PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-window,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-graphics PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-graphics,INTERFACE_INCLUDE_DIRECTORIES>)
For example, this dummy project:
project(example)
cmake_minimum_required(VERSION 3.18)
add_library(dep INTERFACE)
target_include_directories(dep INTERFACE include)
file(WRITE include/header.h "static int a;")
add_library(lib STATIC lib.c)
target_link_libraries(lib PRIVATE dep)
target_compile_options(lib PRIVATE -Wunused -Werror)
file(WRITE lib.c "#include <header.h>")
Fails with:
$ cmake . && make
include/header.h:1:12: error: ‘a’ defined but not used [-Werror=unused-variable]
But after adding this line:
set_target_properties(dep PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:dep,INTERFACE_INCLUDE_DIRECTORIES>)
It builds with no errors.
There is a way to suppress warnings from third party headers in a CMake way.
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
The system keyword is most likely what you want.
If SYSTEM is specified, the compiler will be told
the directories are meant as system include directories on some platforms
The SYSTEM keyword adds -isystem for GCC/Clang. Instead of treating the directory like a normal include directory.
# GCC docs
Warnings from system headers are normally suppressed.
On the assumption that they usually do not indicate real problems
and would only make the compiler output harder to read.
For a while there was no solution for MSVC until recently in CMake 3.22, because the MSVC compiler finally added support for this.
Here is the MSVC blog post where they talk about the new compiler functionality.
The “Ninja” and “NMake Makefiles” generators now use
the MSVC “-external:I” flag for system includes.
This became available as of VS 16.10
(toolchain version 14.29.30037).
I have the following situation: a static library MyStaticLib depending on several libraries of the FFmpeg project (libavformat etc.).
The FFmpeg libraries were linked (not by me) with the "/SAFESEH:NO" option, which means that any image that links to them (via their import libraries) must also be linked with the same option (failure to do so makes the linker abort with "LNK2026: module unsafe for SAFESEH image").
I've tried everything I could think of, but I haven't found a way to attach that option to my MyStaticLib in a way that would make it propagate to the consumer.
This seems strange, because CMake does provide the means for compiler options to propagate to consumers: the command target_compile_options() used with the PUBLIC option does exactly that.
Is there no similar feature for linker flags?
VC++ compiler and linker accept both
a forward slash (/) and a dash (–) as an option specifier.
As mentioned by #tsyvarev, CMake may have problems with forward slash, treating it as a path separator.
Therefore you need to use the following command to add a linker option to MyStaticLib target and propagate the option to the MyStaticLib consumers:
target_link_libraries(MyStaticLib PUBLIC "-SAFESEH:NO")
or if your build config supports other compilers as well:
target_link_libraries(MyStaticLib PUBLIC "$<$<CXX_COMPILER_ID:MSVC>:-SAFESEH:NO>")
Starting with CMake 3.13, you need to use target_link_options() instead:
target_link_options(${CMAKE_PROJECT_NAME} PUBLIC "$<$<C_COMPILER_ID:MSVC>:-SAFESEH:NO>")
Tested with CMake 3.16.2 and MSVC2019.