I have an interface library cxx_opts in cmake that defines a bunch of flags and a binary main that uses the cxx_opts library.
cmake_minimum_required(VERSION 3.16)
project(test LANGUAGES CXX)
add_library(cxx_opts INTERFACE)
target_compile_options(cxx_opts INTERFACE
-Wall -Wpedantic -Wextra -Werror
)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE cxx_opts)
target_compile_options(main PRIVATE -Wno-unused-variable)
For completeness, my main.cpp is super simple:
int main() {
int unused_variable{};
}
I then configure this project and generate a compilation database with this command:
cmake -D CMAKE_EXPORT_COMPILE_COMMANDS=ON -S . -B build
If I now build this code, I'm getting an error:
cmake --build build
main.cpp:2:9: error: unused variable 'unused_variable' [-Werror,-Wunused-variable]
2 | int unused_variable{};
| ^~~~~~~~~~~~~~~
I expect that because I'm adding a -Wno-unused-variable flag to the main target the warning should not trigger, and yet it does and is treated as an error.
If I now inspect the compilation database generated as a result of the configuration step (cleaned up from unimportant stuff), I'm seeing that the order of the flags is wrong:
[
{
"directory": "test_project/build",
"command": "c++ -Wno-unused-variable -Wall -Wpedantic -Wextra -Werror -o CMakeFiles/main.dir/main.cpp.o -c test_project/main.cpp",
"file": "test_project/main.cpp"
}
]
Note how the -Wno-unused-variable appears before the -Werror flag, which causes the behavior I'm seeing.
Now with all of the above in mind, I do not understand why CMake is ordering these flags like it does. I also am an avid CMake user and was under the impression that this should not ever happen. From here, the CMake docs seem to say the following:
If BEFORE is specified, the content will be prepended to the property instead of being appended.
Repeated calls for the same append items in the order called.
To test the above statement I actively added the -Wno-unused-variable flag to the cxx_opts target directly with the same results, it still appears before the rest. So something actively reorders flags in the resulting command.
target_compile_options(cxx_opts INTERFACE
-Wall -Wpedantic -Wextra -Werror
)
target_compile_options(cxx_opts INTERFACE -Wno-unused-variable)
The error here happens on my Mac, so maybe it is Mac-related? Does anyone know what is happening here and what I can do to correct the order of the flags?
UPD: After the comments by @Tsyvarev it seems that we can do this instead that should guarantee the order of the flags (I'm not 100% sure of this yet):
cmake_minimum_required(VERSION 3.16)
project(test LANGUAGES CXX)
add_library(cxx_opts INTERFACE)
target_compile_options(cxx_opts INTERFACE
-Wall -Wpedantic -Wextra -Werror
)
add_library(custom_flags INTERFACE)
target_compile_options(custom_flags INTERFACE -Wno-unused-variable)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE cxx_opts custom_flags)
Note how we have to create another target custom_flags and link it after the cxx_opts for the flags from custom_flags target to appear after the ones from cxx_opts target. Is there a better (more idiomatic) way?
target_compile_optionsand flags obtained via usage requirement (from linked libraries). Actually, the reverse order is expected:target_compile_options(main PRIVATE -Wno-unused-variable)adds items toCOMPILE_OPTIONSproperty immediately, but call totarget_link_librariesdefers propagating usage requirements from linked libraries until the very end of configuration process (after allCMakeLists.txtare processed).INTERFACE_COMPILE_OPTIONS(and otherINTERFACE_*) those options which may be not suitable for consuming targets. And do not add to that lists those options which are not actually needed for use the library itself.target_compile_optionswith the same targetcxx_opts. The order of flags is still reversed.CMakeLists.txtis processed, a target property COMPILE_OPTIONS is populated only bytarget_compile_optionscommand for that target. When the last line of yourCMakeLists.txtis executed, the property contains only-Wno-unused-variable. Only at the end of the configuration process the property COMPILE_OPTIONS is enhanced with values from the linked libraries. So values-Wall,-Wpedantic,-Wextraand-Werrorfrom the librarycxx_optsare appended to the end of the list.