Merge topic 'ctest_cli_initial_configure'

9a0010eef2 ctest: add --source-dir argument to enable initial configure

Acked-by: Kitware Robot <kwrobot@kitware.com>
Tested-by: buildbot <buildbot@kitware.com>
Merge-request: !12121
This commit is contained in:
Brad King
2026-06-02 13:21:54 +00:00
committed by Kitware Robot
12 changed files with 155 additions and 7 deletions

View File

@@ -20,10 +20,13 @@ Synopsis
[--test-command <command> [<args>...]]
`Dashboard Client`_
ctest -D <dashboard> [-- <dashboard-options>...]
ctest -M <model> -T <action> [-- <dashboard-options>...]
ctest -S <script> [-- <dashboard-options>...]
ctest -SP <script> [-- <dashboard-options>...]
ctest -D <dashboard> [-- <dashboard-options>...]
ctest -M <model> -T <action> [-- <dashboard-options>...]
ctest [-M <model>] -T Configure --source-dir <path-to-source>
[--build-dir <path-to-build>]
[-- <dashboard-options>...]
ctest -S <script> [-- <dashboard-options>...]
ctest -SP <script> [-- <dashboard-options>...]
`View Help`_
ctest --help[-<topic>]
@@ -448,12 +451,13 @@ The options for running tests are:
See `Label and Subproject Summary`_.
.. option:: --test-dir <dir>
.. option:: --test-dir <path-to-build>
.. versionadded:: 3.20
Specify the directory in which to look for tests, typically a CMake project
build directory. If not specified, the current directory is used.
See also :ctest-option:`--build-dir`.
.. option:: --test-output-size-passed <size>
@@ -877,6 +881,34 @@ The available ``<dashboard-options>`` are the following:
`CTest Script`_, a :manual:`configure preset <cmake-presets(7)>`, or
setting :variable:`CTEST_CONFIGURE_COMMAND`.
.. option:: --source-dir <path-to-source>
.. versionadded:: 4.4
Specify the project source directory. When combined with
:option:`-T Configure <ctest -T>`, this allows CTest to perform an initial
configure step for an empty binary directory. The binary directory defaults
to the current working directory; use :ctest-option:`--build-dir` to specify
a different location. The binary directory is created automatically if it
does not yet exist.
A CMake generator must also be specified. Use
:cref:`-D CTEST_CMAKE_GENERATOR=\<gen\> <ctest-option-D-var>` to supply one, or
set :variable:`CTEST_CONFIGURE_PRESET` to specify a
:manual:`configure preset <cmake-presets(7)>` that includes a
:preset:`generator <configurePresets.generator>`.
See the `CTest Configure Step`_ settings for more details.
.. option:: --build-dir <path-to-build>
.. versionadded:: 4.4
Specify the project binary (build) directory. This is an alias for
:ctest-option:`--test-dir` intended for use with
:ctest-option:`--source-dir` when bootstrapping a build with
:option:`-T Configure <ctest -T>`.
.. option:: --group <group>
Specify the group to which to submit results.
@@ -1011,6 +1043,15 @@ to the build tree and use one of these signatures::
ctest -D <mode>[<step>]
ctest -M <mode> [-T <step>]...
The :ctest-option:`--source-dir` option additionally allows the
``Configure`` step to be performed on a build tree that does not yet
exist, in which case the :ctest-option:`--build-dir` option specifies
where to create it::
ctest [-M <mode>] -T Configure
--source-dir <path-to-source> [--build-dir <path-to-build>]
ctest --build-and-test <path-to-source> <path-to-build>
The ``<mode>`` must be one of the above `Dashboard Client Modes`_,
and each ``<step>`` must be one of the above `Dashboard Client Steps`_.

View File

