refactor empty argument passing to not require eval

This commit is contained in:
Lars Melchior
2023-04-13 17:49:13 +02:00
parent f4fd660d09
commit a49358ef34
3 changed files with 92 additions and 64 deletions

View File

@@ -505,50 +505,70 @@ function(cpm_override_fetchcontent contentName)
set_property(GLOBAL PROPERTY ${propertyName} TRUE)
endfunction()
macro(cpm_cmake_eval)
set(__ARGN "${ARGN}")
if(COMMAND cmake_language)
cmake_language(EVAL CODE "${__ARGN}")
# replaces empty arguments with a placeholder to compensate CMake issues with handling empty
# arguments
function(cpm_encode_empty_arguments args outVar)
set(out "")
# note: we don't use string replacement for ';;' -> ';__CPM_EMPTY_ARG;' here, as it would
# interfere with nested arguments
foreach(ARG IN LISTS args)
if(NOT out STREQUAL "")
string(APPEND out ";")
endif()
if(ARG STREQUAL "")
string(APPEND out "__CPM_EMPTY_ARG")
else()
# prevent escaped characters from getting resolved early
string(REPLACE "\\" "\\\\\\" ARG "${ARG}")
string(APPEND out "${ARG}")
endif()
endforeach()
set("${outVar}"
"${out}"
PARENT_SCOPE
)
endfunction()
function(cpm_decode_empty_argument arg outVar)
if("${arg}" STREQUAL "__CPM_EMPTY_ARG")
set("${outVar}"
""
PARENT_SCOPE
)
else()
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake "${__ARGN}")
include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake)
set("${outVar}"
"${arg}"
PARENT_SCOPE
)
endif()
endmacro()
endfunction()
# replaces placeholder arguments from `cpm_encode_empty_arguments` with empty arguments
function(cpm_decode_empty_arguments args outVar)
set(out "")
foreach(ARG IN LISTS args)
if(NOT out STREQUAL "")
string(APPEND out ";")
endif()
cpm_decode_empty_argument("${ARG}" ARG)
string(APPEND out "${ARG}")
endforeach()
set("${outVar}"
"${out}"
PARENT_SCOPE
)
endfunction()
# Download and add a package from source
macro(CPMAddPackage)
set(__ARGN "${ARGN}")
list(LENGTH __ARGN __ARGN_Length)
if(__ARGN_Length EQUAL 1)
cpm_add_package_single_arg(${ARGN})
else()
# Forward preserving empty string arguments
# (https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4729)
set(__ARGN_Quoted)
foreach(__ARG IN LISTS __ARGN)
string(APPEND __ARGN_Quoted " [==[${__ARG}]==]")
endforeach()
cpm_cmake_eval("cpm_add_package_multi_arg( ${__ARGN_Quoted} )")
function(CPMAddPackage)
cpm_set_policies()
list(LENGTH ARGN argnLength)
if(argnLength EQUAL 1)
cpm_parse_add_package_single_arg("${ARGN}" ARGN)
# The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM
set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;")
endif()
endmacro()
macro(cpm_add_package_single_arg arg)
cpm_set_policies()
cpm_parse_add_package_single_arg("${arg}" __ARGN_multi)
# The shorthand syntax implies EXCLUDE_FROM_ALL
# cmake-format: off
list(APPEND __ARGN_multi
EXCLUDE_FROM_ALL YES
SYSTEM YES
)
# cmake-format: on
cpm_add_package_multi_arg(${__ARGN_multi}) # Forward function arguments to CPMAddPackage()
endmacro()
function(cpm_add_package_multi_arg)
cpm_set_policies()
set(oneValueArgs
NAME
@@ -572,10 +592,26 @@ function(cpm_add_package_multi_arg)
set(multiValueArgs URL OPTIONS)
cmake_parse_arguments(PARSE_ARGV 0 CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}")
# Encode arguments for `cmake_parse_arguments`
cpm_encode_empty_arguments("${ARGN}" "PARSE_ARGS")
# Parse arguments
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${PARSE_ARGS}")
# Decode arguments
foreach(ARG IN LISTS oneValueArgs)
if(DEFINED CPM_ARGS_${ARG})
cpm_decode_empty_argument("${CPM_ARGS_${ARG}}" CPM_ARGS_${ARG})
endif()
endforeach()
foreach(ARG IN LISTS multiValueArgs)
if(DEFINED CPM_ARGS_${ARG})
cpm_decode_empty_arguments("${CPM_ARGS_${ARG}}" CPM_ARGS_${ARG})
endif()
endforeach()
cpm_decode_empty_arguments("${CPM_ARGS_UNPARSED_ARGUMENTS}" CPM_ARGS_UNPARSED_ARGUMENTS)
# Set default values for arguments
if(NOT DEFINED CPM_ARGS_VERSION)
if(DEFINED CPM_ARGS_GIT_TAG)
cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION)
@@ -949,14 +985,7 @@ function(cpm_declare_fetch PACKAGE VERSION INFO)
cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)")
return()
endif()
# Forward preserving empty string arguments
# (https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4729)
set(__argsQuoted)
foreach(__item IN LISTS ARGN)
string(APPEND __argsQuoted " [==[${__item}]==]")
endforeach()
cpm_cmake_eval("FetchContent_Declare(${PACKAGE} ${__argsQuoted} )")
FetchContent_Declare(${PACKAGE} "${ARGN}")
endfunction()
# returns properties for a package previously defined by cpm_declare_fetch

