Reputation: 5181
I've got the following generator expression working, which sets the /GS
flag if the compiler is MSVC and it sets it for the build configurations RelWithDebInfo
and Release
:
target_compile_options(mytarget PRIVATE
"$<$<CONFIG:Release>: $<$<CXX_COMPILER_ID:MSVC>:/GS>>
$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>")
Now I also want to let the user configure this, and I've added an option
:
option(MYTARGET_ENABLE_GS "Enable /GS" OFF)
So now, I (obviously) want to enable the /GS
flag if the user enabled this option, and if they did, I want to add it if the compiler is MSVC, and it should be added to the Release
and RelWithDebInfo
configurations.
This is pretty nested, and I can't seem to get it right. This is as far as I got:
target_compile_options(mytarget PRIVATE
"$<$<BOOL:MYTARGET_ENABLE_GS>:
$<$<CONFIG:Release>: $<$<CXX_COMPILER_ID:MSVC>:/GS>>
$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>>")
Edit: Fixed, see below.
I've had to use the $<$<BOOL:...>>
because that "translates" the option
(which can be on/off or true/false, to 0
or 1
, which the generator expression needs.
However above line doesn't work: It doesn't add (or not add) /GS
.
I'd like to know:
1) Where is my mistake? How to do this? And
>
or something like that.
I could probably use "manual" if
s to make this more readable, but imagine having 5-10 of such options - writing an if
/end
with a target_compile_options
inside results in like 15-30 lines of if
/end
code, which is also not very pretty to look at. What's the best way to do this?Edit: I was nearly there. Variables have to be enclosed with ${...}
in generator expressions. So it's for example:
target_compile_options(mytarget PRIVATE
"$<$<BOOL:${MYTARGET_ENABLE_GS}>:
$<$<CONFIG:Release>: $<$<CXX_COMPILER_ID:MSVC>:/GS>>
$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>>")
and that works great.
Which still leaves point "2)", which I would be keen to getting insights on.
Upvotes: 9
Views: 9357
Reputation: 22588
When you generate a MSVC solution, the build type (Release, Debug, etc.) is unknown until you actually run the build. Thus, using generator expression for that is correct.
But for the 2 other variables (does user set MYTARGET_ENABLE_GS to OFF and is generation performed for MSVC), they are resolved at configuration time. So, you don't have to check them in a generator expression. You could simply write:
if(MSVC AND MYTARGET_ENABLE_GS)
target_compile_options(mytarget PRIVATE "$<$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>:/GS>")
endif()
This solution also uses $<OR:?[,?]...>
generator expression to regroup under the same expression both cases you build in Release OR RelWithDebInfo
Upvotes: 7
Reputation: 9896
CMake's documentation a generator expressions works if your config matches any configuration listed after CONFIG:
, but I couldn't find the syntax documented anywhere. Trial and error show the following works correctly:
if(MSVC AND MYTARGET_ENABLE_GS)
target_compile_options(mytarget PRIVATE "$<$<CONFIG:Release,RelWithDebInfo>:/GS>")
endif()
Upvotes: 0
Reputation: 65870
Whenever you may use if
command, use it. Generator expressions are not replacement for if
command.
Generator expressions allow to use conditions dependent on build type. Because on multi-configuration build systems, like Visual Studio, build type isn't known at configuration stage, you cannot use such condition in if
command.
But generator expressions are ugly, so do not use them when it is not needed.
There is nothing bad in
if(MYTARGET_ENABLE_GS)
target_compile_options(mytarget PRIVATE "$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>")
endif()
If you want to check an option at the beginning, but create a target later, you may store generator expression in the variable, and use this variable later:
set(additional_options)
# Depending on parameters, add options to 'additional_options' list.
if(MYTARGET_ENABLE_GS)
list(APPEND additional_options "$<$<CONFIG:Release>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>$<$<CONFIG:RelWithDebInfo>:$<$<CXX_COMPILER_ID:MSVC>:/GS>>")
endif()
if(<other option>)
list(APPEND additional_options <...>)
endif()
# ...
target_compile_options(mytarget PRIVATE ${additional_options})
Upvotes: 4