CMake generator expression dependent on source property - cmake

I'm trying to add a compiler flag to all source files that don't have a specific property set.
The first use case is adding -Wshadow -Wuseless-cast to the command line for all non-GENERATED files, later on I'd like to add custom properties for other compiler flags.
I'd like to avoid the "trick" of countermanding default compile flags with per-source flags, because that requires subdirectory CMakeLists.txt to be aware of different options, the need to override them and the proper way to extend a list of flags with
set_property(
SOURCE ...
APPEND_STRING
PROPERTY COMPILE_FLAGS "-Wno-shadow ")
which IMO is a lot of boilerplate that needs to be duplicated often.
The documentation for generator expressions is awfully silent on checking source properties. Can this be done at all?

Related

In CMake, is there a way to set properties on all target dependencies?

In CMake, we can set target properties as either PRIVATE, PUBLIC, or INTERFACE. Both PUBLIC and INTERFACE properties are inherited by any targets that depend on the current target. However, unless I'm missing something, there doesn't seem to be an easy way to define a property that must propagate in the other direction (i.e., inherited by dependencies of the current target).
Most linkers/compilers require that all linked targets have the same value for certain properties (e.g., the exception handling model). If we want to change one of these properties for an executable it requires that it be set on all of its dependencies. Often these dependencies are submodules in our code where we can't modify their CMakeLists.txt files for our specific use-case. This leaves us with two options:
Set a global property (e.g., CMAKE_CXX_FLAGS or add_compile_options) that propagates to all targets in any subdirectories regardless of whether they are dependencies or not.
Explicitly set the properties on each dependent target using target_compile_options. This gets excessive and repetitive depending on the number of dependencies.
It would be nice if there was a functionality that would pass properties down only to dependency targets without having to specify them all individually. Does anyone know how to do this?
For the case of compiler flags that must be consistent for an entire program (including parts that are dynamically linked), such as MSVC's exception handling model, I think the set-something-global approach is suitable. To me, it seems pragmatic and slightly more robust than adding flags to each third-party target one-by-one (ie. what if you forget to handle to one? or what if third-party targets are added or removed in a new version? it seems like a ripe opportunity for human error).
Setting the environment variable [CMAKE_<LANG>_FLAGS] is a good start. You may need to do more if you are building external projects via ExternalProject.
A word of caution for such settings like the exception handling model: You might be tempted to hardcode this global setting inthe CMake files for your project. If your project is used by people other than just you or your company, and especially if its main component is a library and not an executable, it's good practice not to do that. Don't take away your user's ability to choose something like this (unless for some reason your library requires a certain exception handling model, in which case I would still leave this global setting up to them to set, provide documentation stating this, and look into emitting a CMake warning if a user doesn't comply). Instead, use a feature like CMake presets, or only set it if the project is the top-level project
An intersting side note: CMake currently globally "hard-codes" /EHsc for MSVC builds by default. Here's the ticket discussing this

CMake: How to make dependence on package optional?

I would like MPI to be optional for using my code.
I currently have a Cmake project that includes MPI as follows in the CMakeLists.txt:
find_package(MPI REQUIRED)
My some of my .cpp and .h files have the following:
#define MPI_available true
On a system where MPI is not available, one can remove the first statement and change the second statement into #define MPI_available false. Then the code is structured such that it doesn't attempt to include ``mpi.h''. However, I would prefer CMAKE to detect the presence/absence of MPI, and set the MPI_available flag for compiling the source files accordingly.
I believe setting
find_package(MPI QUIET)
will ensure that cmake does not choke when it cannot find MPI. Is this the preferred way of getting where I want to be? If so, how to link this to the flag? If not, what should I do to make MPI optional when cmake-> making the code.
Call to find_package(someLib) sets a variable someLib_FOUND. You can use it to check whether the someLib is available, then you can set a compile definitions. Something like:
find_package(MPI)
if(NOT MPI_FOUND)
target_compile_definitions(yourTarget PUBLIC MPI_available=0)
endif()
Calling cmake's default FindMPI.cmake module through find_package(MPI) already ensures that cmake will define the variable MPI_FOUND to reflect whether mpi was found or not.
Afterwards, you can use MPI_FOUND to achieve your goal. For example, you can generate your project's config.h with calls to cmake's config_file to define macros such as MPI_available, and update your code accordingly.

CMake compiler independent flags