View File

@@ -3,6 +3,18 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
include(${CPM_PATH}/CPM.cmake)
include(${CPM_PATH}/testing.cmake)
set(input "a;;b;c;;;;def;g;;")
cpm_encode_empty_arguments("${input}" encoded)
foreach(arg IN LISTS encoded)
assert_not_equal("${arg}" "")
endforeach()
assert_equal("${contains_empty_arg}" "")
cpm_decode_empty_arguments("${encoded}" decoded)
assert_equal("${decoded}" "${input}")
# ignore source cache if set
set(CPM_SOURCE_CACHE "")
# Intercept underlying `FetchContent_Declare`
function(FetchContent_Declare)
set_property(GLOBAL PROPERTY last_FetchContent_Declare_ARGN "${ARGN}")
@@ -38,21 +50,6 @@ assert_equal(
"fibonacci;EMPTY_OPTION;;COMMAND_WITH_EMPTY_ARG;foo;;bar;GIT_REPOSITORY;https://github.com/cpm-cmake/testpack-fibonacci.git;GIT_TAG;v1.2.3"
)
# Intercept underlying `cpm_add_package_multi_arg`
function(cpm_add_package_multi_arg)
set_property(GLOBAL PROPERTY last_cpm_add_package_multi_arg_ARGN "${ARGN}")
endfunction()
# TEST: CPM Module file shall store all arguments including empty strings
include(${CPM_MODULE_PATH}/Findfibonacci.cmake)
get_property(
last_cpm_add_package_multi_arg_ARGN GLOBAL PROPERTY last_cpm_add_package_multi_arg_ARGN
)
assert_equal(
"${last_cpm_add_package_multi_arg_ARGN}"
"NAME;fibonacci;GIT_REPOSITORY;https://github.com/cpm-cmake/testpack-fibonacci.git;VERSION;1.2.3;EMPTY_OPTION;;COMMAND_WITH_EMPTY_ARG;foo;;bar"
)
# remove generated files
file(REMOVE_RECURSE ${CPM_MODULE_PATH})
file(REMOVE ${CPM_PACKAGE_LOCK_FILE})

View File

@@ -2,6 +2,8 @@ include(CMakePackageConfigHelpers)
include(${CPM_PATH}/testing.cmake)
set(TEST_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/source_dir)
# clean existing build if it exists
file(REMOVE_RECURSE "${TEST_BUILD_DIR}")
set(TEST_DEPENDENCY_NAME Dependency)