Reputation: 623
In my project I have a root CMakeLists.txt
which defines some executables. I use target_compile_options
to configure some settings like warnings for these executables. I have some subdirectories that compile some libraries to link with the executable. How can I propagate the compile options from the root CMakeLists.txt
to the dependencies in subdirectories without redefining the compile options in each subdirectory CMakeLists.txt
?
As an example, here is simplified version of my root CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(proj)
enable_language(C ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
add_subdirectory(src/lib/somelib)
add_executable(my_executable src/app/main.c)
target_compile_options(my_executable PUBLIC -Wpedantic) # as an example
target_link_libraries(my_executable PRIVATE somelib)
and the CMakeLists.txt
in src/lib/somelib
add_library(somelib somelib.c)
target_include_directories(somelib PUBLIC .)
In this example, I would like for somelib.c
to be compiled with whatever compile options are in the root CMakeLists.txt
.
Upvotes: 9
Views: 6985
Reputation: 39
You can add a compile option using:
add_compile_options(-Wall)
or by appending to CMAKE_<LANG>_FLAGS
(in chis case <LANG>
is C
) as follows:
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
To propagate it to a subdirectory it needs to be called before add_subdirectory(...)
add_compile_options(-Wall)
add_subdirectory(my/source/dir/path)
You can also achieve that with target_compile_options
by calling it from top-level CMakeLists, but in that case, you need to have a target defined and do it in the opposite order by calling add_subdirectory
first:
add_subdirectory(my/source/dir/path)
target_compile_options(MyLib PUBLIC -Wall)
my/source/dir/path/CMakeLists.txt
:
project(MyLib C)
# ...
add_library(${PROJECT_NAME} my_lib.h my_lib.c)
It should also work for executable, i.e.
add_executable(${PROJECT_NAME} main.c)
P.S. I lost a few hours on this myself, so I hope it helps someone :)
Upvotes: 0
Reputation: 19916
The place for warning flags is in the CMakePresets.json or a custom toolchain file. Only hard usage requirements belong in the CMakeLists.txt files. Your code successfully compiling has nothing to do with which warnings you use.
Furthermore, you should generally apply warning flags consistently across your project. Don't use the build system to bury problems in your code. If your compiler is throwing a false positive, add compiler-speicific pragmas (guarded by the necessary ifdefs, as needed) to locally disable warnings around the problematic code.
Here's how I would write your top-level CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(proj LANGUAGES C ASM)
set(CMAKE_C_STANDARD 11
CACHE STRING "Version of the C standard to use")
option(CMAKE_C_STANDARD_REQUIRED "Enable to enforce strict C standard selection" ON)
option(CMAKE_C_EXTENSIONS "Enable to allow compiler-specific C extensions" OFF)
add_subdirectory(src/lib/somelib)
add_executable(my_executable src/app/main.c)
target_link_libraries(my_executable PRIVATE somelib)
In CMakePresets.json:
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 21,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default",
"description": "Default build options for GCC-compatible compilers",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_C_FLAGS": "-Wall -Wextra -pedantic"
}
}
]
}
Compile with
$ cmake --preset default
I have written about the rationale for this elsewhere, so I'll post links to those references.
The gist is that the meaning of a warning flag is dependent on the compiler vendor, variant, and version, and so putting them in your CMakeLists.txt attaches a very brittle dependency on those things. It makes compiler upgrades and changes unnecessarily difficult and makes your build harder to distribute and reuse, even within a company.
Additionally, you should avoid using relative paths in target_include_directories
and library targets should generally guard their paths with $<BUILD_INTERFACE:...>
to be ready for installation / export.
target_include_directories(
somelib PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
Upvotes: 3
Reputation: 14046
From the cmake manual:
add_compile_options
Adds options to the COMPILE_OPTIONS directory property. These options are used when compiling targets from the current directory and below.
So for the given example, should be able to just add this to the top level CMakeLists.txt:
add_compile_options(-Wpedantic)
Upvotes: 3