ExternalProject: Set environment variables

Add the ability to modify the environment of the various steps running
as part of an external project build. This specifically adds the ability
to set them on the configure , build , install, and test steps, as well
as exposing the `ENVIRONMENT_MODIFICATION` keyword arguments to
`ExternalProject_Add_Step`, allowing customization of the environment of
custom steps.

The values of the environment variable respect the `LIST_SEPARATOR`.

Fixes: #26963
This commit is contained in:
Evan Wilde
2025-04-09 00:06:58 -07:00
committed by Brad King
parent ff21c3f78a
commit e301cbffcc
11 changed files with 363 additions and 1 deletions

View File

@@ -654,6 +654,48 @@ overridden if required.
examples of build systems whose build step is smart enough to know if the
configure step needs to be rerun.
``CONFIGURE_ENVIRONMENT_MODIFICATION <modification>...``
.. versionadded: 4.2
Specify environment variables that should be modified for the configure step.
Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
case-sensitive name of an environment variable to be modified. Entries are
considered in the order specified in the property's value. The ``OP`` may be
one of:
.. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
.. code-block:: cmake
ExternalProject_Add(example
... # Download options, etc...
CONFIGURE_ENVIRONMENT_MODIFICATION
SDKROOT=set:macosx
PKG_CONFIG_PATH=set:$ENV{PKG_CONFIG_PATH}
)
This snippet defines two environment variables when configuring the example
project. The ``SDKROOT`` environment variable is set to ``macosx`, while
the value of ``PKG_CONFIG_PATH`` is forwarded to the external project.
Environment modifications work with ``LIST_SEPARATOR`` to replace the
separator with a ``;`` in the environment variable.
.. code-block:: cmake
ExternalProject_Add(example
... # Download options, etc...
LIST_SEPARATOR ,
CONFIGURE_ENVIRONMENT_MODIFICATION
LIST_VAR=set:a,b,c
)
This snippet
and the environment variable ``LIST_VAR`` is passed to the configure command
invocation with the value ``a;b;c``.
Build Step Options
""""""""""""""""""
@@ -719,6 +761,19 @@ pass ``-v`` to the external project's build step, even if it also uses
``JOB_SERVER_AWARE`` option for details. This option is relevant
only when an explicit ``BUILD_COMMAND`` is specified.
``BUILD_ENVIRONMENT_MODIFICATION <modification>...``
.. versionadded: 4.2
Specify environment variables that should be modified for the build step.
Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
case-sensitive name of an environment variable to be modified. Entries are
considered in the order specified in the property's value. The ``OP`` may be
one of:
.. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
Install Step Options
""""""""""""""""""""
@@ -777,6 +832,19 @@ step. This can be overridden with custom install commands if required.
:envvar:`CMAKE_INSTALL_MODE` environment variable changes from one run
to another.
``INSTALL_ENVIRONMENT_MODIFICATION <modification>...``
.. versionadded: 4.2
Specify environment variables that should be modified for the install step.
Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
case-sensitive name of an environment variable to be modified. Entries are
considered in the order specified in the property's value. The ``OP`` may be
one of:
.. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
Test Step Options
"""""""""""""""""
@@ -815,6 +883,19 @@ options are provided.
This may cause a step target to be created automatically for either
the ``install`` or ``build`` step. See policy :policy:`CMP0114`.
``TEST_ENVIRONMENT_MODIFICATION <modification>...``
.. versionadded: 4.2
Specify environment variables that should be modified for the test step.
Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
case-sensitive name of an environment variable to be modified. Entries are
considered in the order specified in the property's value. The ``OP`` may be
one of:
.. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
Output Logging Options
""""""""""""""""""""""
@@ -940,7 +1021,8 @@ Miscellaneous Options
"""""""""""""""""""""
``LIST_SEPARATOR <sep>``
For any of the various ``..._COMMAND`` options, and ``CMAKE_ARGS``,
For any of the various ``..._COMMAND`` options, ``CMAKE_ARGS``, and
`..._ENVIRONMENT_MODIFICATION`` operations,
``ExternalProject`` will replace ``<sep>`` with ``;`` in the specified
command lines. This can be used to ensure a command has a literal ``;`` in it
where direct usage would otherwise be interpreted as argument separators to
@@ -1043,6 +1125,20 @@ control needed to implement such step-level capabilities.
``DEPENDS <file>...``
Files on which this custom step depends.
``ENVIRONMENT_MODIFICATION <modification>...``
.. versionadded: 4.2
Specify environment variables that should be modified while running the
commands in the external project step.
Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
case-sensitive name of an environment variable to be modified. Entries are
considered in the order specified in the property's value. The ``OP`` may be
one of:
.. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
``INDEPENDENT <bool>``
.. versionadded:: 3.19
@@ -2057,6 +2153,7 @@ function(ExternalProject_Add_Step name step)
DEPENDEES
DEPENDERS
DEPENDS
ENVIRONMENT_MODIFICATION
INDEPENDENT
BYPRODUCTS
ALWAYS
@@ -2176,6 +2273,50 @@ function(ExternalProject_Add_Step name step)
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")
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")
set(_result "")
list(APPEND _result "${CMAKE_COMMAND}" -E env ${environment} --)
foreach(element IN LISTS command)
list(APPEND _result "${element}")
if("${element}" STREQUAL COMMAND)
list(APPEND _result "${CMAKE_COMMAND}" -E env ${environment} --)
endif()
endforeach()
set(command ${_result})
endif()
# Replace location tags.
_ep_replace_location_tags(
${name}
@@ -2660,6 +2801,14 @@ function(_ep_add_configure_command name)
set(dependees patch)
endif()
get_property(environment
TARGET ${name}
PROPERTY _EP_CONFIGURE_ENVIRONMENT_MODIFICATION
)
if(environment)
set(environment "ENVIRONMENT_MODIFICATION" ${environment})
endif()
get_property(log
TARGET ${name}
PROPERTY _EP_LOG_CONFIGURE
@@ -2691,6 +2840,7 @@ function(_ep_add_configure_command name)
WORKING_DIRECTORY \${binary_dir}
DEPENDEES \${dependees}
DEPENDS \${file_deps}
${environment}
${log}
${uses_terminal}
)"
@@ -2770,6 +2920,13 @@ function(_ep_add_build_command name)
set(maybe_JOB_SERVER_AWARE "")
endif()
get_property(environment
TARGET ${name}
PROPERTY _EP_BUILD_ENVIRONMENT_MODIFICATION
)
if(environment)
set(environment ENVIRONMENT_MODIFICATION ${environment})
endif()
set(__cmdQuoted)
foreach(__item IN LISTS cmd)
@@ -2785,6 +2942,7 @@ function(_ep_add_build_command name)
DEPENDS \${file_deps}
ALWAYS \${always}
${maybe_JOB_SERVER_AWARE}
${environment}
${log}
${uses_terminal}
)"
@@ -2857,6 +3015,14 @@ function(_ep_add_install_command name)
set(maybe_JOB_SERVER_AWARE "")
endif()
get_property(environment
TARGET ${name}
PROPERTY _EP_INSTALL_ENVIRONMENT_MODIFICATION
)
if(environment)
set(environment ENVIRONMENT_MODIFICATION ${environment})
endif()
set(__cmdQuoted)
foreach(__item IN LISTS cmd)
string(APPEND __cmdQuoted " [==[${__item}]==]")
@@ -2870,6 +3036,7 @@ function(_ep_add_install_command name)
DEPENDEES build
ALWAYS \${always}
${maybe_JOB_SERVER_AWARE}
${environment}
${log}
${uses_terminal}
)"
@@ -2936,6 +3103,14 @@ function(_ep_add_test_command name)
set(uses_terminal "")
endif()
get_property(environment
TARGET ${name}
PROPERTY _EP_TEST_ENVIRONMENT_MODIFICATION
)
if(environment)
set(environment ENVIRONMENT_MODIFICATION ${environment})
endif()
set(__cmdQuoted)
foreach(__item IN LISTS cmd)
string(APPEND __cmdQuoted " [==[${__item}]==]")
@@ -2948,6 +3123,7 @@ function(_ep_add_test_command name)
${dependees_args}
${dependers_args}
${exclude_args}
${environment}
${log}
${uses_terminal}
)"