The above API forces users to explicitly set the DISABLE_SPECIAL_FLAG property on each target that is directly linking against mylib (I’m aware that users can work around it by linking publically against their own interface library that sets it only once).
I’m wondering if there’s a way to implement something like CMAKE_AUTOMOC, where if the CMAKE_AUTOMOC variable is set in a scope, all targets created below that variable get their AUTOMOC property initialized to whatever is set in CMAKE_AUTOMOC.
So I’d like the user to set a GLOBAL_DISABLE_SPECIAL_FLAG variable to 1, and then the DISABLE_SPECIAL_FLAG property is automatically populated with 1 for all targets created below that statement.
Variable-initialized properties are handled by CMake at the C++ level, with a hard-coded list. There is no way to update this list without changing CMake’s C++ code. If you would like such a feature, please open a bug report with a proposed solution.
This sounds like using define_property(INHERITED) to make get_property “chain up to the next higher scope when the requested property is not set in the scope given to the command.” (see https://cmake.org/cmake/help/latest/command/define_property.html for more details)
From what I’ve read, INHERITED only affects get_property()-like calls, whereas i would need an inherited set_property()-like call so that generator expressions can evaluate the appropriate values.
This zip archive contains a small CMake project with a top-level CMakeLists.txt that defines mylib, and three sub-folders that each define an executable target.
top-level CMakeLists.txt:
cmake_minimum_required(VERSION 3.4)
add_library(mylib INTERFACE)
define_property(TARGET
PROPERTY DISABLE_SPECIAL_FLAG
INHERITED
BRIEF_DOCS "Disable special flag"
FULL_DOCS "When true, don't add -my-nice-flag to the compile options of the targets that depend on mylib."
)
set(genex_condition "$<NOT:$<BOOL:$<TARGET_PROPERTY:DISABLE_SPECIAL_FLAG>>>")
set(flags "$<${genex_condition}:-my-nice-flag>")
target_compile_options(mylib INTERFACE "${flags}")
add_subdirectory(default)
add_subdirectory(disable_special_flag)
add_subdirectory(not_disable_special_flag)
default/CMakeLists.txt:
# don't set DISABLE_SPECIAL_FLAG to anything
add_executable(appDefault "main.cpp")
target_link_libraries(appDefault PRIVATE mylib)
When you build that project, you’ll see that -my-nice-flag is passed to the compiler when building appDefault and appNotDisabled, but not when building appDisabled. On my Windows machine, this results in the following build output:
$ ~/dev/bin/cmake-3.4.0/bin/cmake --build . -- -v:m
Microsoft (R) Build Engine version 14.0.25420.1
Copyright (C) Microsoft Corporation. All rights reserved.
cl : Command line warning D9002: ignoring unknown option '-my-nice-flag' [D:\dev\tmp\cmake-topic-1196\build\default\
appDefault.vcxproj]
main.cpp
appDefault.vcxproj -> D:\dev\tmp\cmake-topic-1196\build\default\Debug\appDefault.exe
appDefault.vcxproj -> D:/dev/tmp/cmake-topic-1196/build/default/Debug/appDefault.pdb (Full PDB)
main.cpp
appDisabled.vcxproj -> D:\dev\tmp\cmake-topic-1196\build\disable_special_flag\Debug\appDisabled.exe
appDisabled.vcxproj -> D:/dev/tmp/cmake-topic-1196/build/disable_special_flag/Debug/appDisabled.pdb (Full PDB)
cl : Command line warning D9002: ignoring unknown option '-my-nice-flag' [D:\dev\tmp\cmake-topic-1196\build\not_disa
ble_special_flag\appNotDisabled.vcxproj]
main.cpp
appNotDisabled.vcxproj -> D:\dev\tmp\cmake-topic-1196\build\not_disable_special_flag\Debug\appNotDisabled.exe
appNotDisabled.vcxproj -> D:/dev/tmp/cmake-topic-1196/build/not_disable_special_flag/Debug/appNotDisabled.pdb (Ful
l PDB)
Let me know if I missed something or if I’m totally off wrt. your use case.
The missing piece of the puzzle for me was the usage of set_directory_properties.
Indeed in this case i could create a function called my_namespaced_disable_special_flag(), which would both define the inherited property, and set the the directory property.
The downsides to this approach that I see compared to how CMAKE_AUTOMOC works (variable-initialized properties), is that with the inherited property, the considered property value can escape all the way to the global scope, and the ordering of calls is not respected.
Undesired case:
define_property(TARGET
PROPERTY DISABLE_SPECIAL_FLAG
INHERITED
BRIEF_DOCS "Disable special flag"
FULL_DOCS "When true, don't add -my-nice-flag to the compile options of the targets that depend on mylib."
)
set_directory_properties(PROPERTIES DISABLE_SPECIAL_FLAG 1)
add_subdirectory(d1)
set_directory_properties(PROPERTIES DISABLE_SPECIAL_FLAG 0)
The final property modification will still affect targets in d1 as if “0” is the value, whereas if i use a hypothetical