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

cmake

Solution

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`

Problem

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?

Original source

Related problems