问题
I'm trying to create a custom command that runs with some environment variables, such as LDFLAGS, whose value needs to be quoted if it contains spaces:
LDFLAGS="-Lmydir -Lmyotherdir"
I cannot find a way to include this argument in a CMake custom command, due to CMake's escaping rules. Here's what I've tried so far:
COMMAND LDFLAGS="-Ldir -Ldir2" echo blah VERBATIM)
yields "LDFLAGS=\"-Ldir -Ldir2\"" echo blah
COMMAND LDFLAGS=\"-Ldir -Ldir2\" echo blah VERBATIM)
yields LDFLAGS=\"-Ldir -Ldir2\" echo blah
It seems I either get the whole string quoted, or the escaped quotes don't resolve when used as part of the command.
I would appreciate either a way to include the literal double-quote or as an alternative a better way to set environment variables for a command. Please note that I'm still on CMake 2.8, so I don't have the new "env" command available in 3.2.
Note that this is not a duplicate of When to quote variables? as none of those quoting methods work for this particular case.
回答1:
The obvious choice - often recommended when hitting the boundaries of COMMAND especially with older versions of CMake - is to use an external script.
I just wanted to add some simple COMMAND only variations that do work and won't need a shell, but are - I have to admit - still partly platform dependent.
One example would be to put only the quoted part into a variable:
set(vars_as_string "-Ldir -Ldir2") add_custom_target( QuotedEnvVar COMMAND env LD_FLAGS=${vars_as_string} | grep LD_FLAGS )Which actually does escape the space and not the quotes.
Another example would be to add it with escaped quotes as a "launcher" rule:
add_custom_target( LauncherEnvVar COMMAND env | grep LD_FLAGS ) set_target_properties( LauncherEnvVar PROPERTIES RULE_LAUNCH_CUSTOM "env LD_FLAGS=\"-Ldir -Ldir2\"" )
Edit: Added examples for multiple quoted arguments without the need of escaping quotes
Another example would be to "hide some of the complexity" in a function and - if you want to add this to all your custom command calls - use the global/directory RULE_LAUNCH_CUSTOM property:
function(set_env) get_property(_env GLOBAL PROPERTY RULE_LAUNCH_CUSTOM) if (NOT _env) set_property(GLOBAL PROPERTY RULE_LAUNCH_CUSTOM "env") endif() foreach(_arg IN LISTS ARGN) set_property(GLOBAL APPEND_STRING PROPERTY RULE_LAUNCH_CUSTOM " ${_arg}") endforeach() endfunction(set_env) set_env(LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb") add_custom_target( MultipleEnvVar COMMAND env | grep -E 'LDFLAGS|CFLAGS' )
Alternative (for CMake >= 3.0)
I think what we actually are looking for here (besides the
cmake -E env ...) is named Bracket Argument and does allow any character without the need of adding backslashes:set_property( GLOBAL PROPERTY RULE_LAUNCH_CUSTOM [=[env LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb"]=] ) add_custom_target( MultipleEnvVarNew COMMAND env | grep -E 'LDFLAGS|CFLAGS' )
References
- 0005145: Set environment variables for ADD_CUSTOM_COMMAND/ADD_CUSTOM_TARGET
- How to modify environment variables passed to custom CMake target?
- [CMake] How to set environment variable for custom command
- cmake: when to quote variables?
回答2:
Ok, I removed my original answer as the one proposed by @Florian is better. There is one additional tweak needed for multiple quoted args. Consider a list of environment variables as such:
set(my_env_vars LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb")
In order to produce the desired expansion, convert to string and then replace ; with a space.
set(my_env_string "${my_env_vars}") #produces LDFLAGS="...";CFLAGS="..."
string(REPLACE ";" " " my_env_string "${my_env_string}")
Then you can proceed with @Florian's brilliant answer and add the custom launch rule. If you need semicolons in your string then you'll need to convert them to something else first.
Note that in this case I didn't need to launch with env:
set_target_properties(mytarget PROPERTIES RULE_LAUNCH_CUSTOM "${my_env_string}")
This of course depends on your shell.
On second thought, my original answer is below as I also have a case where I don't have access to the target name.
set(my_env LDFLAGS=\"-Ldir -Ldir2" CFLAGS=\"-Idira -Idirb\")
add_custom_command(COMMAND sh -c "${my_env} grep LDFLAGS" VERBATIM)
This technique still requires that the semicolons from the list->string conversion be replaced.
来源:https://stackoverflow.com/questions/39368525/how-do-i-include-a-literal-double-quote-in-a-custom-cmake-command