#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