mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-09 23:59:53 -05:00
ExternalProject: Fix lists and empty commands with environment modification
Fix two bugs from commit e301cbffcc (ExternalProject: Set environment
variables, 2025-04-09):
* Do not flatten lists in command arguments when adding env mods.
* Remove empty `COMMAND`s without injecting corresponding env mods.
Fixes: #27125
Fixes: #27126
Co-authored-by: Brad King <brad.king@kitware.com>
This commit is contained in:
@@ -2273,60 +2273,50 @@ function(ExternalProject_Add_Step name step)
|
||||
PROPERTY _EP_${step}_WORKING_DIRECTORY
|
||||
)
|
||||
|
||||
# Replace list separators.
|
||||
# Replace list separators and inject environment modifications.
|
||||
get_property(sep
|
||||
TARGET ${name}
|
||||
PROPERTY _EP_LIST_SEPARATOR
|
||||
)
|
||||
if(sep AND command)
|
||||
string(REPLACE "${sep}" "\\;" command "${command}")
|
||||
endif()
|
||||
|
||||
# Add environment here!
|
||||
get_property(environment
|
||||
TARGET ${name}
|
||||
PROPERTY _EP_${step}_ENVIRONMENT_MODIFICATION)
|
||||
if(environment AND command)
|
||||
if("${sep}" STREQUAL ":")
|
||||
# The environment modification operation and value is separated by a
|
||||
# colon. We should not replace that colon with a semicolon, allowing
|
||||
# colons to act as a valid list separator.
|
||||
# <name>=<op>:<value>
|
||||
# Note: Environment variable names can contain `:` on Windows
|
||||
set(result "")
|
||||
foreach(env_modification IN LISTS environment)
|
||||
if("${env_modification}" MATCHES "(.*)=([a-z]*):(.*)?")
|
||||
if(CMAKE_MATCH_COUNT EQUAL 3)
|
||||
string(REPLACE "${sep}" "\\\\\\\\\\;" _escapedMod "${CMAKE_MATCH_3}")
|
||||
endif()
|
||||
list(APPEND result "${CMAKE_MATCH_1}=${CMAKE_MATCH_2}:${_escapedMod}")
|
||||
else()
|
||||
message(SEND_ERROR "Malformed environment modification specifier:"
|
||||
" '${env_modification}'\n"
|
||||
"Expected MYVAR=OP:VALUE")
|
||||
PROPERTY _EP_${step}_ENVIRONMENT_MODIFICATION
|
||||
)
|
||||
if(environment)
|
||||
set(env_args "")
|
||||
foreach(env_mod IN LISTS environment)
|
||||
if(env_mod MATCHES [[^([^=:]+)=([a-z]+):(.*)$]])
|
||||
set(_value "${CMAKE_MATCH_3}")
|
||||
# Replace the separator only in the value in case it is `:`.
|
||||
if(sep)
|
||||
string(REPLACE "${sep}" [[\;]] _value "${_value}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(environment ${result})
|
||||
elseif(sep)
|
||||
# if the separator is not a colon, we don't have to worry about
|
||||
# accidentally replacing the separator between the modification and value
|
||||
string(REPLACE "${sep}" "\\\\\\\\;" environment "${environment}")
|
||||
endif()
|
||||
list(JOIN environment ";--modify;" environment)
|
||||
list(PREPEND environment "--modify")
|
||||
|
||||
string(REPLACE ";" "\;" command "${command}")
|
||||
string(REPLACE "COMMAND" ";" command "${command}")
|
||||
|
||||
set(__cmd)
|
||||
foreach(__item IN LISTS command)
|
||||
list(APPEND __cmd "COMMAND")
|
||||
if(__item AND NOT "x${__item}" STREQUAL "x;;")
|
||||
list(APPEND __cmd "${CMAKE_COMMAND}" -E env ${environment} --)
|
||||
list(APPEND env_args --modify "${CMAKE_MATCH_1}=${CMAKE_MATCH_2}:${_value}")
|
||||
else()
|
||||
message(SEND_ERROR "Malformed environment modification specifier:"
|
||||
" '${env_mod}'\n"
|
||||
"Expected MYVAR=OP:VALUE")
|
||||
endif()
|
||||
list(APPEND __cmd "${__item}")
|
||||
endforeach()
|
||||
set(command ${__cmd})
|
||||
set(env_command "${CMAKE_COMMAND};-E;env;${env_args};--")
|
||||
else()
|
||||
set(env_command "")
|
||||
endif()
|
||||
if(command)
|
||||
if(env_command)
|
||||
# Strip empty commands so we do not add env for them.
|
||||
string(REGEX REPLACE [[^COMMAND;+(COMMAND;+)*]] "" command "${command}")
|
||||
string(REGEX REPLACE [[;COMMAND;+(COMMAND;+)*]] ";COMMAND;" command "${command}")
|
||||
# Replace the separator with an extra escape to survive list(TRANSFORM).
|
||||
if(sep)
|
||||
string(REPLACE "${sep}" [[\\;]] command "${command}")
|
||||
endif()
|
||||
# Prepend every command with our environment modification launcher.
|
||||
list(TRANSFORM command APPEND ";${env_command}" REGEX "^COMMAND$")
|
||||
set(command "${env_command};${command}")
|
||||
elseif(sep)
|
||||
string(REPLACE "${sep}" [[\;]] command "${command}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Replace location tags.
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
.*(Performing configure step for 'CustomCommand'|CustomCommand-configure).*
|
||||
*-- Stage: config
|
||||
*-- Separator: ;
|
||||
*-- List: 4;5;6.*
|
||||
*-- List: 4;5;6
|
||||
*-- MYLIST:
|
||||
*-- -- a
|
||||
*-- -- b
|
||||
*-- -- c.*
|
||||
*-- Variable - Stage: config.*
|
||||
*-- Variable - ListVar: 4;5;6
|
||||
.*(Performing build step for 'CustomCommand'|CustomCommand-build).*
|
||||
@@ -30,3 +34,12 @@
|
||||
*-- Stage: build
|
||||
*-- Separator: ,
|
||||
*-- List: 7,8,9,10
|
||||
.*(Performing configure step for 'DefaultCommandListSep'|DefaultCommandListSep-configure).*
|
||||
*-- ConfigVar: config
|
||||
*-- Separator: ;
|
||||
*-- List: 9;8;7
|
||||
*-- MYLIST:
|
||||
*-- -- d
|
||||
*-- -- e
|
||||
*-- -- f
|
||||
*-- -- g
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
.*(Performing configure step for 'CustomCommand'|CustomCommand-configure).*
|
||||
*-- Stage: config
|
||||
*-- Separator: ;
|
||||
*-- List: 4;5;6.*
|
||||
*-- List: 4;5;6
|
||||
*-- MYLIST:
|
||||
*-- -- a
|
||||
*-- -- b
|
||||
*-- -- c.*
|
||||
*-- Variable - Stage: config.*
|
||||
*-- Variable - ListVar: 4;5;6
|
||||
.*(Performing build step for 'CustomCommand'|CustomCommand-build).*
|
||||
@@ -31,14 +35,23 @@
|
||||
*-- Separator: ,
|
||||
*-- List: 7,8,9,10
|
||||
.*(Performing configure step for 'DefaultCommandListSep'|DefaultCommandListSep-configure).*
|
||||
*-- ConfigVar: config
|
||||
*-- Separator: ;
|
||||
*-- List: 9;8;7
|
||||
*-- MYLIST:
|
||||
*-- -- d
|
||||
*-- -- e
|
||||
*-- -- f
|
||||
*-- -- g
|
||||
.*(Performing configure step for 'DefaultCommandListColon'|DefaultCommandListColon-configure).*
|
||||
*-- ConfigVar: config
|
||||
*-- Separator: ;
|
||||
*-- List: 10;11;12
|
||||
.*(Performing build step for 'DefaultCommandListSep'|DefaultCommandListSep-build).*
|
||||
.*(Performing build step for 'DefaultCommandListColon'|DefaultCommandListColon-build).*
|
||||
*-- Stage: build
|
||||
*-- Separator: ;
|
||||
*-- List: 10;11;12
|
||||
.*(Performing install step for 'DefaultCommandListSep'|DefaultCommandListSep-install).*
|
||||
.*(Performing install step for 'DefaultCommandListColon'|DefaultCommandListColon-install).*
|
||||
*-- Stage: install
|
||||
*-- Separator: ;
|
||||
*-- List: 10;11;12;13
|
||||
|
||||
@@ -12,9 +12,13 @@ ExternalProject_Add(CustomCommand
|
||||
PATCH_COMMAND ""
|
||||
LIST_SEPARATOR ,
|
||||
CONFIGURE_COMMAND ""
|
||||
COMMAND "${CMAKE_COMMAND}" -P ${ScriptPath}
|
||||
COMMAND
|
||||
COMMAND "${CMAKE_COMMAND}" -DMYLIST='a,b,c' -P ${ScriptPath}
|
||||
COMMAND "${CMAKE_COMMAND}" -DVARNAME=Stage -P ${ScriptPath}
|
||||
COMMAND ""
|
||||
COMMAND COMMAND COMMAND
|
||||
COMMAND "${CMAKE_COMMAND}" -E echo "" ""
|
||||
COMMAND
|
||||
COMMAND "${CMAKE_COMMAND}" -DVARNAME=ListVar -P ${ScriptPath}
|
||||
CONFIGURE_ENVIRONMENT_MODIFICATION
|
||||
Stage=set:config
|
||||
@@ -75,17 +79,34 @@ ExternalProject_Add(DefaultCommand
|
||||
Stage=set:install
|
||||
Separator=set:,)
|
||||
|
||||
ExternalProject_Add(DefaultCommandListSep
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/EnvVars"
|
||||
DOWNLOAD_COMMAND ""
|
||||
UPDATE_COMMAND ""
|
||||
PATCH_COMMAND ""
|
||||
DEPENDS DefaultCommand
|
||||
LIST_SEPARATOR `
|
||||
CMAKE_ARGS
|
||||
-DVARIABLE=ConfigVar
|
||||
-DMYLIST=d`e`f`g
|
||||
CONFIGURE_ENVIRONMENT_MODIFICATION
|
||||
ConfigVar=set:config
|
||||
ListVar=set:9`8`7
|
||||
ListSeparator=set:`
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# Using `:` as a list separator on Windows does not work as it replaces the `:`
|
||||
# between the drive letter and the filepath with `;`.
|
||||
if(NOT WIN32)
|
||||
# Ensure that using `:` as a list-separator does not break setting environment
|
||||
# variables
|
||||
ExternalProject_Add(DefaultCommandListSep
|
||||
ExternalProject_Add(DefaultCommandListColon
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/EnvVars"
|
||||
DOWNLOAD_COMMAND ""
|
||||
UPDATE_COMMAND ""
|
||||
PATCH_COMMAND ""
|
||||
DEPENDS DefaultCommand
|
||||
DEPENDS DefaultCommandListSep
|
||||
LIST_SEPARATOR :
|
||||
CMAKE_ARGS
|
||||
-DVARIABLE=ConfigVar
|
||||
|
||||
@@ -6,6 +6,13 @@ message(STATUS "${VARIABLE}: $ENV{${VARIABLE}}")
|
||||
message(STATUS "Separator: $ENV{ListSeparator}")
|
||||
message(STATUS "List: $ENV{ListVar}")
|
||||
|
||||
if(MYLIST)
|
||||
message(STATUS "MYLIST:")
|
||||
foreach(__item IN LISTS MYLIST)
|
||||
message(STATUS "-- ${__item}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
add_custom_target(EchoEnvVars ALL COMMENT "Build environment..."
|
||||
COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_SOURCE_DIR}/EchoVar.cmake")
|
||||
|
||||
|
||||
@@ -5,3 +5,10 @@ else()
|
||||
message(STATUS "Separator: $ENV{ListSeparator}")
|
||||
message(STATUS "List: $ENV{ListVar}")
|
||||
endif()
|
||||
|
||||
if(MYLIST)
|
||||
message(STATUS "MYLIST:")
|
||||
foreach(__item IN LISTS MYLIST)
|
||||
message(STATUS "-- ${__item}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
Reference in New Issue
Block a user