Are there any compiler independent flags that can be set? I'd like to be able to set single variable to e.g. OPTIMIZE_MOST and get -O3 on gcc and /O2 in MS C++ compiler. Is there something I can use or should flags be set for each compiler separately?
Simply spoken: No, there is no flag to directly set the optimization level independently for every compiler.
However, CMake provides so called build types. Those are independent of the compiler in use and each comes with a predefined selection of flags, one of which is the optimization flag.
Available build types are
Debug
Release
RelWithDebInfo
MinSizeRel
For a comprehensive explanation, I refer to this answer. It also provides some code that helps to identify the flags in question when included into the CMakeLists.txt file:
message("CMAKE_C_FLAGS_DEBUG is ${CMAKE_C_FLAGS_DEBUG}")
message("CMAKE_C_FLAGS_RELEASE is ${CMAKE_C_FLAGS_RELEASE}")
message("CMAKE_C_FLAGS_RELWITHDEBINFO is ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
message("CMAKE_C_FLAGS_MINSIZEREL is ${CMAKE_C_FLAGS_MINSIZEREL}")
message("CMAKE_CXX_FLAGS_DEBUG is ${CMAKE_CXX_FLAGS_DEBUG}")
message("CMAKE_CXX_FLAGS_RELEASE is ${CMAKE_CXX_FLAGS_RELEASE}")
message("CMAKE_CXX_FLAGS_RELWITHDEBINFO is ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
message("CMAKE_CXX_FLAGS_MINSIZEREL is ${CMAKE_CXX_FLAGS_MINSIZEREL}")
To a degree. For some concepts, CMake has support for specifying them in a compiler-agnostic manner, usually by setting properties on the target in question. Unfortunately, there is no one location where all such possibilities would be listed. I went through the current list of target properties and identified the following properties as "absrtacting away build-tool option syntax":
COMPILE_PDB_NAME
INCLUDE_DIRECTORIES
INSTALL_RPATH
INTERPROCEDURAL_OPTIMIZATION
LINK_DIRECTORIES
LINK_LIBRARIES
PDB_NAME
PDB_OUTPUT_DIRECTORY
(plus the properties for setting output name, path, etc.)
There is apparently nothing for handling optimisation flags other than IPO.
To the best of my knowledge, there is also no generic process for adding these — they are added to CMake as someone finds the need for them (and the time to implement them).

Is there a LINK_DIRECTORIES or equivalent property in CMake?

I have created a project with a large number of link_directories() commands. I'd now like to store the resulting string of directories into a variable. For include_directories() this is easy using
get_property( test_INCLUDE_DIRECTORIES TARGET test PROPERTY INCLUDE_DIRECTORIES )
however there seems to be no LINK_DIRECTORIES property to do
get_property( test_LINK_DIRECTORIES TARGET test PROPERTY LINK_DIRECTORIES )
Is there a way to get a list of link directories used for a target?
(Note: I realize I could manually track the link directories in a variable myself and then use a single link_directories() but it doesn't seem very clean)
Take a look at the LINK_DIRECTORIES directory property.
The point is that link_directories operates on a per-directory basis (the command affects all targets defined in the same CMakeLists, as well as targets from all of its subdirectories), unlike, for instance, target_include_directories which works on a per-target basis.
You can query the value of the property with:
get_property(test_LINK_DIRECTORIES DIRECTORY PROPERTY LINK_DIRECTORIES)
if called from the same directory as the link_directories call. Otherwise, you need to give the (full or relative) path as an additional argument after DIRECTORY. Unfortunately, I know of no way to obtain the matching directory for an existing target.
Note that in general the use of link_directories is discouraged in CMake, which is probably the main reason why it's not supported very well. Unless you have very good reasons not to, you should always stick with full library paths passed to target_link_libraries. It will save you lots of headaches in the long run.

What is the modern method for setting general compile flags in CMake?

There are multiple mechanisms offered by CMake for getting flags to the compiler:
CMAKE_<LANG>_FLAGS_<CONFIG> variables
add_compile_options command
set_target_properties command
Is there one method that is preferred over the other in modern use? If so why? Also, how can this method be used with multiple configuration systems such as MSVC?
For modern CMake (versions 2.8.12 and up) you should use target_compile_options, which uses target properties internally.
CMAKE_<LANG>_FLAGS is a global variable and the most error-prone to use. It also does not support generator expressions, which can come in very handy.
add_compile_options is based on directory properties, which is fine in some situations, but usually not the most natural way to specify options.
target_compile_options works on a per-target basis (through setting the COMPILE_OPTIONS and INTERFACE_COMPILE_OPTIONS target properties), which usually results in the cleanest CMake code, as the compile options for a source file are determined by which project the file belongs to (rather than which directory it is placed in on the hard disk). This has the additional advantage that it automatically takes care of passing options on to dependent targets if requested.
Even though they are little bit more verbose, the per-target commands allow a reasonably fine-grained control over the different build options and (in my personal experience) are the least likely to cause headaches in the long run.
In theory, you could also set the respective properties directly using set_target_properties, but target_compile_options is usually more readable.
For example, to set the compile options of a target foo based on the configuration using generator expressions you could write:
target_compile_options(foo PUBLIC "$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>")
target_compile_options(foo PUBLIC "$<$<CONFIG:RELEASE>:${MY_RELEASE_OPTIONS}>")
The PUBLIC, PRIVATE, and INTERFACE keywords define the scope of the options. E.g., if we link foo into bar with target_link_libraries(bar foo):
PRIVATE options will only be applied to the target itself (foo) and not to other libraries (consumers) linking against it.
INTERFACE options will only be applied to the consuming target bar
PUBLIC options will be applied to both, the original target foo and the consuming target bar