How to transfer existing cmdline params to ExternalProject_Add?

We using some 3-rd party components in the project, which are built from sources and then cached in order to avoid unnecessary rebuilding.
That is done by simple logic, as

find_package (foo QUIET)
if (NOT foo_FOUND)
... configure external project file from template
... build & install configured project into predefined prefix
... add that prefix to CMAKE_PREFIX_PATH, or to CMAKE_FIND_ROOT_PATH
find_package (foo REQUIRED)

External project for caching is configured from template like

cmake_minimum_required ( VERSION 3.17 )

project ( @module@-prebuild NONE )
include ( ExternalProject )

ExternalProject_Add ( @module@_populate
	BUILD_COMMAND "@CMAKE_COMMAND@" -E echo "Starting build config ${BUILD_TYPE}"
	COMMAND "@CMAKE_COMMAND@" --build . --config RelWithDebInfo
	COMMAND "@CMAKE_COMMAND@" --install . --config RelWithDebInfo --prefix "@MODULE_BUILD@"

# file configured from cmake/

Template is used to create real config and then build (in config-time) with a clause like this:

	configure_file ( ${module}-build/CMakeLists.txt @ONLY )
	execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${module}-build)

It works perfectly with native build. Produced artifacts includes cmake exports, so that find_package then found them without rebuilding.
It works also perfectly with cross-compiling, if toolchain is passed via env CMAKE_TOOLCHAIN_FILE (since all sub-processes see the same env and so, implicitly use same toolchain)

Problem is cross-compile which happens from outside which we can’t control. I’ve tried to build for openwrt and faced with the fact, that it passes params to cmake as cmd-line params, i.e. not via env variables. Call looks like cmake -DCMAKE_SYSTEM_PROCESSOR=mips -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE="-DNDEBUG" -DCMAKE_C_COMPILER="/Volumes/OpenWrt/openwrt/staging_dir/toolchain-mips_24kc_gcc-11.2.0_musl/bin/mips-openwrt-linux-musl-gcc"… (and many others, about 5K of text).

I want to grab someway this params, and then pass them for configuring external project with the same environments.

Official docs just says, that cmake just pass several params, and you need to add others yourself, but I found no obvious way to take these ‘others’.

As ad-hoc I can, of course, accurate take the params from that call line, and pass them one-by-one into external_project, as -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} and so on, but it looks really dirty and fragile (if on update it pass yet another param - we just don’t have it in our hard-coded list, and will lose it).

May be a way exists to access original params which was used calling cmake, to grab them? Like kind of iteration over cmake’s cache before ‘project’ statement, or anything else?

Just made working solution, or, well, ‘ad hoc’, not true solution.

get_cmake_property ( CACHE_VARS CACHE_VARIABLES )
file ( WRITE "${CMAKE_BINARY_DIR}/cmd.cmake" "# Original cmdline-provided cache\n" )
	if (CACHE_VAR_HELPSTRING STREQUAL "No help, variable specified on the command line.")
		file ( APPEND "${CMAKE_BINARY_DIR}/cmd.cmake" "set (${CACHE_VAR} \n\"${${CACHE_VAR}}\"\n CACHE STRING \"No help, variable specified on the command line.\" FORCE )\n" )
	endif ()
endforeach ()

Values is then plugged to external project configuration via

CMAKE_ARGS -C "${CMAKE_BINARY_DIR}/cmd.cmake" ...

(passing via list instead of file not so obvious, as params themselves freely use ; and ", which make extra confusion when passing. File ‘just works’)

Cmake does have a load_cache command, and also a couple of variables that define a script cmake should load before processing a project (which basically allows code injection).

So what I would do is write a script to be loaded by the child project, which simply contains: load_cache("@CACHE_FILE@")

Then from the top level project:


configure_file (loader.cmake loader.cmake)

ExternalProject_Add (...

Yes, but this is exactly what ‘-C’ flag does, without intervention into child’s code.
More interesting is the content of such cache. Let each child make it’s own investigation; I just want to transfer what was passed via cmdline to the parent, and even more concrete - different CMAKE_* variables.

No there is no way to do that. Even if you could, those command line arguments would likely only have been there for one run. Subsequent CMake runs would not have them, so you’d get a different result.