@@ -167,9 +167,13 @@ struct cmCTest::Private
int CompatibilityMode;
// information for the --build-and-test options
// Build and source directories used by various operating modes.
// BinaryDir is the active build tree.
// TestDir and SourceDir hold the raw values from --test-dir/--build-dir and
// --source-dir respectively, before path normalization is applied.
std::string BinaryDir;
std::string TestDir;
std::string SourceDir;
std::string NotesFiles;
@@ -2354,6 +2358,18 @@ int cmCTest::Run(std::vector<std::string> const& args)
} },
CommandArgument{ "-A", CommandArgument::Values::One, dashA },
CommandArgument{ "--add-notes", CommandArgument::Values::One, dashA },
CommandArgument{ "--source-dir", "'--source-dir' requires an argument",
CommandArgument::Values::One,
[this](std::string const& dir) -> bool {
this->Impl->SourceDir = dir;
return true;
} },
CommandArgument{ "--build-dir", "'--build-dir' requires an argument",
CommandArgument::Values::One,
[this](std::string const& dir) -> bool {
this->Impl->TestDir = dir;
return true;
} },
CommandArgument{ "--test-dir", "'--test-dir' requires an argument",
CommandArgument::Values::One,
[this](std::string const& dir) -> bool {
@@ -2603,6 +2619,19 @@ int cmCTest::Run(std::vector<std::string> const& args)
if (!this->Impl->TestDir.empty()) {
workDir = cmSystemTools::ToNormalizedPathOnDisk(this->Impl->TestDir);
}
// When --source-dir is given, record it as the source directory override
// and ensure the binary directory exists so an empty dir is accepted.
if (!this->Impl->SourceDir.empty()) {
this->Impl->CTestConfigurationOverwrites["SourceDirectory"] =
cmSystemTools::ToNormalizedPathOnDisk(this->Impl->SourceDir);
if (!cmSystemTools::MakeDirectory(workDir)) {
cmCTestLog(this, ERROR_MESSAGE,
"Failed to create directory: " << workDir << std::endl);
return 1;
}
}
cmWorkingDirectory changeDir(workDir);
if (changeDir.Failed()) {
cmCTestLog(this, ERROR_MESSAGE, changeDir.GetError() << std::endl);

View File

@@ -96,6 +96,13 @@ cmDocumentationEntry const cmDocumentationOptions[] = {
{ "-T <action>, --test-action <action>",
"Sets the dashboard action to "
"perform" },
{ "--source-dir <path-to-source>",
"Specify the project source directory. When combined with "
"-T Configure, this allows CTest to perform an initial configure "
"step for an empty binary directory." },
{ "--build-dir <path-to-build>",
"Alias for --test-dir. Provided as a more intuitive name when "
"using -T Configure to bootstrap a build directory." },
{ "--group <group>",
"Specify what build group on the dashboard you'd like to "
"submit results to." },
@@ -126,7 +133,8 @@ cmDocumentationEntry const cmDocumentationOptions[] = {
{ "--no-subproject-summary",
"Disable timing summary information for "
"subprojects." },
{ "--test-dir <dir>", "Specify the directory in which to look for tests." },
{ "--test-dir <path-to-build>",
"Specify the directory in which to look for tests." },
{ "--build-and-test <path-to-source> <path-to-build>",
"Configure, build and run a test." },
{ "--build-target <tgt>", "Specify a specific target to build." },

View File

@@ -656,6 +656,64 @@ endfunction()
run_testDir(testDir 0)
run_testDir(testDir-preset 1)
# Test --source-dir and --build-dir
run_cmake_command(source-dir-invalid-arg ${CMAKE_CTEST_COMMAND} --source-dir)
run_cmake_command(build-dir-invalid-arg ${CMAKE_CTEST_COMMAND} --build-dir)
# Build the -D arguments needed to pass the generator to ctest -T Configure.
macro(ctest_source_dir_generator_args var)
set(${var} -D "CTEST_CMAKE_GENERATOR=${RunCMake_GENERATOR}")
if(RunCMake_GENERATOR_PLATFORM)
list(APPEND ${var}
-D "CTEST_CMAKE_GENERATOR_PLATFORM=${RunCMake_GENERATOR_PLATFORM}")
endif()
endmacro()
# Verify that ctest -T Configure works with an empty binary directory
# when --source-dir is provided.
function(run_configure_empty_bindir)
set(src "${RunCMake_BINARY_DIR}/configure-empty-bindir-src")
set(bin "${RunCMake_BINARY_DIR}/configure-empty-bindir-bin")
file(REMOVE_RECURSE "${src}" "${bin}")
file(MAKE_DIRECTORY "${src}")
file(WRITE "${src}/CMakeLists.txt"
"cmake_minimum_required(VERSION 3.10)\nproject(Minimal LANGUAGES NONE)\n")
# Note that run_cmake_command always pre-creates RunCMake_TEST_BINARY_DIR
# before invoking the command, so this test exercises configure from an already-
# created but otherwise empty binary directory. The MakeDirectory call in CTest
# itself is what would handle the truly-absent case in production use.
set(RunCMake_TEST_BINARY_DIR "${bin}")
set(RunCMake_TEST_NO_CLEAN 1)
ctest_source_dir_generator_args(generator_args)
run_cmake_command(configure-empty-bindir
${CMAKE_CTEST_COMMAND}
--source-dir "${src}"
--build-dir "${bin}"
${generator_args}
-T Configure)
endfunction()
run_configure_empty_bindir()
# Verify expected error condition when --source-dir does not contain
# a CMakeLists.txt file.
function(run_configure_no_cmakelists)
set(src "${RunCMake_BINARY_DIR}/configure-no-cmakelists-src")
set(bin "${RunCMake_BINARY_DIR}/configure-no-cmakelists-bin")
file(REMOVE_RECURSE "${src}" "${bin}")
# Source dir exists but contains no CMakeLists.txt
file(MAKE_DIRECTORY "${src}")
set(RunCMake_TEST_BINARY_DIR "${bin}")
set(RunCMake_TEST_NO_CLEAN 1)
ctest_source_dir_generator_args(generator_args)
run_cmake_command(configure-no-cmakelists
${CMAKE_CTEST_COMMAND}
--source-dir "${src}"
--build-dir "${bin}"
${generator_args}
-T Configure)
endfunction()
run_configure_no_cmakelists()
# Test --output-junit
function(run_output_junit)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/output-junit)

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1 @@
CMake Error: '--build-dir' requires an argument

View File

@@ -0,0 +1,5 @@
set(cache_file "${RunCMake_TEST_BINARY_DIR}/CMakeCache.txt")
if(NOT EXISTS "${cache_file}")
set(RunCMake_TEST_FAILED
"CMakeCache.txt not found after configure:\n ${cache_file}")
endif()

View File

@@ -0,0 +1 @@
Cannot find file: .*/DartConfiguration\.tcl

View File

@@ -0,0 +1 @@
ctest_configure called with invalid source directory

View File

@@ -0,0 +1 @@
CMake Error: '--source-dir' requires an argument