2

I am using CMake v3.13.4 with the Visual Studio 2017 Win64 generator and I need to modify the command line options for the Visual Studio Librarian (for a CMake object library).

To achieve that CMake offers the target property STATIC_LIBRARY_OPTIONS that can be set by the set_property and set_target_properties command.

The documentation states that STATIC_LIBRARY_OPTIONS supports generator expressions:

Contents of STATIC_LIBRARY_OPTIONS may use “generator expressions” with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties.

But: No matter what I try, the values are not properly escaped´, e.g.

set_property(TARGET object_library PROPERTY STATIC_LIBRARY_OPTIONS $<$<CONFIG:Release>:/WX /NOLOGO /LTCG /ERRORREPORT:NONE>)

leads to the following in Visual Studio:

All Options: `/OUT:"..." /LTCG /MACHINE:X64 /NOLOGO 
Additional Options: %(AdditionalOptions) /machine:x64 ""$"<1:/WX" "/ERRORREPORT:NONE>"

I've tried the following, all of them seem to fail.

set_property(TARGET object_library PROPERTY
  STATIC_LIBRARY_OPTIONS $<$<CONFIG:Release>:/WX /NOLOGO /LTCG /ERRORREPORT:NONE>
  #STATIC_LIBRARY_OPTIONS "$<$<CONFIG:Release>:/WX /NOLOGO /LTCG /ERRORREPORT:NONE>"
  #STATIC_LIBRARY_OPTIONS $<$<CONFIG:Release>:"/WX /NOLOGO /LTCG /ERRORREPORT:NONE">
  #STATIC_LIBRARY_OPTIONS $<$<CONFIG:Release>:/WX /NOLOGO /LTCG /ERRORREPORT:NONE>
  #STATIC_LIBRARY_OPTIONS $<$<CONFIG:Release>:/WX;/NOLOGO;/LTCG;/ERRORREPORT:NONE>
  #STATIC_LIBRARY_OPTIONS $<$<CONFIG:Release>:"/WX;/NOLOGO;/LTCG;/ERRORREPORT:NONE">
  #STATIC_LIBRARY_OPTIONS "$<$<CONFIG:Release>:/WX;/NOLOGO;/LTCG;/ERRORREPORT:NONE>"
  )

So my question is: How can I pass multiple values using generator expressions to STATIC_LIBRARY_OPTIONS with the set_property or set_target_properties command?

LoLance
  • 18,434
  • 1
  • 12
  • 39
Florian Wolters
  • 3,273
  • 3
  • 25
  • 47
  • 1
    "How can I pass multiple values using generator expressions?" - **Wrap each value** into its own generator expression: `$:/WX> $:/NOLOGO> ...`. – Tsyvarev Mar 20 '19 at 15:21

3 Answers3

3

Thanks to @Tsyvarev, I've been able to solve this problem. The solution is to wrap each value into its own generator expression:

set_property(TARGET object_library PROPERTY
    STATIC_LIBRARY_OPTIONS
      $<$<CXX_COMPILER_ID:MSVC>:/WX>
      $<$<CXX_COMPILER_ID:MSVC>:/NOLOGO>
      $<$<CXX_COMPILER_ID:MSVC>:/ERRORREPORT:NONE>
      $<$<CXX_COMPILER_ID:MSVC>:$<$<CONFIG:Release>:/LTCG>>
  )
Florian Wolters
  • 3,273
  • 3
  • 25
  • 47
1

Assuming you have a list of options:

set(option_list /WX /NOLOGO /LTCG /ERRORREPORT:NONE)

you may create a list of generator expressions for them by a single command:

list(TRANSFORM option_list
  REPLACE ".+" "$<$<CXX_COMPILER_ID:MSVC>:\\0>"
  OUTPUT_VARIABLE option_list_msvc
)

Resulted list can be used directly:

set_property(TARGET object_library PROPERTY STATIC_LIBRARY_OPTIONS ${option_list_msvc})

Command flow list(TRANSFORM) is available since CMake 3.12.

Tsyvarev
  • 45,732
  • 15
  • 64
  • 98
0

Below you find my answer, which, as @Tsyvarev helped me realize, doesn't help in the question's situation. Please instead consider his answer. As I found his comments below helpful, I'll leave the answer here, so that you may read the comments.

This answer is for future readers with newer cmake: As detailed in this answer by @firmament, depending on the cmake version, it may also be possible to put all values into a list via

set(my_option_list /WX /NOLOGO /LTCG /ERRORREPORT:NONE)

and pass this list to the generator expression:

"<$<CONFIG:Release>:${my_option_list}>"

This works on cmake 3.18.4 with clang and gcc generator expressions.

Eike
  • 78
  • 1
  • 7
  • 1
    I have tested this approach. Your generator expression in `Release` configuration internally produces `"/WX;/NOLOGO;/LTCG;/ERRORREPORT:NONE"`. For some commands this is equivalent to the list of those options: `/WX /NOLOGO /LTCG /ERRORREPORT:NONE`, so everything works. Among these command is `add_compile_options` from [your question](https://stackoverflow.com/q/65035750/3440745). But for some other commands this doesn't work. E.g. `add_custom_target(my_target COMMAND echo ":${my_option_list}>"` prints semicolons between the options. (Instead of printing them space-separated). – Tsyvarev Dec 09 '20 at 19:02
  • Thanks for letting me know! I guess, that invalidates my answer to this question. What's the best course of action? Should I delete it? Apparently it is not a right answer to this question. – Eike Dec 10 '20 at 20:22
  • "Apparently it is not a right answer to this question." - Why do you think so? You answer answers the current question, it answers your question. Actually, it resolves `add_custom_target` problem, but with additional COMMAND_EXPAND_LISTS keyword: https://stackoverflow.com/a/65231456/3440745. I have just explained some... specialties of your approach. BTW, I have upvoted your answer, not downvoted. – Tsyvarev Dec 10 '20 at 20:35
  • What I meant, is, that using just my answer doesn't lead to the desired outcome and so future readers would not benefit from it. I think, I should delete it to not confuse people that would better use your answer. As I'm not well versed with SO, I'll wait for a comment from you, whether this would be foolish or not. – Eike Dec 12 '20 at 10:08
  • Also maybe the current behaviour should be filed as a bug? I for one find it extremely confusing, how generator expressions work so differently for different commands. But I don't feel confident in my abilities and lack thereof with cmake to actually file one. – Eike Dec 12 '20 at 10:16
  • "how generator expressions work so differently for different commands." - No, the generator expressions *themselves* works in the same way. And you generator expression **always** produces `"/WX;/NOLOGO;/LTCG;/ERRORREPORT:NONE"`. But such **semicolon-separated string** is treated differently by different commands. It seems that many commands (which support generator expressions) treat that string as **list**, and this is the desired behavior. Command `add_custom_target` treats it differently... but there is an **official** way for change that behavior. I see no problem in that. – Tsyvarev Dec 12 '20 at 13:02
  • I think your comments might be helpful, therefor I will not delete my answer, so that they remain. I'll update it to direct everyone to your answer. – Eike Dec 12 '20 at 14:15