I have a question about how CMAKE_<LANG>_STANDARD and which takes precedence.
Cache variable -DCMAKE_<LANG>_STANDARD vs set() (not cached):
Local variable wins because it shadows cached variable
set() in parent project vs set() in FetchContented project:
FetchContent definition wins
set_target_properties vs any value of CMAKE_<LANG>_STANDARD:
Property wins
So then what is and appropriate design:
Always use set() (uncached) to set the project’s minimum standard, allowing the user to bump/decrease the standard version. User cannot overwrite project’s standard
It is the importer’s responsibility to make sure the imported project satisfies their minimum version requirement. This is to avoid confusion like: Project’s standard is always respected even if parent project has different standard
How to set a recommended minimum STANDARD (e.g. C++23), and if compiler does not support it, default to a minimum standard that is supported (e.g. C++17)?
If you mean “during the build process” something that tries to peek into CMakeCache.txt and divine something…sure the cache is the only thing that exists at that point. An example would help a lot.
I have tried to replicate the environment here, from an earlier experiment, but it seems I cannot replicate. I might have not had the CMAKE_C_STANDARD set in that commit so it only took the value from the cache.
So in this case the values prescribed in the project always win. Then my confusion is resolved except for:
Advice on that? How do I test the compiler feature? Do I have to do it on individual targets as:
target_compile_features(mylib PUBLIC
"$<$<COMPILE_FEATURES:cxx_std_23>:cxx_std_23>"
"$<$<NOT:$<COMPILE_FEATURES:cxx_std_23>>:cxx_std_17>"
)
I don’t think there’s an easier way to do it, no. However, I think your genex does nothing useful as it will only say cxx_std_23 if the linking target already has cxx_std_23 available. I’d just use cxx_std_17 and use set(CMAKE_CXX_STANDARD 23) when you want to test C++23.
Hmm, that’s confusing. My understanding of that genex is that it tests the compiler for C++23 and if available it sets that as the standard, otherwise it sets it as C++17. The difference with set(CMAKE_CXX_STANDARD 23) is that if it’s not satisfied, it does not set an appropriate minimum standard. Or am I wrong and cmake goes through the standard list and it picks the first highest one that is satisfied?
where features is a comma-separated list. Evaluates to 1 if all of the features are available for the ‘head’ target, and 0 otherwise.
the “available to the ‘head’ target” means “has in its compile feature list”.
If this expression is used while evaluating the link implementation of a target and if any dependency transitively increases the required C_STANDARD or CXX_STANDARD for the ‘head’ target, an error is reported.
Means that increasing the standard while doing the query is going to raise an error.
So, basically: try it out and see if it works (my reading might indeed be inaccurate). Whatever the results, the docs could probably use some clarification.