Как включить буквальную двойную кавычку в пользовательскую команду CMake?
Я пытаюсь создать пользовательскую команду, которая запускается с некоторыми переменными среды, такими как LDFLAGS, значение которой необходимо заключать в кавычки, если оно содержит пробелы:
LDFLAGS="-Lmydir -Lmyotherdir"
Я не могу найти способ включить этот аргумент в пользовательскую команду CMake из-за правил выхода из CMake. Вот что я пробовал до сих пор:
COMMAND LDFLAGS="-Ldir -Ldir2" echo blah VERBATIM)
доходность "LDFLAGS=\"-Ldir -Ldir2\"" echo blah
COMMAND LDFLAGS=\"-Ldir -Ldir2\" echo blah VERBATIM)
доходность LDFLAGS=\"-Ldir -Ldir2\" echo blah
Кажется, я либо получаю всю строку в кавычках, либо экранированные кавычки не разрешаются, когда используются как часть команды.
Я был бы признателен либо за способ включения буквальных двойных кавычек, либо как за альтернативу лучший способ установить переменные окружения для команды. Обратите внимание, что я все еще на CMake 2.8, поэтому у меня нет новой команды env, доступной в 3.2.
Обратите внимание, что это не дубликат Когда кавычки переменных? поскольку ни один из этих методов цитирования не работает в данном конкретном случае.
5 ответов
Очевидный выбор - часто рекомендуется при попадании за границы COMMAND
особенно с более старыми версиями CMake - это использовать внешний скрипт.
Я просто хотел добавить несколько простых COMMAND
только варианты, которые работают и не нуждаются в оболочке, но, я должен признать, все еще частично зависят от платформы.
Один из примеров - поместить в переменную только часть в кавычках:
set(vars_as_string "-Ldir -Ldir2") add_custom_target( QuotedEnvVar COMMAND env LD_FLAGS=${vars_as_string} | grep LD_FLAGS )
Который на самом деле избегает места, а не кавычки.
Другим примером может быть добавление его с экранированными кавычками в качестве правила запуска:
add_custom_target( LauncherEnvVar COMMAND env | grep LD_FLAGS ) set_target_properties( LauncherEnvVar PROPERTIES RULE_LAUNCH_CUSTOM "env LD_FLAGS=\"-Ldir -Ldir2\"" )
Изменить: Добавлены примеры для нескольких аргументов в кавычках без необходимости экранирования кавычек
Другим примером может быть "скрыть некоторую сложность" в функции и - если вы хотите добавить это ко всем вызовам пользовательских команд - используйте каталог global /
RULE_LAUNCH_CUSTOM
имущество: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' )
Альтернатива (для CMake >= 3.0)
Я думаю, что мы на самом деле ищем здесь (кроме
cmake -E env ...
) называется Bracket Argument и допускает любой символ без добавления обратной косой черты:set_property( GLOBAL PROPERTY RULE_LAUNCH_CUSTOM [=[env LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb"]=] ) add_custom_target( MultipleEnvVarNew COMMAND env | grep -E 'LDFLAGS|CFLAGS' )
Рекомендации
Вам нужно три обратных слеша. Мне это понадобилось недавно, чтобы получить определение препроцессора из PkgConfig и применить его к моим флагам C++:
pkg_get_variable(SHADERDIR movit shaderdir)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSHADERDIR=\\\"${SHADERDIR}\\\"")
Ответ Флориана неверен по нескольким причинам:
- Помещение указанной части в переменную не имеет значения.
- Вам обязательно стоит использовать
VERBATIM
. Он исправляет ошибки цитирования, специфичные для платформы. - Вы определенно не должны использовать
RULE_LAUNCH_CUSTOM
за это. Он не предназначен для этого и работает только с некоторыми генераторами. - Вы не должны использовать
env
как команду. Он недоступен в Windows.
Оказывается, настоящая причина, по которой код OP не работает, заключается в том, что CMake всегда полностью цитирует первое слово после
COMMAND
потому что это должно быть имя исполняемого файла. Вы просто не должны ставить переменные среды на первое место.
Например:
add_custom_command(
OUTPUT q1.txt
COMMAND ENV_VAR="a b" echo "hello" > q1.txt
VERBATIM
)
add_custom_target(q1 ALL DEPENDS q1.txt)
$ VERBOSE=1 make
...
"ENV_VAR=\"a b\"" echo hello > q1.txt
/bin/sh: ENV_VAR="a b": command not found
Итак, как передать переменную среды с пробелами? Простой.
add_custom_command(
OUTPUT q1.txt
COMMAND ${CMAKE_COMMAND} -E env ENV_VAR="a b" echo "hello" > q1.txt
VERBATIM
)
Хорошо, я удалил свой первоначальный ответ, так как предложенный @Florian лучше. Существует одна дополнительная настройка, необходимая для нескольких аргументов в кавычках. Рассмотрим список переменных среды как таковой:
set(my_env_vars LDFLAGS="-Ldir1 -Ldir2" CFLAGS="-Idira -Idirb")
Чтобы произвести желаемое расширение, преобразуйте в строку, а затем замените ;
с пробелом.
set(my_env_string "${my_env_vars}") #produces LDFLAGS="...";CFLAGS="..."
string(REPLACE ";" " " my_env_string "${my_env_string}")
Затем вы можете приступить к блестящему ответу @ Florian и добавить собственное правило запуска. Если вам нужны точки с запятой в вашей строке, вам нужно сначала преобразовать их во что-то другое.
Обратите внимание, что в этом случае мне не нужно было запускать с env
:
set_target_properties(mytarget PROPERTIES RULE_LAUNCH_CUSTOM "${my_env_string}")
Это, конечно, зависит от вашей оболочки.
Если подумать, мой оригинальный ответ ниже, так как у меня также есть случай, когда у меня нет доступа к целевому имени.
set(my_env LDFLAGS=\"-Ldir -Ldir2" CFLAGS=\"-Idira -Idirb\")
add_custom_command(COMMAND sh -c "${my_env} grep LDFLAGS" VERBATIM)
Этот метод по-прежнему требует замены точек с запятой в преобразовании list->string.
Некоторые люди предлагают использовать ${CMAKE_COMMAND} и передать свой исполняемый файл в качестве аргумента, например:
COMMAND ${CMAKE_COMMAND} -E env "$(WindowsSdkDir)/bin/x64/makecert.exe" ...
Это сработало для меня.