Список CMake(ДОБАВИТЬ…) переключение прямой косой черты на обратную косую черту

#windows #cmake #ninja #cmake-language

Вопрос:

Я столкнулся с очень странной проблемой со списком CMake(ДОБАВИТЬ …). Мой сценарий следующий (просто пример):

 cmake_minimum_required(VERSION 3.20)
include(CMakePrintHelpers)

project(exe)
file(WRITE ${PROJECT_NAME}.cpp "#include <iostream>
#include "test1.h"
#include "test2.h"
void main() {
    std::cout << "Hello world!" << std::endl;
}")
add_executable(${PROJECT_NAME} "exe.cpp")

set(COMMANDS "echo /* empty file */ > test1.h"
             "echo /* empty file */ > test2.h")

foreach(CMD IN LISTS COMMANDS)
    list(APPEND CMDS COMMAND "cmd.exe /c "${CMD}"")
endforeach()

cmake_print_variables(PROJECT_NAME CMDS)
add_custom_target(${PROJECT_NAME}_headers1
                    ${CMDS}
                    BYPRODUCTS test1.h test2.h
                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                    VERBATIM)
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_headers1)

set(CMDS COMMAND cmd.exe /c "echo /* empty file */ > test1.h"
         COMMAND cmd.exe /c "echo /* empty file */ > test2.h")
cmake_print_variables(PROJECT_NAME CMDS)
add_custom_target(${PROJECT_NAME}_headers2
                    ${CMDS}
                    BYPRODUCTS test1.h test2.h
                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                    VERBATIM)
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_headers2)
 

Генерирование дает следующий результат:

 d:playcmake>cmake.exe -G"Ninja" -S. -B"build/ninja"
-- PROJECT_NAME="exe" ; CMDS="COMMAND;cmd.exe /c "echo /* empty file */ > test1.h";COMMAND;cmd.exe /c "echo /* empty file */ > test2.h""
-- PROJECT_NAME="exe" ; CMDS="COMMAND;cmd.exe;/c;echo /* empty file */ > test1.h;COMMAND;cmd.exe;/c;echo /* empty file */ > test2.h"
-- Configuring done
-- Generating done
-- Build files have been written to: D:/play/cmake/build/ninja
 

Я ожидал, что обе пользовательские цели будут выполнять одни и те же команды. Однако файл build.ninja обрабатывает каждую пользовательскую цель по-разному:

 #############################################
# Custom command for CMakeFilesexe_headers1

build CMakeFilesexe_headers1 test1.h test2.h: CUSTOM_COMMAND
  COMMAND = cmd.exe /C "cd /D D:playcmake amp;amp; PRE_BUILD amp;amp; "cmd.exe c "echo * empty file * > test1.h"" amp;amp; "cmd.exe c "echo * empty file * > test2.h"""
  restat = 1


#############################################
# Custom command for CMakeFilesexe_headers2

build CMakeFilesexe_headers2 test1.h test2.h: CUSTOM_COMMAND
  COMMAND = cmd.exe /C "cd /D D:playcmake amp;amp; PRE_BUILD amp;amp; cmd.exe /c "echo /* empty file */ > test1.h" amp;amp; cmd.exe /c "echo /* empty file */ > test2.h""
  restat = 1
 

Кто-нибудь знает, как запретить списку(ДОБАВИТЬ…) «переворачивать» косую черту («/») на обратную косую черту («»)? Что еще более странно, так это то, что на вывод cmake_print_variables(…) это не влияет.

Заранее спасибо. -Ури

Комментарии:

1.«Я ожидал, что обе пользовательские цели будут выполнять одни и те же команды». — А? Почему вы ожидаете, что цели будут выполнять одни и те же команды, когда даже вывод cmake_print_variables отличается? Как вы можете видеть, во втором выводе ; правильно разделяется исполняемый файл и все его аргументы. Но в первом выводе вся строка cmd.exe /c "echo /* empty file */ > test1.h интерпретируется как один параметр. Неправильно передавать такую строку, как COMMAND .

2. Это не то, о чем я говорю. Пожалуйста, обратите внимание, что exe_headers1-это «cmd.exe c «эхо * пустой файл * > test1.h» » …» и exe_headers2-это *cmd.exe /c «эхо /> пустой файл / > test1.h»…> . Косые черты перевернуты.

3. Да, я заметил, что в первом случае вы получили неожиданные обратные косые черты. Но исправление только этих косых черт имеет небольшой смысл: в этом случае вам нужно исправить неправильный параметр, который вы передали в качестве КОМАНДЫ. Это то, о чем говорилось в моем предыдущем комментарии.

4. Не уверен, имеет ли это какое-либо отношение к проблеме, но вы COMMAND add_custom_target ошиблись; программа и параметры являются отдельными записями списка, поэтому внутри foreach() вы должны использовать list(APPEND CMDS COMMAND cmd.exe /c ${CMD}) ; Кстати: я предпочитаю вызывать сценарии cmake для выполнения чего-то подобного генерации заголовка, так как это работает независимо от платформы COMMAND ${CMAKE_COMMAND} -P myScript.cmake