Как включить буквальную двойную кавычку в пользовательскую команду 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" ...

Это сработало для меня.

Другие вопросы по тегам