summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.editorconfig10
-rw-r--r--.gitattributes1
-rw-r--r--.gitlab-ci.yml23
-rw-r--r--.gitlab/artifacts.yml1
-rwxr-xr-x.gitlab/ci/sccache.sh21
-rw-r--r--.gitlab/os-linux.yml22
-rw-r--r--Auxiliary/cmake-mode.el2
-rw-r--r--Copyright.txt2
-rw-r--r--Help/command/add_custom_command.rst21
-rw-r--r--Help/guide/tutorial/index.rst2
-rw-r--r--Help/release/3.19.rst5
-rw-r--r--Help/release/dev/makefile-depfile.rst5
-rw-r--r--Modules/FetchContent.cmake9
-rw-r--r--Modules/FindGTK2.cmake1
-rw-r--r--Modules/Internal/CPack/CPackNuGet.cmake2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmAddCustomCommandCommand.cxx6
-rw-r--r--Source/cmDependsCompiler.cxx133
-rw-r--r--Source/cmGccDepfileReader.cxx34
-rw-r--r--Source/cmGccDepfileReader.h8
-rw-r--r--Source/cmGlobalUnixMakefileGenerator3.h6
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx108
-rw-r--r--Source/cmGlobalXCodeGenerator.h5
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx39
-rw-r--r--Source/cmMakefileTargetGenerator.cxx19
-rw-r--r--Source/cmMakefileUtilityTargetGenerator.cxx39
-rw-r--r--Source/cmTransformDepfile.cxx16
-rw-r--r--Source/cmcmd.cxx2
-rw-r--r--Tests/ConfigSources/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt (renamed from Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt)0
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt4
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake10
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake73
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake3
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake61
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake10
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake6
-rw-r--r--Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake1
-rw-r--r--Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt22
-rw-r--r--Tests/RunCMake/BuildDepends/GenerateDepFile.cmake6
-rw-r--r--Tests/RunCMake/BuildDepends/RunCMakeTest.cmake20
-rw-r--r--Tests/RunCMake/BuildDepends/WriteDepfile.cmake8
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative-stderr.txt3
-rw-r--r--Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative.cmake1
-rw-r--r--Tests/RunCMake/FetchContent/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt5
-rw-r--r--Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake8
-rw-r--r--Tests/RunCMake/Make/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/XcodeProject/SearchPaths-check.cmake76
-rw-r--r--Tests/RunCMake/XcodeProject/SearchPaths.cmake21
-rw-r--r--Utilities/Release/linux/aarch64/Dockerfile35
-rw-r--r--Utilities/Release/linux/aarch64/base/Dockerfile31
-rw-r--r--Utilities/Release/linux/aarch64/cache.txt44
-rw-r--r--Utilities/Release/linux/aarch64/deps/Dockerfile141
-rw-r--r--Utilities/Release/linux/aarch64/deps/openssl-source.patch12
-rw-r--r--Utilities/Release/linux/aarch64/deps/qt-install.patch24
-rw-r--r--Utilities/Release/linux/aarch64/test/Dockerfile26
-rw-r--r--Utilities/Release/linux/aarch64/test/test-make.bash17
-rw-r--r--Utilities/Release/linux/aarch64/test/test-ninja.bash17
61 files changed, 1089 insertions, 152 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..e5e7e30
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,10 @@
+root = true
+
+[*]
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[{CMakeLists.txt,*.cmake,*.rst}]
+indent_size = 2
+indent_style = space
diff --git a/.gitattributes b/.gitattributes
index 3da2d60..fac38df 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,6 @@
.git* export-ignore
.hooks* export-ignore
+.editorconfig export-ignore
# Custom attribute to mark sources as using our C code style.
[attr]our-c-style whitespace=tab-in-indent format.clang-format-6.0
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 626071a..073630e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -186,6 +186,29 @@ upload:linux-x86_64-package:
variables:
RSYNC_DESTINATION: dev
+build:linux-aarch64-package:
+ extends:
+ - .linux_package_aarch64
+ - .cmake_build_linux_package
+ - .cmake_release_artifacts
+ - .linux_builder_tags_aarch64
+ - .run_only_for_package
+ dependencies:
+ - prep:doc-package
+ needs:
+ - prep:doc-package
+
+upload:linux-aarch64-package:
+ extends:
+ - .rsync_upload
+ - .run_only_for_package
+ dependencies:
+ - build:linux-aarch64-package
+ needs:
+ - build:linux-aarch64-package
+ variables:
+ RSYNC_DESTINATION: dev
+
# macOS builds
build:macos-ninja:
diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
index 589b16c..76ffd27 100644
--- a/.gitlab/artifacts.yml
+++ b/.gitlab/artifacts.yml
@@ -74,6 +74,7 @@
paths:
# Any packages made.
- build/cmake-*-Linux-x86_64.*
+ - build/cmake-*-Linux-aarch64.*
- build/cmake-*-macos-universal.*
# Any source packages made.
- build/cmake-*.tar.gz
diff --git a/.gitlab/ci/sccache.sh b/.gitlab/ci/sccache.sh
index af24710..77bedaa 100755
--- a/.gitlab/ci/sccache.sh
+++ b/.gitlab/ci/sccache.sh
@@ -2,21 +2,30 @@
set -e
-case "$( uname -s )" in
- Linux)
+readonly kernel="$(uname -s)-$(uname -m)"
+case $kernel in
+ Linux-x86_64)
version="0.2.13"
shatool="sha256sum"
sha256sum="28a5499e340865b08b632306b435913beb590fbd7b49a3f887a623b459fabdeb"
platform="x86_64-unknown-linux-musl"
;;
- Darwin)
+ Linux-aarch64)
+ version="g6628e1f"
+ shatool="sha256sum"
+ sha256sum="bb88adbb5a29c166ecaa78d0593493b609a7f84d91d1228502a908f319b513f0"
+ platform="aarch64-unknown-linux-musl"
+ url="https://github.com/hwinit/sccache/releases/download/$version"
+ ;;
+ Darwin-x86_64)
version="gfe63078"
shatool="shasum -a 256"
sha256sum="60a0302b1d7227f7ef56abd82266353f570d27c6e850c56c6448bf62def38888"
platform="x86_64-apple-darwin"
+ url="https://paraview.org/files/dependencies"
;;
*)
- echo "Unrecognized platform $( uname -s )"
+ echo "Unrecognized platform $kernel"
exit 1
;;
esac
@@ -28,9 +37,7 @@ readonly platform
readonly filename="sccache-$version-$platform"
readonly tarball="$filename.tar.gz"
-if [ "$( uname -s )" = "Darwin" ]; then
- url="https://paraview.org/files/dependencies"
-else
+if [ -z "$url" ]; then
url="https://github.com/mozilla/sccache/releases/download/$version"
fi
readonly url
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 6684d71..a88ff6e 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -17,18 +17,21 @@
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
-.linux_package:
+.linux_package_x86_64:
+ image: "kitware/cmake:build-linux-x86_64-deps-2020-04-02@sha256:77e9ab183f34680990db9da5945473e288f0d6556bce79ecc1589670d656e157"
+
variables:
GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
LAUNCHER: "scl enable devtoolset-6 rh-python36 --"
+ CMAKE_ARCH: x86_64
-.linux_package_x86_64:
- extends: .linux_package
-
- image: "kitware/cmake:build-linux-x86_64-deps-2020-04-02@sha256:77e9ab183f34680990db9da5945473e288f0d6556bce79ecc1589670d656e157"
+.linux_package_aarch64:
+ image: "kitware/cmake:build-linux-aarch64-deps-2020-12-21@sha256:0bd7dfe4e45593b04e39cd21e44011034610cfd376900558c5ef959bb1af15af"
variables:
- CMAKE_ARCH: x86_64
+ GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci"
+ LAUNCHER: "scl enable devtoolset-7 --"
+ CMAKE_ARCH: aarch64
### Debian
@@ -160,6 +163,13 @@
- docker
- linux
+.linux_builder_tags_aarch64:
+ tags:
+ - cmake
+ - build
+ - docker
+ - linux-aarch64
+
## Linux-specific scripts
.before_script_linux: &before_script_linux
diff --git a/Auxiliary/cmake-mode.el b/Auxiliary/cmake-mode.el
index 52f2d41..ddc7b40 100644
--- a/Auxiliary/cmake-mode.el
+++ b/Auxiliary/cmake-mode.el
@@ -211,7 +211,7 @@ the indentation. Otherwise it retains the same position on the line"
"end"
(or "function" "macro")
(zero-or-more space)
- "(" (zero-or-more (not ")")) ")"))
+ "(" (zero-or-more (not-char ")")) ")"))
(defun cmake-beginning-of-defun ()
"Move backward to the beginning of a CMake function or macro.
diff --git a/Copyright.txt b/Copyright.txt
index b867d01..7460e73 100644
--- a/Copyright.txt
+++ b/Copyright.txt
@@ -1,5 +1,5 @@
CMake - Cross Platform Makefile Generator
-Copyright 2000-2020 Kitware, Inc. and Contributors
+Copyright 2000-2021 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 567af16..9a4efd1 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -201,6 +201,10 @@ The options are:
Note that the ``IMPLICIT_DEPENDS`` option is currently supported
only for Makefile generators and will be ignored by other generators.
+ .. note::
+
+ This option cannot be specified at the same time as ``DEPFILE`` option.
+
``JOB_POOL``
.. versionadded:: 3.15
@@ -263,15 +267,26 @@ The options are:
``DEPFILE``
.. versionadded:: 3.7
- Specify a ``.d`` depfile for the :generator:`Ninja` generator.
+ Specify a ``.d`` depfile for the :generator:`Ninja` generator and
+ :ref:`Makefile Generators`.
A ``.d`` file holds dependencies usually emitted by the custom
command itself.
- Using ``DEPFILE`` with other generators than Ninja is an error.
+ Using ``DEPFILE`` with other generators than :generator:`Ninja` or
+ :ref:`Makefile Generators` is an error.
+
+ .. versionadded:: 3.20
+ Added the support of :ref:`Makefile Generators`.
If the ``DEPFILE`` argument is relative, it should be relative to
:variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the
``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR`
- (see policy :policy:`CMP0116`.)
+ (see policy :policy:`CMP0116`. This policy is always ``NEW`` for
+ :ref:`Makefile Generators`).
+
+ .. note::
+
+ For :ref:`Makefile Generators`, this option cannot be specified at the
+ same time as ``IMPLICIT_DEPENDS`` option.
Examples: Generating Files
^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst
index 4b09e53..00fa39a 100644
--- a/Help/guide/tutorial/index.rst
+++ b/Help/guide/tutorial/index.rst
@@ -176,7 +176,7 @@ directory:
To make use of the new library we will add an :command:`add_subdirectory`
call in the top-level ``CMakeLists.txt`` file so that the library will get
built. We add the new library to the executable, and add ``MathFunctions`` as
-an include directory so that the ``mqsqrt.h`` header file can be found. The
+an include directory so that the ``mysqrt.h`` header file can be found. The
last few lines of the top-level ``CMakeLists.txt`` file should now look like:
.. code-block:: cmake
diff --git a/Help/release/3.19.rst b/Help/release/3.19.rst
index 60a8ecc..eb49c6f 100644
--- a/Help/release/3.19.rst
+++ b/Help/release/3.19.rst
@@ -385,3 +385,8 @@ Changes made since CMake 3.19.0 include the following.
* The :variable:`CMAKE_ISPC_HEADER_SUFFIX` variable and corresponding
:prop_tgt:`ISPC_HEADER_SUFFIX` target property were added to control
the header suffix used by ``ISPC`` compiler generated headers.
+
+3.19.3
+------
+
+* A precompiled Linux ``aarch64`` binary is now provided on ``cmake.org``.
diff --git a/Help/release/dev/makefile-depfile.rst b/Help/release/dev/makefile-depfile.rst
new file mode 100644
index 0000000..4a3e5fb
--- /dev/null
+++ b/Help/release/dev/makefile-depfile.rst
@@ -0,0 +1,5 @@
+makefile-depfile
+----------------
+
+* The :command:`add_custom_command` command gained ``DEPFILE`` support on
+ :ref:`Makefile Generators`.
diff --git a/Modules/FetchContent.cmake b/Modules/FetchContent.cmake
index 8fabcdc..ba2acfc 100644
--- a/Modules/FetchContent.cmake
+++ b/Modules/FetchContent.cmake
@@ -1060,7 +1060,14 @@ function(FetchContent_Populate contentName)
# so no population is required. The build directory may still be specified
# by the declared details though.
- if(NOT EXISTS "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+ if(NOT IS_ABSOLUTE "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+ # Don't check this directory because we don't know what location it is
+ # expected to be relative to. We can't make this a hard error for backward
+ # compatibility reasons.
+ message(WARNING "Relative source directory specified. This is not safe, "
+ "as it depends on the calling directory scope.\n"
+ " FETCHCONTENT_SOURCE_DIR_${contentNameUpper} --> ${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
+ elseif(NOT EXISTS "${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
message(FATAL_ERROR "Manually specified source directory is missing:\n"
" FETCHCONTENT_SOURCE_DIR_${contentNameUpper} --> ${FETCHCONTENT_SOURCE_DIR_${contentNameUpper}}")
endif()
diff --git a/Modules/FindGTK2.cmake b/Modules/FindGTK2.cmake
index 7036b66..00bfc29 100644
--- a/Modules/FindGTK2.cmake
+++ b/Modules/FindGTK2.cmake
@@ -805,6 +805,7 @@ foreach(_GTK2_component ${GTK2_FIND_COMPONENTS})
_GTK2_ADD_TARGET (GIOMM GTK2_DEPENDS gio glibmm gobject sigc++ glib)
_GTK2_FIND_INCLUDE_DIR(ATKMM atkmm.h)
+ _GTK2_FIND_INCLUDE_DIR(ATKMMCONFIG atkmmconfig.h)
_GTK2_FIND_LIBRARY (ATKMM atkmm true true)
_GTK2_ADD_TARGET (ATKMM GTK2_DEPENDS atk glibmm gobject sigc++ glib)
diff --git a/Modules/Internal/CPack/CPackNuGet.cmake b/Modules/Internal/CPack/CPackNuGet.cmake
index 56bbffd..fb363f4 100644
--- a/Modules/Internal/CPack/CPackNuGet.cmake
+++ b/Modules/Internal/CPack/CPackNuGet.cmake
@@ -332,7 +332,7 @@ endfunction()
function(_cpack_nuget_make_files_tag)
set(_files)
foreach(_comp IN LISTS ARGN)
- string(APPEND _files " <file src=\"${_comp}\\**\" target=\".\" />\n")
+ string(APPEND _files " <file src=\"${_comp}/**\" target=\".\" />\n")
endforeach()
set(_CPACK_NUGET_FILES_TAG "<files>\n${_files} </files>" PARENT_SCOPE)
endfunction()
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 49c60e6..1df2edf 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 19)
-set(CMake_VERSION_PATCH 20201222)
+set(CMake_VERSION_PATCH 20210104)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index ccd7255..ff2cc3e 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -296,6 +296,12 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
status.SetError("given APPEND option with no OUTPUT.");
return false;
}
+ if (!implicit_depends.empty() && !depfile.empty() &&
+ mf.GetGlobalGenerator()->GetName() != "Ninja") {
+ // Makefiles generators does not support both at the same time
+ status.SetError("IMPLICIT_DEPENDS and DEPFILE can not both be specified.");
+ return false;
+ }
// Check for an append request.
if (append) {
diff --git a/Source/cmDependsCompiler.cxx b/Source/cmDependsCompiler.cxx
index f6e5af8..beb080f 100644
--- a/Source/cmDependsCompiler.cxx
+++ b/Source/cmDependsCompiler.cxx
@@ -19,6 +19,7 @@
#include "cmFileTime.h"
#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmStringAlgorithms.h"
@@ -86,7 +87,7 @@ bool cmDependsCompiler::CheckDependencies(
if (!forceReadDeps) {
depFileTime.Load(depFile);
}
- if (forceReadDeps || depFileTime.Newer(internalDepFileTime)) {
+ if (forceReadDeps || depFileTime.Compare(internalDepFileTime) >= 0) {
status = false;
if (this->Verbose) {
cmSystemTools::Stdout(cmStrCat("Dependencies file \"", depFile,
@@ -95,59 +96,92 @@ bool cmDependsCompiler::CheckDependencies(
}
std::vector<std::string> depends;
- if (format == "msvc"_s) {
- cmsys::ifstream fin(depFile.c_str());
- if (!fin) {
- continue;
+ if (format == "custom"_s) {
+ std::string prefix;
+ if (this->LocalGenerator->GetCurrentBinaryDirectory() !=
+ this->LocalGenerator->GetBinaryDirectory()) {
+ prefix =
+ cmStrCat(this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ this->LocalGenerator->GetCurrentBinaryDirectory()),
+ '/');
}
- std::string line;
- if (!isValidPath) {
- // insert source as first dependency
- depends.push_back(source);
- }
- while (cmSystemTools::GetLineFromStream(fin, line)) {
- depends.emplace_back(std::move(line));
- }
- } else {
- auto deps = cmReadGccDepfile(depFile.c_str());
+ auto deps = cmReadGccDepfile(depFile.c_str(), prefix);
if (!deps) {
continue;
}
- // dependencies generated by the compiler contains only one target
- depends = std::move(deps->front().paths);
- if (depends.empty()) {
- // unexpectedly empty, ignore it and continue
- continue;
- }
-
- // depending of the effective format of the dependencies file generated
- // by the compiler, the target can be wrongly identified as a
- // dependency so remove it from the list
- if (depends.front() == target) {
- depends.erase(depends.begin());
+ for (auto& entry : *deps) {
+ depends = std::move(entry.paths);
+ if (isValidPath) {
+ cm::erase_if(depends, isValidPath);
+ }
+ // copy depends for each target, except first one, which can be
+ // moved
+ for (auto index = entry.rules.size() - 1; index > 0; --index) {
+ dependencies[entry.rules[index]] = depends;
+ }
+ dependencies[entry.rules.front()] = std::move(depends);
}
+ } else {
+ if (format == "msvc"_s) {
+ cmsys::ifstream fin(depFile.c_str());
+ if (!fin) {
+ continue;
+ }
- // ensure source file is the first dependency
- if (depends.front() != source) {
- cm::erase(depends, source);
+ std::string line;
if (!isValidPath) {
- depends.insert(depends.begin(), source);
+ // insert source as first dependency
+ depends.push_back(source);
+ }
+ while (cmSystemTools::GetLineFromStream(fin, line)) {
+ depends.emplace_back(std::move(line));
+ }
+ } else if (format == "gcc"_s) {
+ auto deps = cmReadGccDepfile(depFile.c_str());
+ if (!deps) {
+ continue;
}
- } else if (isValidPath) {
- // remove first dependency because it must not be filtered out
- depends.erase(depends.begin());
+
+ // dependencies generated by the compiler contains only one target
+ depends = std::move(deps->front().paths);
+ if (depends.empty()) {
+ // unexpectedly empty, ignore it and continue
+ continue;
+ }
+
+ // depending of the effective format of the dependencies file
+ // generated by the compiler, the target can be wrongly identified
+ // as a dependency so remove it from the list
+ if (depends.front() == target) {
+ depends.erase(depends.begin());
+ }
+
+ // ensure source file is the first dependency
+ if (depends.front() != source) {
+ cm::erase(depends, source);
+ if (!isValidPath) {
+ depends.insert(depends.begin(), source);
+ }
+ } else if (isValidPath) {
+ // remove first dependency because it must not be filtered out
+ depends.erase(depends.begin());
+ }
+ } else {
+ // unknown format, ignore it
+ continue;
}
- }
- if (isValidPath) {
- cm::erase_if(depends, isValidPath);
- // insert source as first dependency
- depends.insert(depends.begin(), source);
- }
+ if (isValidPath) {
+ cm::erase_if(depends, isValidPath);
+ // insert source as first dependency
+ depends.insert(depends.begin(), source);
+ }
- dependencies[target] = std::move(depends);
+ dependencies[target] = std::move(depends);
+ }
}
}
@@ -168,6 +202,8 @@ void cmDependsCompiler::WriteDependencies(
// external dependencies file
for (auto& node : makeDependencies) {
+ auto target = LocalGenerator->ConvertToMakefilePath(
+ this->LocalGenerator->MaybeConvertToRelativePath(binDir, node.first));
auto& deps = node.second;
std::transform(
deps.cbegin(), deps.cend(), deps.begin(),
@@ -176,13 +212,16 @@ void cmDependsCompiler::WriteDependencies(
this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep));
});
- makeDepends << this->LocalGenerator->ConvertToMakefilePath(node.first)
- << ": " << deps.front();
- // first dependency is the source, remove it because should not be declared
- // as phony target
- deps.erase(deps.begin());
+ bool first_dep = true;
+ makeDepends << target << ": ";
for (const auto& dep : deps) {
- makeDepends << ' ' << lineContinue << " " << dep;
+ if (first_dep) {
+ first_dep = false;
+ makeDepends << dep;
+ } else {
+ makeDepends << ' ' << lineContinue << " " << dep;
+ }
+
phonyTargets.emplace(dep.data(), dep.length());
}
makeDepends << std::endl << std::endl;
diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx
index eb3511a..96a562e 100644
--- a/Source/cmGccDepfileReader.cxx
+++ b/Source/cmGccDepfileReader.cxx
@@ -4,10 +4,13 @@
#include <type_traits>
#include <utility>
+#include <vector>
#include <cm/optional>
#include "cmGccDepfileLexerHelper.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath)
{
@@ -17,3 +20,34 @@ cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath)
}
return cm::nullopt;
}
+
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath,
+ const std::string& prefix)
+{
+ auto deps = cmReadGccDepfile(filePath);
+
+ if (prefix.empty() || !deps) {
+ return deps;
+ }
+
+ for (auto& dep : *deps) {
+ for (auto& rule : dep.rules) {
+ if (!cmSystemTools::FileIsFullPath(rule)) {
+ rule = cmStrCat(prefix, rule);
+ }
+ if (cmSystemTools::FileIsFullPath(rule)) {
+ rule = cmSystemTools::CollapseFullPath(rule);
+ }
+ }
+ for (auto& path : dep.paths) {
+ if (!cmSystemTools::FileIsFullPath(path)) {
+ path = cmStrCat(prefix, path);
+ }
+ if (cmSystemTools::FileIsFullPath(path)) {
+ path = cmSystemTools::CollapseFullPath(path);
+ }
+ }
+ }
+
+ return deps;
+}
diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h
index 59ed7fd..66ff75d 100644
--- a/Source/cmGccDepfileReader.h
+++ b/Source/cmGccDepfileReader.h
@@ -2,8 +2,16 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
+#include <string>
+
#include <cm/optional>
#include "cmGccDepfileReaderTypes.h"
cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath);
+
+/*
+ * Read dependencies file and append prefix to all relative paths
+ */
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath,
+ const std::string& prefix);
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 6459771..09679a7 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -93,6 +93,12 @@ public:
*/
static bool SupportsPlatform() { return false; }
+ /**
+ * Utilized to determine if this generator
+ * supports DEPFILE option.
+ */
+ bool SupportsCustomCommandDepfile() const override { return true; }
+
/** Get the documentation entry for this generator. */
static void GetDocumentation(cmDocumentationEntry& entry);
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index b6fedaf..d59d382 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -3213,36 +3213,43 @@ void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
if (!attr) {
settings->AddAttribute(attribute, value);
} else {
- if (value->GetType() != cmXCodeObject::OBJECT_LIST &&
- value->GetType() != cmXCodeObject::STRING) {
- cmSystemTools::Error("Unsupported value type for appending: " +
- std::string(attribute));
- return;
- }
- if (attr->GetType() == cmXCodeObject::OBJECT_LIST) {
- if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
- for (auto* obj : value->GetObjectList()) {
- attr->AddObject(obj);
- }
- } else {
- attr->AddObject(value);
- }
- } else if (attr->GetType() == cmXCodeObject::STRING) {
- if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
- // Add old value as a list item to new object list
- // and replace the attribute with the new list
- value->PrependObject(attr);
- settings->AddAttribute(attribute, value);
- } else {
- std::string newValue =
- cmStrCat(attr->GetString(), ' ', value->GetString());
- attr->SetString(newValue);
- }
- } else {
- cmSystemTools::Error("Unsupported attribute type for appending: " +
- std::string(attribute));
+ this->AppendBuildSettingAttribute(settings, attribute, attr, value);
+ }
+ }
+}
+
+void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
+ cmXCodeObject* settings, const char* attribute, cmXCodeObject* attr,
+ cmXCodeObject* value)
+{
+ if (value->GetType() != cmXCodeObject::OBJECT_LIST &&
+ value->GetType() != cmXCodeObject::STRING) {
+ cmSystemTools::Error("Unsupported value type for appending: " +
+ std::string(attribute));
+ return;
+ }
+ if (attr->GetType() == cmXCodeObject::OBJECT_LIST) {
+ if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
+ for (auto* obj : value->GetObjectList()) {
+ attr->AddObject(obj);
}
+ } else {
+ attr->AddObject(value);
}
+ } else if (attr->GetType() == cmXCodeObject::STRING) {
+ if (value->GetType() == cmXCodeObject::OBJECT_LIST) {
+ // Add old value as a list item to new object list
+ // and replace the attribute with the new list
+ value->PrependObject(attr);
+ settings->AddAttribute(attribute, value);
+ } else {
+ std::string newValue =
+ cmStrCat(attr->GetString(), ' ', value->GetString());
+ attr->SetString(newValue);
+ }
+ } else {
+ cmSystemTools::Error("Unsupported attribute type for appending: " +
+ std::string(attribute));
}
}
@@ -3265,6 +3272,24 @@ void cmGlobalXCodeGenerator::AppendBuildSettingAttribute(
}
}
+void cmGlobalXCodeGenerator::InheritBuildSettingAttribute(
+ cmXCodeObject* target, const char* attribute)
+{
+ cmXCodeObject* configurationList =
+ target->GetAttribute("buildConfigurationList")->GetObject();
+ cmXCodeObject* buildConfigs =
+ configurationList->GetAttribute("buildConfigurations");
+ for (auto obj : buildConfigs->GetObjectList()) {
+ cmXCodeObject* settings = obj->GetAttribute("buildSettings");
+ if (cmXCodeObject* attr = settings->GetAttribute(attribute)) {
+ BuildObjectListOrString inherited(this, true);
+ inherited.Add("$(inherited)");
+ this->AppendBuildSettingAttribute(settings, attribute, attr,
+ inherited.CreateList());
+ }
+ }
+}
+
void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
{
cmGeneratorTarget* gt = target->GetTarget();
@@ -3581,11 +3606,11 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
for (auto& libDir : linkSearchPaths) {
libSearchPaths.Add(this->XCodeEscapePath(libDir));
}
- // Add paths defined in project-wide build settings
- libSearchPaths.Add("$(inherited)");
- this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
- libSearchPaths.CreateList(),
- configName);
+ if (!libSearchPaths.IsEmpty()) {
+ this->AppendBuildSettingAttribute(target, "LIBRARY_SEARCH_PATHS",
+ libSearchPaths.CreateList(),
+ configName);
+ }
}
// add framework search paths
@@ -3596,11 +3621,11 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
for (auto& fwDir : frameworkSearchPaths) {
fwSearchPaths.Add(this->XCodeEscapePath(fwDir));
}
- // Add paths defined in project-wide build settings
- fwSearchPaths.Add("$(inherited)");
- this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
- fwSearchPaths.CreateList(),
- configName);
+ if (!fwSearchPaths.IsEmpty()) {
+ this->AppendBuildSettingAttribute(target, "FRAMEWORK_SEARCH_PATHS",
+ fwSearchPaths.CreateList(),
+ configName);
+ }
}
// now add the left-over link libraries
@@ -4154,6 +4179,13 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects(
for (auto t : targets) {
this->AddDependAndLinkInformation(t);
this->AddEmbeddedFrameworks(t);
+ // Inherit project-wide values for any target-specific search paths.
+ this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "SYSTEM_HEADER_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "FRAMEWORK_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "SYSTEM_FRAMEWORK_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "LIBRARY_SEARCH_PATHS");
+ this->InheritBuildSettingAttribute(t, "LD_RUNPATH_SEARCH_PATHS");
}
if (this->XcodeBuildSystem == BuildSystem::One) {
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 3cc4efe..14db1dc 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -182,9 +182,14 @@ private:
cmGeneratorTarget* gtgt);
void AppendOrAddBuildSetting(cmXCodeObject* settings, const char* attr,
cmXCodeObject* value);
+ void AppendBuildSettingAttribute(cmXCodeObject* settings,
+ const char* attribute, cmXCodeObject* attr,
+ cmXCodeObject* value);
void AppendBuildSettingAttribute(cmXCodeObject* target, const char* attr,
cmXCodeObject* value,
const std::string& configName);
+ void InheritBuildSettingAttribute(cmXCodeObject* target,
+ const char* attribute);
cmXCodeObject* CreateUtilityTarget(cmGeneratorTarget* gtgt);
void AddDependAndLinkInformation(cmXCodeObject* target);
void AddEmbeddedFrameworks(cmXCodeObject* target);
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 08cefb7..358df9d 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -13,6 +13,7 @@
#include <cm/string_view>
#include <cm/vector>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cmsys/FStream.hxx"
#include "cmsys/Terminal.h"
@@ -1435,7 +1436,7 @@ bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
this->Makefile->GetSafeDefinition("CMAKE_DEPENDS_DEPENDENCY_FILES");
if (!depends.empty()) {
// dependencies are managed by compiler
- auto depFiles = cmExpandedList(depends);
+ auto depFiles = cmExpandedList(depends, true);
std::string const internalDepFile =
targetDir + "/compiler_depend.internal";
std::string const depFile = targetDir + "/compiler_depend.make";
@@ -1998,18 +1999,32 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo(
cmakefileStream << "\n# The set of dependency files which are needed:\n";
cmakefileStream << "set(CMAKE_DEPENDS_DEPENDENCY_FILES\n";
for (auto const& compilerLang : compilerLangs) {
- auto depFormat = this->Makefile->GetSafeDefinition(
- cmStrCat("CMAKE_", compilerLang.first, "_DEPFILE_FORMAT"));
auto const& compilerPairs = compilerLang.second;
- for (auto const& compilerPair : compilerPairs) {
- for (auto const& src : compilerPair.second) {
- cmakefileStream << " \"" << src << "\" \""
- << this->MaybeConvertToRelativePath(
- this->GetBinaryDirectory(), compilerPair.first)
- << "\" \"" << depFormat << "\" \""
- << this->MaybeConvertToRelativePath(
- this->GetBinaryDirectory(), compilerPair.first)
- << ".d\"\n";
+ if (compilerLang.first == "CUSTOM"_s) {
+ for (auto const& compilerPair : compilerPairs) {
+ for (auto const& src : compilerPair.second) {
+ cmakefileStream << R"( "" ")"
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << R"(" "custom" ")"
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), src)
+ << "\"\n";
+ }
+ }
+ } else {
+ auto depFormat = this->Makefile->GetSafeDefinition(
+ cmStrCat("CMAKE_", compilerLang.first, "_DEPFILE_FORMAT"));
+ for (auto const& compilerPair : compilerPairs) {
+ for (auto const& src : compilerPair.second) {
+ cmakefileStream << " \"" << src << "\" \""
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << "\" \"" << depFormat << "\" \""
+ << this->MaybeConvertToRelativePath(
+ this->GetBinaryDirectory(), compilerPair.first)
+ << ".d\"\n";
+ }
}
}
}
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 1f23424..70a0393 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -1617,6 +1617,16 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile(
std::vector<std::string> depends;
this->LocalGenerator->AppendCustomDepend(depends, ccg);
+ if (!ccg.GetCC().GetDepfile().empty()) {
+ // Add dependency over timestamp file for dependencies management
+ auto dependTimestamp = cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(),
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts")));
+
+ depends.push_back(dependTimestamp);
+ }
+
// Write the rule.
const std::vector<std::string>& outputs = ccg.GetOutputs();
bool symbolic = this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs,
@@ -1653,6 +1663,15 @@ void cmMakefileTargetGenerator::GenerateCustomRuleFile(
objFullPath, srcFullPath);
}
+ // Setup implicit depend for depfile if any
+ if (!ccg.GetCC().GetDepfile().empty()) {
+ std::string objFullPath = cmSystemTools::CollapseFullPath(
+ outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory());
+ this->LocalGenerator->AddImplicitDepends(
+ this->GeneratorTarget, "CUSTOM", objFullPath, ccg.GetFullDepfile(),
+ cmDependencyScannerKind::Compiler);
+ }
+
this->CustomCommandOutputs.insert(outputs.begin(), outputs.end());
}
diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx
index 6c18e48..a885b17 100644
--- a/Source/cmMakefileUtilityTargetGenerator.cxx
+++ b/Source/cmMakefileUtilityTargetGenerator.cxx
@@ -15,6 +15,7 @@
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmMakefile.h"
#include "cmOSXBundleGenerator.h"
+#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
@@ -36,10 +37,42 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles()
*this->BuildFileStream << "# Utility rule file for "
<< this->GeneratorTarget->GetName() << ".\n\n";
+ const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
+ ? "$(CMAKE_BINARY_DIR)/"
+ : "");
+
+ // Include the dependencies for the target.
+ std::string dependFile =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.make");
+ *this->BuildFileStream
+ << "# Include any custom commands dependencies for this target.\n"
+ << this->GlobalGenerator->IncludeDirective << " " << root
+ << cmSystemTools::ConvertToOutputPath(
+ this->LocalGenerator->MaybeConvertToRelativePath(
+ this->LocalGenerator->GetBinaryDirectory(), dependFile))
+ << "\n\n";
+ if (!cmSystemTools::FileExists(dependFile)) {
+ // Write an empty dependency file.
+ cmGeneratedFileStream depFileStream(
+ dependFile, false, this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# Empty custom commands generated dependencies file for "
+ << this->GeneratorTarget->GetName() << ".\n"
+ << "# This may be replaced when dependencies are built.\n";
+ }
+
+ std::string dependTimestamp =
+ cmStrCat(this->TargetBuildDirectoryFull, "/compiler_depend.ts");
+ if (!cmSystemTools::FileExists(dependTimestamp)) {
+ // Write a dependency timestamp file.
+ cmGeneratedFileStream depFileStream(
+ dependTimestamp, false, this->GlobalGenerator->GetMakefileEncoding());
+ depFileStream << "# CMAKE generated file: DO NOT EDIT!\n"
+ << "# Timestamp file for custom commands dependencies "
+ "management for "
+ << this->GeneratorTarget->GetName() << ".\n";
+ }
+
if (!this->NoRuleMessages) {
- const char* root = (this->Makefile->IsOn("CMAKE_MAKE_INCLUDE_FROM_ROOT")
- ? "$(CMAKE_BINARY_DIR)/"
- : "");
// Include the progress variables for the target.
*this->BuildFileStream
<< "# Include the progress variables for this target.\n"
diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx
index 163d7e0..b91e1ce 100644
--- a/Source/cmTransformDepfile.cxx
+++ b/Source/cmTransformDepfile.cxx
@@ -13,7 +13,6 @@
#include "cmGccDepfileReader.h"
#include "cmGccDepfileReaderTypes.h"
-#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
namespace {
@@ -79,26 +78,13 @@ bool cmTransformDepfile(cmDepfileFormat format, const std::string& prefix,
{
cmGccDepfileContent content;
if (cmSystemTools::FileExists(infile)) {
- auto result = cmReadGccDepfile(infile.c_str());
+ auto result = cmReadGccDepfile(infile.c_str(), prefix);
if (!result) {
return false;
}
content = *std::move(result);
}
- for (auto& dep : content) {
- for (auto& rule : dep.rules) {
- if (!cmSystemTools::FileIsFullPath(rule)) {
- rule = cmStrCat(prefix, rule);
- }
- }
- for (auto& path : dep.paths) {
- if (!cmSystemTools::FileIsFullPath(path)) {
- path = cmStrCat(prefix, path);
- }
- }
- }
-
cmsys::ofstream fout(outfile.c_str());
if (!fout) {
return false;
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index b8464f2..73fbfb6 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1272,6 +1272,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentBinary(startOutDir);
snapshot.GetDirectory().SetCurrentSource(startDir);
+ snapshot.GetDirectory().SetRelativePathTopSource(homeDir.c_str());
+ snapshot.GetDirectory().SetRelativePathTopBinary(homeOutDir.c_str());
cmMakefile mf(cm.GetGlobalGenerator(), snapshot);
auto lgd = cm.GetGlobalGenerator()->CreateLocalGenerator(&mf);
diff --git a/Tests/ConfigSources/CMakeLists.txt b/Tests/ConfigSources/CMakeLists.txt
index 5513af8..ab0b5d8 100644
--- a/Tests/ConfigSources/CMakeLists.txt
+++ b/Tests/ConfigSources/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.0)
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT _isMultiConfig AND NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build")
+ set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build" FORCE)
endif()
project(ConfigSources CXX)
diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-result.txt
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-result.txt
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt
new file mode 100644
index 0000000..cddea3c
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CustomCommandDependencies-BadArgs.cmake:[0-9]+ \(add_custom_command\):
+ add_custom_command IMPLICIT_DEPENDS and DEPFILE can not both be specified.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake
new file mode 100644
index 0000000..91ee338
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies-BadArgs.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_custom_command(OUTPUT main.c
+ DEPFILE main.c.d
+ IMPLICIT_DEPENDS C main.c.in
+ COMMAND "${CMAKE_COMMAND}" -DINFILE=main.c.in -DOUTFILE=main.c -DDEPFILE=main.c.d
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/GenerateDepFile.cmake"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_custom_target(mainc ALL DEPENDS main.c)
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake
new file mode 100644
index 0000000..28bbf11
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.cmake
@@ -0,0 +1,73 @@
+enable_language(C)
+
+add_custom_command(OUTPUT main.c
+ DEPFILE main.c.d
+ COMMAND "${CMAKE_COMMAND}" -DINFILE=main.c.in -DOUTFILE=main.c -DDEPFILE=main.c.d
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/GenerateDepFile.cmake"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_custom_target(mainc ALL DEPENDS main.c)
+
+add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+cmake_minimum_required(VERSION 3.19)
+set(check_pairs
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c.in\"
+ \"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
+ )
+set(check_exes
+ \"$<TARGET_FILE:main>\"
+ )
+
+if (check_step EQUAL 2)
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Makefile.cmake\")
+ if (NOT CMAKE_DEPEND_INFO_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPEND_INFO_FILES not found.\")
+ else()
+ foreach(DEPEND_INFO_FILE IN LISTS CMAKE_DEPEND_INFO_FILES)
+ include(\"${CMAKE_CURRENT_BINARY_DIR}/\${DEPEND_INFO_FILE}\")
+ if (NOT CMAKE_DEPENDS_DEPENDENCY_FILES)
+ set(RunCMake_TEST_FAILED \"Variable CMAKE_DEPENDS_DEPENDENCY_FILES not found.\")
+ else()
+ list(LENGTH CMAKE_DEPENDS_DEPENDENCY_FILES DEPENDENCY_FILES_SIZE)
+ math(EXPR STOP_INDEX \"\${DEPENDENCY_FILES_SIZE} - 1\")
+ foreach(INDEX RANGE 0 \${STOP_INDEX} 4)
+ math(EXPR OBJECT_INDEX \"\${INDEX} + 1\")
+ math(EXPR FORMAT_INDEX \"\${INDEX} + 2\")
+ math(EXPR DEP_INDEX \"\${INDEX} + 3\")
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${OBJECT_INDEX} OBJECT_FILE)
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${FORMAT_INDEX} DEP_FORMAT)
+ list(GET CMAKE_DEPENDS_DEPENDENCY_FILES \${DEP_INDEX} DEP_FILE)
+ if (NOT EXISTS \"${CMAKE_CURRENT_BINARY_DIR}/\${DEP_FILE}\")
+ set(RunCMake_TEST_FAILED \"File \${DEP_FILE} not found.\")
+ else()
+ cmake_path(APPEND TARGET_DEP_FILE \"${CMAKE_CURRENT_BINARY_DIR}\" \"\${DEPEND_INFO_FILE}\")
+ cmake_path(REPLACE_FILENAME TARGET_DEP_FILE \"compiler_depend.make\")
+ file(READ \"\${TARGET_DEP_FILE}\" DEPENDS_CONTENT)
+ if (WIN32)
+ string (REPLACE \"\\\\\" \"/\" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ string (TOLOWER \"\${DEPENDS_CONTENT}\" DEPENDS_CONTENT)
+ string (TOLOWER \"\${OBJECT_FILE}\" OBJECT_FILE)
+ else()
+ string(REPLACE \"\\\\ \" \" \" DEPENDS_CONTENT \"\${DEPENDS_CONTENT}\")
+ endif()
+ if(DEPEND_INFO_FILE MATCHES \"main\\\\.dir\")
+ if (DEP_FORMAT STREQUAL \"gcc\" AND NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+ endif()
+ if (DEP_FORMAT STREQUAL \"custom\" AND NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c.in\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+ endif()
+ else()
+ if (NOT DEPENDS_CONTENT MATCHES \"\${OBJECT_FILE} *:.+main.c.in\")
+ set(RunCMake_TEST_FAILED \"Dependency file '\${TARGET_DEP_FILE}' badly generated:\\n\${DEPENDS_CONTENT}\")
+ endif()
+ endif()
+ endif()
+ endforeach()
+ endif()
+ endforeach()
+ endif()
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake
new file mode 100644
index 0000000..87576eb
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step1.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c.in" [[
+int main(void) { return 1; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake
new file mode 100644
index 0000000..69b21b8
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDependencies.step2.cmake
@@ -0,0 +1,3 @@
+file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.c.in" [[
+int main(void) { return 2; }
+]])
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
new file mode 100644
index 0000000..6ac1291
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
@@ -0,0 +1,61 @@
+cmake_policy(SET CMP0116 NEW)
+enable_language(C)
+
+add_custom_command(
+ OUTPUT topcc.c
+ DEPFILE topcc.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=topcc.c -DINFILE=topccdep.txt -DDEPFILE=topcc.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+ )
+add_custom_target(topcc ALL DEPENDS topcc.c)
+
+add_custom_command(
+ OUTPUT topexe.c
+ DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/topexe.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=topexe.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/topexedep.txt" -DDEPFILE=topexe.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+ )
+add_executable(topexe "${CMAKE_CURRENT_BINARY_DIR}/topexe.c")
+
+add_custom_command(
+ OUTPUT toplib.c
+ DEPFILE toplib.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=toplib.c -DINFILE=toplibdep.txt -DDEPFILE=toplib.c.d -P "${CMAKE_CURRENT_LIST_DIR}/WriteDepfile.cmake"
+ )
+add_library(toplib STATIC toplib.c)
+
+add_subdirectory(DepfileSubdir)
+
+file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
+function(check_exists file)
+ if(NOT EXISTS \"\${file}\")
+ string(APPEND RunCMake_TEST_FAILED \"\${file} does not exist\\n\")
+ endif()
+ set(RunCMake_TEST_FAILED \"\${RunCMake_TEST_FAILED}\" PARENT_SCOPE)
+endfunction()
+
+function(check_not_exists file)
+ if(EXISTS \"\${file}\")
+ string(APPEND RunCMake_TEST_FAILED \"\${file} exists\\n\")
+ endif()
+ set(RunCMake_TEST_FAILED \"\${RunCMake_TEST_FAILED}\" PARENT_SCOPE)
+endfunction()
+
+set(check_pairs
+ \"${CMAKE_BINARY_DIR}/topcc.c|${CMAKE_BINARY_DIR}/topccdep.txt\"
+ \"$<TARGET_FILE:topexe>|${CMAKE_BINARY_DIR}/topexedep.txt\"
+ \"$<TARGET_FILE:toplib>|${CMAKE_BINARY_DIR}/toplibdep.txt\"
+ \"${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c|${CMAKE_BINARY_DIR}/DepfileSubdir/subccdep.txt\"
+ \"$<TARGET_FILE:subexe>|${CMAKE_BINARY_DIR}/DepfileSubdir/subexedep.txt\"
+ \"$<TARGET_FILE:sublib>|${CMAKE_BINARY_DIR}/DepfileSubdir/sublibdep.txt\"
+ )
+
+if(check_step EQUAL 3)
+ list(APPEND check_pairs
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/topcc.c\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:topexe>\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:toplib>\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|${CMAKE_BINARY_DIR}/DepfileSubdir/subcc.c\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:subexe>\"
+ \"${CMAKE_BINARY_DIR}/step3.timestamp|$<TARGET_FILE:sublib>\"
+ )
+endif()
+")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake
new file mode 100644
index 0000000..0dfe78e
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step1.cmake
@@ -0,0 +1,10 @@
+file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir")
+file(REMOVE "${RunCMake_TEST_BINARY_DIR}/../sublib.c")
+file(REMOVE "${RunCMake_TEST_BINARY_DIR}/step3.timestamp")
+
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake
new file mode 100644
index 0000000..c711514
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step2.cmake
@@ -0,0 +1,6 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/toplibdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subccdep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/subexedep.txt")
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/DepfileSubdir/sublibdep.txt")
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake
new file mode 100644
index 0000000..c55ccc1
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.step3.cmake
@@ -0,0 +1 @@
+file(TOUCH "${RunCMake_TEST_BINARY_DIR}/step3.timestamp")
diff --git a/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt b/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt
new file mode 100644
index 0000000..06db47c
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/DepfileSubdir/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_policy(SET CMP0116 NEW)
+
+add_custom_command(
+ OUTPUT subcc.c
+ DEPFILE subcc.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=subcc.c -DINFILE=subccdep.txt -DDEPFILE=subcc.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+ )
+add_custom_target(subcc ALL DEPENDS subcc.c)
+
+add_custom_command(
+ OUTPUT subexe.c
+ DEPFILE subexe.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=subexe.c -DINFILE=subexedep.txt -DDEPFILE=subexe.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+ )
+add_executable(subexe subexe.c)
+
+add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/../sublib.c
+ DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/sublib.c.d
+ COMMAND ${CMAKE_COMMAND} -DOUTFILE=${CMAKE_BINARY_DIR}/../sublib.c "-DINFILE=${CMAKE_CURRENT_BINARY_DIR}/sublibdep.txt" -DDEPFILE=sublib.c.d -P "${CMAKE_CURRENT_LIST_DIR}/../WriteDepfile.cmake"
+ )
+add_library(sublib STATIC "${CMAKE_BINARY_DIR}/../sublib.c")
diff --git a/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake b/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake
new file mode 100644
index 0000000..f7d0f13
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/GenerateDepFile.cmake
@@ -0,0 +1,6 @@
+file(READ "${INFILE}" INCONTENT)
+file(WRITE "${OUTFILE}" "${INCONTENT}")
+
+string(REPLACE [[ ]] [[\ ]] OUTFILE "${OUTFILE}")
+string(REPLACE [[ ]] [[\ ]] INFILE "${INFILE}")
+file(WRITE "${DEPFILE}" "${OUTFILE}: ${INFILE}\n")
diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
index 23e222a..1b7b8d9 100644
--- a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
+++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake
@@ -30,8 +30,17 @@ function(run_BuildDepends CASE)
include(${RunCMake_SOURCE_DIR}/${CASE}.step2.cmake OPTIONAL)
set(check_step 2)
run_cmake_command(${CASE}-build2 ${CMAKE_COMMAND} --build . --config Debug)
+ if(run_BuildDepends_skip_step_3)
+ return()
+ endif()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${fs_delay}) # handle 1s resolution
+ include(${RunCMake_SOURCE_DIR}/${CASE}.step3.cmake OPTIONAL)
+ set(check_step 3)
+ run_cmake_command(${CASE}-build3 ${CMAKE_COMMAND} --build . --config Debug)
endfunction()
+set(run_BuildDepends_skip_step_3 1)
+
run_BuildDepends(C-Exe)
if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
if(RunCMake_GENERATOR MATCHES "Visual Studio 10" OR
@@ -122,4 +131,15 @@ if ((RunCMake_GENERATOR STREQUAL "Unix Makefiles"
AND MSVC_VERSION GREATER 1300
AND CMAKE_C_COMPILER_ID STREQUAL "MSVC"))
run_BuildDepends(CompilerDependencies)
+ run_BuildDepends(CustomCommandDependencies)
+endif()
+
+if (RunCMake_GENERATOR MATCHES "Makefiles")
+ run_cmake(CustomCommandDependencies-BadArgs)
+endif()
+
+if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+ unset(run_BuildDepends_skip_step_3)
+ run_BuildDepends(CustomCommandDepfile)
+ set(run_BuildDepends_skip_step_3 1)
endif()
diff --git a/Tests/RunCMake/BuildDepends/WriteDepfile.cmake b/Tests/RunCMake/BuildDepends/WriteDepfile.cmake
new file mode 100644
index 0000000..c958cde
--- /dev/null
+++ b/Tests/RunCMake/BuildDepends/WriteDepfile.cmake
@@ -0,0 +1,8 @@
+file(WRITE "${OUTFILE}" [[int main(void)
+{
+ return 0;
+}
+]])
+string(REPLACE [[ ]] [[\ ]] OUTFILE "${OUTFILE}")
+string(REPLACE [[ ]] [[\ ]] INFILE "${INFILE}")
+file(WRITE "${DEPFILE}" "${OUTFILE}: ${INFILE}\n")
diff --git a/Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative-stderr.txt b/Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative-stderr.txt
new file mode 100644
index 0000000..3defcb4
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative-stderr.txt
@@ -0,0 +1,3 @@
+ *Relative source directory specified. This is not safe, as it depends on
+ *the calling directory scope.
++ *FETCHCONTENT_SOURCE_DIR_WITHPROJECT --> WithProject
diff --git a/Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative.cmake b/Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative.cmake
new file mode 100644
index 0000000..d8b42ba
--- /dev/null
+++ b/Tests/RunCMake/FetchContent/ManualSourceDirectoryRelative.cmake
@@ -0,0 +1 @@
+include(ManualSourceDirectory.cmake)
diff --git a/Tests/RunCMake/FetchContent/RunCMakeTest.cmake b/Tests/RunCMake/FetchContent/RunCMakeTest.cmake
index 3eb331f..9baeab7 100644
--- a/Tests/RunCMake/FetchContent/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FetchContent/RunCMakeTest.cmake
@@ -21,6 +21,11 @@ run_cmake_with_options(ManualSourceDirectory
run_cmake_with_options(ManualSourceDirectoryMissing
-D "FETCHCONTENT_SOURCE_DIR_WITHPROJECT=${CMAKE_CURRENT_LIST_DIR}/ADirThatDoesNotExist"
)
+# Need to use :STRING to prevent CMake from automatically converting it to an
+# absolute path
+run_cmake_with_options(ManualSourceDirectoryRelative
+ -D "FETCHCONTENT_SOURCE_DIR_WITHPROJECT:STRING=WithProject"
+)
function(run_FetchContent_DirOverrides)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/DirOverrides-build)
diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt
deleted file mode 100644
index 74d62a4..0000000
--- a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR-stderr.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-^CMake Error at CustomCommandDepfile-ERROR.cmake:1 \(add_custom_command\):
- add_custom_command Option DEPFILE not supported by [^
-]+
-Call Stack \(most recent call first\):
- CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake b/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake
deleted file mode 100644
index bad7955..0000000
--- a/Tests/RunCMake/Make/CustomCommandDepfile-ERROR.cmake
+++ /dev/null
@@ -1,8 +0,0 @@
-add_custom_command(
- OUTPUT hello.copy.c
- COMMAND "${CMAKE_COMMAND}" -E copy
- "${CMAKE_CURRENT_SOURCE_DIR}/hello.c"
- hello.copy.c
- WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
- DEPFILE "test.d"
- )
diff --git a/Tests/RunCMake/Make/RunCMakeTest.cmake b/Tests/RunCMake/Make/RunCMakeTest.cmake
index b66e30e..c7717ec 100644
--- a/Tests/RunCMake/Make/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Make/RunCMakeTest.cmake
@@ -39,7 +39,6 @@ function(run_VerboseBuild)
endfunction()
run_VerboseBuild()
-run_cmake(CustomCommandDepfile-ERROR)
run_cmake(IncludeRegexSubdir)
function(run_MakefileConflict)
diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
index abba741..8e0a3bc 100644
--- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake
@@ -3,6 +3,7 @@ include(RunCMake)
run_cmake(ExplicitCMakeLists)
run_cmake(ImplicitCMakeLists)
run_cmake(InterfaceLibSources)
+run_cmake_with_options(SearchPaths -DCMAKE_CONFIGURATION_TYPES=Debug)
run_cmake(XcodeFileType)
run_cmake(XcodeAttributeLocation)
diff --git a/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake b/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake
new file mode 100644
index 0000000..71b7d8f
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/SearchPaths-check.cmake
@@ -0,0 +1,76 @@
+set(xcProjectFile "${RunCMake_TEST_BINARY_DIR}/SearchPaths.xcodeproj/project.pbxproj")
+if(NOT EXISTS "${xcProjectFile}")
+ set(RunCMake_TEST_FAILED "Project file ${xcProjectFile} does not exist.")
+ return()
+endif()
+
+set(relevant_lines "")
+set(found_project_FRAMEWORK_SEARCH_PATHS 0)
+set(found_target_both_FRAMEWORK_SEARCH_PATHS 0)
+set(found_target_include_FRAMEWORK_SEARCH_PATHS 0)
+set(found_target_library_FRAMEWORK_SEARCH_PATHS 0)
+set(found_inherited_FRAMEWORK_SEARCH_PATHS 0)
+set(found_project_LIBRARY_SEARCH_PATHS 0)
+set(found_target_library_LIBRARY_SEARCH_PATHS 0)
+set(found_inherited_LIBRARY_SEARCH_PATHS 0)
+file(STRINGS "${xcProjectFile}" lines)
+foreach(line IN LISTS lines)
+ if(line MATCHES [[FRAMEWORK_SEARCH_PATHS]])
+ string(APPEND relevant_lines " ${line}\n")
+ if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = "[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/ProjectSearchPath";]])
+ set(found_project_FRAMEWORK_SEARCH_PATHS 1)
+ endif()
+ if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathInc(\\")?","(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib(\\")?","\$\(inherited\)"\);]])
+ set(found_target_both_FRAMEWORK_SEARCH_PATHS 1)
+ endif()
+ if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathInc(\\")?","\$\(inherited\)"\);]])
+ set(found_target_include_FRAMEWORK_SEARCH_PATHS 1)
+ endif()
+ if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib(\\")?","\$\(inherited\)"\);]])
+ set(found_target_library_FRAMEWORK_SEARCH_PATHS 1)
+ endif()
+ if(line MATCHES [[FRAMEWORK_SEARCH_PATHS = \("\$\(inherited\)"\);]])
+ set(found_inherited_FRAMEWORK_SEARCH_PATHS 1)
+ endif()
+ endif()
+
+ if(line MATCHES [[LIBRARY_SEARCH_PATHS]])
+ string(APPEND relevant_lines " ${line}\n")
+ if(line MATCHES [[LIBRARY_SEARCH_PATHS = "[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/ProjectSearchPath";]])
+ set(found_project_LIBRARY_SEARCH_PATHS 1)
+ endif()
+ if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib/\$\(CONFIGURATION\)\$\(EFFECTIVE_PLATFORM_NAME\)(\\")?","(\\")?[^"]*/Tests/RunCMake/XcodeProject/SearchPaths-build/TargetSearchPathLib(\\")?","\$\(inherited\)"\);]])
+ set(found_target_library_LIBRARY_SEARCH_PATHS 1)
+ endif()
+ if(line MATCHES [[LIBRARY_SEARCH_PATHS = \("\$\(inherited\)"\);]])
+ set(found_inherited_LIBRARY_SEARCH_PATHS 1)
+ endif()
+ endif()
+endforeach()
+if(NOT found_project_FRAMEWORK_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Did not find expected FRAMEWORK_SEARCH_PATHS for project in\n ${xcProjectFile}\n")
+endif()
+if(NOT found_target_both_FRAMEWORK_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Did not find expected FRAMEWORK_SEARCH_PATHS for target 'both' in\n ${xcProjectFile}\n")
+endif()
+if(NOT found_target_include_FRAMEWORK_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'include' in\n ${xcProjectFile}\n")
+endif()
+if(NOT found_target_library_FRAMEWORK_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'library' in\n ${xcProjectFile}\n")
+endif()
+if(found_inherited_FRAMEWORK_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Found unexpected LIBRARY_SEARCH_PATHS inherited-only value in\n ${xcProjectFile}\n")
+endif()
+if(NOT found_project_LIBRARY_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for project in\n ${xcProjectFile}\n")
+endif()
+if(NOT found_target_library_LIBRARY_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Did not find expected LIBRARY_SEARCH_PATHS for target 'library' in\n ${xcProjectFile}\n")
+endif()
+if(found_inherited_LIBRARY_SEARCH_PATHS)
+ string(APPEND RunCMake_TEST_FAILED "Found unexpected LIBRARY_SEARCH_PATHS inherited-only value in\n ${xcProjectFile}\n")
+endif()
+if(RunCMake_TEST_FAILED)
+ string(APPEND RunCMake_TEST_FAILED "Relevant lines include\n${relevant_lines}")
+endif()
diff --git a/Tests/RunCMake/XcodeProject/SearchPaths.cmake b/Tests/RunCMake/XcodeProject/SearchPaths.cmake
new file mode 100644
index 0000000..ef97709
--- /dev/null
+++ b/Tests/RunCMake/XcodeProject/SearchPaths.cmake
@@ -0,0 +1,21 @@
+enable_language(C)
+
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathInc/TargetInc.framework")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
+
+set(CMAKE_XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
+set(CMAKE_XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "${CMAKE_CURRENT_BINARY_DIR}/ProjectSearchPath")
+
+add_executable(neither main.c)
+
+add_executable(both main.c)
+target_include_directories(both PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathInc/TargetInc.framework")
+target_link_libraries(both PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
+
+add_executable(include main.c)
+target_include_directories(include PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathInc/TargetInc.framework")
+
+add_executable(library main.c)
+target_link_libraries(library PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib/TargetLib.framework")
+target_link_directories(library PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/TargetSearchPathLib")
diff --git a/Utilities/Release/linux/aarch64/Dockerfile b/Utilities/Release/linux/aarch64/Dockerfile
new file mode 100644
index 0000000..4077b79
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/Dockerfile
@@ -0,0 +1,35 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Produce an image containing a portable CMake binary package for Linux/aarch64.
+# Build using the CMake source directory as the build context.
+# The resulting image will have an '/out' directory containing the package.
+
+# Keep this in sync with the `.gitlab-ci.yml` `release_linux` image.
+ARG FROM_IMAGE_NAME=kitware/cmake:build-linux-aarch64-deps-2020-12-21
+ARG FROM_IMAGE_DIGEST=@sha256:0bd7dfe4e45593b04e39cd21e44011034610cfd376900558c5ef959bb1af15af
+ARG FROM_IMAGE=$FROM_IMAGE_NAME$FROM_IMAGE_DIGEST
+FROM $FROM_IMAGE
+
+COPY . /opt/cmake/src/cmake
+
+ARG TEST=true
+
+RUN : \
+ && mkdir -p /opt/cmake/src/cmake-build \
+ && cd /opt/cmake/src/cmake-build \
+ && cp ../cmake/Utilities/Release/linux/aarch64/cache.txt CMakeCache.txt \
+ && source /opt/rh/devtoolset-7/enable \
+ && set -x \
+ && ../cmake/bootstrap --parallel=$(nproc) --docdir=doc/cmake \
+ && nice make -j $(nproc) \
+ && if $TEST; then \
+ # Run tests that require the full build tree.
+ bin/ctest --output-on-failure -j 8 -R '^(CMake\.|CMakeLib\.|CMakeServerLib\.|RunCMake\.ctest_memcheck)'; \
+ fi \
+ && bin/cpack -G TGZ \
+ && bin/cpack -G STGZ \
+ && set +x \
+ && mkdir /out \
+ && mv cmake-*-Linux-aarch64.* /out \
+ && :
diff --git a/Utilities/Release/linux/aarch64/base/Dockerfile b/Utilities/Release/linux/aarch64/base/Dockerfile
new file mode 100644
index 0000000..b9c683e
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/base/Dockerfile
@@ -0,0 +1,31 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Produce a base image with a build environment for portable CMake binaries.
+# Build using the directory containing this file as its own build context.
+
+ARG FROM_IMAGE_NAME=centos:7
+ARG FROM_IMAGE_DIGEST=@sha256:43964203bf5d7fe38c6fca6166ac89e4c095e2b0c0a28f6c7c678a1348ddc7fa
+ARG FROM_IMAGE=$FROM_IMAGE_NAME$FROM_IMAGE_DIGEST
+FROM $FROM_IMAGE
+
+RUN : \
+ && yum install -y centos-release-scl \
+ && yum install -y \
+ ca-certificates \
+ curl \
+ devtoolset-7-gcc \
+ devtoolset-7-gcc-c++ \
+ fontconfig-devel \
+ freetype-devel \
+ git \
+ libX11-devel \
+ libxcb-devel \
+ make \
+ patch \
+ perl \
+ python3-pip \
+ xz \
+ which \
+ && yum clean all \
+ && :
diff --git a/Utilities/Release/linux/aarch64/cache.txt b/Utilities/Release/linux/aarch64/cache.txt
new file mode 100644
index 0000000..89050d1
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/cache.txt
@@ -0,0 +1,44 @@
+CMAKE_BUILD_TYPE:STRING=Release
+
+CMAKE_C_STANDARD:STRING=11
+CMAKE_CXX_STANDARD:STRING=14
+
+# Require only older APIs where possible.
+CMAKE_C_FLAGS:STRING=-D_POSIX_C_SOURCE=199506L -D_POSIX_SOURCE=1 -D_SVID_SOURCE=1 -D_BSD_SOURCE=1
+
+# Link C++ library statically.
+CMAKE_EXE_LINKER_FLAGS:STRING=-static-libstdc++ -static-libgcc
+
+# Enable ssl support in curl
+CMAKE_USE_OPENSSL:BOOL=ON
+OPENSSL_CRYPTO_LIBRARY:STRING=/opt/openssl/lib/libcrypto.a;-pthread
+OPENSSL_INCLUDE_DIR:PATH=/opt/openssl/include
+OPENSSL_SSL_LIBRARY:FILEPATH=/opt/openssl/lib/libssl.a
+
+# Enable ccmake
+BUILD_CursesDialog:BOOL=ON
+CURSES_FORM_LIBRARY:FILEPATH=/opt/ncurses/lib/libform.a
+CURSES_INCLUDE_PATH:PATH=/opt/ncurses/include
+CURSES_NCURSES_LIBRARY:FILEPATH=/opt/ncurses/lib/libncurses.a
+
+# Enable cmake-gui with static qt plugins
+BUILD_QtDialog:BOOL=TRUE
+CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=3
+CMAKE_PREFIX_PATH:STRING=/opt/qt
+CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES:STRING=/opt/qt/plugins/platforms/libqxcb.a;/opt/qt/lib/libQt5XcbQpa.a;/opt/qt/lib/libQt5ServiceSupport.a;/opt/qt/lib/libQt5EdidSupport.a;/opt/qt/lib/libQt5EventDispatcherSupport.a;/opt/qt/lib/libQt5FontDatabaseSupport.a;/opt/qt/lib/libQt5ThemeSupport.a;/opt/qt/lib/libxcb-static.a;-lxcb;-lfontconfig;-lfreetype
+
+# Build documentation.
+SPHINX_EXECUTABLE:FILEPATH=/usr/local/bin/sphinx-build
+SPHINX_HTML:BOOL=ON
+SPHINX_MAN:BOOL=ON
+SPHINX_QTHELP:BOOL=ON
+QCOLLECTIONGENERATOR_EXECUTABLE:PATH=/opt/qt/bin/qhelpgenerator
+
+# We bootstrap as part of the build so skip its test.
+CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
+
+# Skip Qt5 tests because our Qt is static.
+CMake_TEST_Qt5:BOOL=FALSE
+
+# CPack package file name component for this platform.
+CPACK_SYSTEM_NAME:STRING=Linux-aarch64
diff --git a/Utilities/Release/linux/aarch64/deps/Dockerfile b/Utilities/Release/linux/aarch64/deps/Dockerfile
new file mode 100644
index 0000000..8d0f6fd
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/deps/Dockerfile
@@ -0,0 +1,141 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Produce an image with custom-built dependencies for portable CMake binaries.
+# Build using the directory containing this file as its own build context.
+
+ARG FROM_IMAGE_NAME=kitware/cmake:build-linux-aarch64-base-2020-12-21
+ARG FROM_IMAGE_DIGEST=@sha256:c8d9fa279ef09c26e74ff28770ae0db1f4cb75ef53b782ace604daba71a41f65
+ARG FROM_IMAGE=$FROM_IMAGE_NAME$FROM_IMAGE_DIGEST
+FROM $FROM_IMAGE
+
+# Sphinx
+RUN : \
+ && pip3 install sphinx==2.1.2 \
+ && :
+
+# Qt
+# Version 5.12.0 was the last to bundle xkbcommon.
+COPY qt-install.patch /opt/qt/src/
+RUN : \
+ && mkdir -p /opt/qt/src/qt-build \
+ && cd /opt/qt/src \
+ && curl -OL https://download.qt.io/archive/qt/5.12/5.12.0/single/qt-everywhere-src-5.12.0.tar.xz \
+ && sha512sum qt-everywhere-src-5.12.0.tar.xz | grep -q 0dd03d2645fb6dac5b58c8caf92b4a0a6900131f1ccfb02443a0df4702b5da0458f4c45e758d1b929ec709b0f4b36900df2fd60a058af9cc8c1a0748b6d57aae \
+ && tar xJf qt-everywhere-src-5.12.0.tar.xz \
+ && cd qt-build \
+ && source /opt/rh/devtoolset-7/enable \
+ && ../qt-everywhere-src-5.12.0/configure \
+ -prefix /opt/qt \
+ -static \
+ -release \
+ -c++std c++11 \
+ -opensource -confirm-license \
+ -gui \
+ -widgets \
+ -xcb \
+ -fontconfig \
+ -sql-sqlite \
+ -qt-doubleconversion \
+ -qt-libjpeg \
+ -qt-libpng \
+ -qt-pcre \
+ -qt-sqlite \
+ -qt-xcb \
+ -qt-xkbcommon \
+ -qt-zlib \
+ -system-freetype \
+ -no-accessibility \
+ -no-compile-examples \
+ -no-cups \
+ -no-dbus \
+ -no-directfb \
+ -no-egl \
+ -no-eglfs \
+ -no-evdev \
+ -no-gbm \
+ -no-gif \
+ -no-glib \
+ -no-gtk \
+ -no-harfbuzz \
+ -no-iconv \
+ -no-icu \
+ -no-journald \
+ -no-kms \
+ -no-libinput \
+ -no-libproxy \
+ -no-linuxfb \
+ -no-ltcg \
+ -no-mirclient \
+ -no-mtdev \
+ -no-opengl \
+ -no-openssl \
+ -no-pch \
+ -no-sql-mysql \
+ -no-sql-psql \
+ -no-sql-sqlite2 \
+ -no-syslog \
+ -no-system-proxies \
+ -no-tslib \
+ -no-use-gold-linker \
+ -skip declarative \
+ -skip multimedia \
+ -skip qtcanvas3d \
+ -skip qtconnectivity \
+ -skip qtdeclarative \
+ -skip qtlocation \
+ -skip qtmultimedia \
+ -skip qtsensors \
+ -skip qtserialport \
+ -skip qtsvg \
+ -skip qtwayland \
+ -skip qtwebchannel \
+ -skip qtwebengine \
+ -skip qtwebsockets \
+ -skip qtwinextras \
+ -skip qtxmlpatterns \
+ -nomake examples \
+ -nomake tests \
+ && make install -j $(nproc) \
+ && cd /opt/qt \
+ && patch -p1 -i src/qt-install.patch \
+ && cd /opt \
+ && rm -rf /opt/qt/src \
+ && :
+
+# Curses
+RUN : \
+ && mkdir -p /opt/ncurses/src/ncurses-build \
+ && cd /opt/ncurses/src \
+ && curl -O https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz \
+ && sha512sum ncurses-6.1.tar.gz | grep -q e308af43f8b7e01e98a55f4f6c4ee4d1c39ce09d95399fa555b3f0cdf5fd0db0f4c4d820b4af78a63f6cf6d8627587114a40af48cfc066134b600520808a77ee \
+ && tar xzf ncurses-6.1.tar.gz \
+ && cd ncurses-build \
+ && source /opt/rh/devtoolset-7/enable \
+ && ../ncurses-6.1/configure \
+ --prefix=/opt/ncurses \
+ --with-terminfo-dirs=/etc/terminfo:/lib/terminfo:/usr/share/terminfo \
+ --with-default-terminfo-dir=/usr/share/terminfo \
+ --without-shared \
+ && make -j $(nproc) \
+ && make install.libs install.includes \
+ && cd /opt \
+ && rm -rf /opt/ncurses/src \
+ && :
+
+# OpenSSL
+COPY openssl-source.patch /opt/openssl/src/
+RUN : \
+ && mkdir -p /opt/openssl/src \
+ && cd /opt/openssl/src \
+ && curl -O https://www.openssl.org/source/openssl-1.1.1f.tar.gz \
+ && sha512sum openssl-1.1.1f.tar.gz | grep -q b00bd9b5ad5298fbceeec6bb19c1ab0c106ca5cfb31178497c58bf7e0e0cf30fcc19c20f84e23af31cc126bf2447d3e4f8461db97bafa7bd78f69561932f000c \
+ && tar xzf openssl-1.1.1f.tar.gz \
+ && cd openssl-1.1.1f \
+ && patch -p1 -i ../openssl-source.patch \
+ && source /opt/rh/devtoolset-7/enable \
+ && ./Configure --prefix=/opt/openssl linux-elf no-asm no-shared -D_POSIX_C_SOURCE=199506L -D_POSIX_SOURCE=1 -D_SVID_SOURCE=1 -D_BSD_SOURCE=1 \
+ && make install_dev -j $(nproc) \
+ && cd /opt \
+ && rm -rf /opt/openssl/src \
+ && :
diff --git a/Utilities/Release/linux/aarch64/deps/openssl-source.patch b/Utilities/Release/linux/aarch64/deps/openssl-source.patch
new file mode 100644
index 0000000..c81fe2f
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/deps/openssl-source.patch
@@ -0,0 +1,12 @@
+# enable pthread APIs disabled by our _POSIX_SOURCE definitions
+--- openssl-source/crypto/threads_pthread.c.orig
++++ openssl-source/crypto/threads_pthread.c
+@@ -6,6 +6,8 @@
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
++#undef _POSIX_C_SOURCE
++#undef _POSIX_SOURCE
+
+ #include <openssl/crypto.h>
+ #include "internal/cryptlib.h"
diff --git a/Utilities/Release/linux/aarch64/deps/qt-install.patch b/Utilities/Release/linux/aarch64/deps/qt-install.patch
new file mode 100644
index 0000000..792aefd
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/deps/qt-install.patch
@@ -0,0 +1,24 @@
+# Add Qt Core dependencies missing from static Qt build.
+--- qt-install/lib/cmake/Qt5Core/Qt5CoreConfig.cmake.orig
++++ qt-install/lib/cmake/Qt5Core/Qt5CoreConfig.cmake
+@@ -111,7 +111,7 @@
+ list(REMOVE_DUPLICATES Qt5Core_COMPILE_DEFINITIONS)
+ list(REMOVE_DUPLICATES Qt5Core_EXECUTABLE_COMPILE_FLAGS)
+
+- set(_Qt5Core_LIB_DEPENDENCIES "")
++ set(_Qt5Core_LIB_DEPENDENCIES "${_qt5Core_install_prefix}/lib/libqtpcre2.a")
+
+
+ add_library(Qt5::Core STATIC IMPORTED)
+# Add Qt Gui dependencies missing from static Qt build.
+--- qt-install/lib/cmake/Qt5Gui/Qt5GuiConfig.cmake.orig
++++ qt-install/lib/cmake/Qt5Gui/Qt5GuiConfig.cmake
+@@ -111,7 +111,7 @@
+ list(REMOVE_DUPLICATES Qt5Gui_COMPILE_DEFINITIONS)
+ list(REMOVE_DUPLICATES Qt5Gui_EXECUTABLE_COMPILE_FLAGS)
+
+- set(_Qt5Gui_LIB_DEPENDENCIES "Qt5::Core")
++ set(_Qt5Gui_LIB_DEPENDENCIES "Qt5::Core;${_qt5Gui_install_prefix}/lib/libqtlibpng.a")
+
+
+ add_library(Qt5::Gui STATIC IMPORTED)
diff --git a/Utilities/Release/linux/aarch64/test/Dockerfile b/Utilities/Release/linux/aarch64/test/Dockerfile
new file mode 100644
index 0000000..03674fb
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/test/Dockerfile
@@ -0,0 +1,26 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Produce a base image with a test environment for packaged CMake binaries.
+# Build using the directory containing this file as its own build context.
+
+ARG FROM_IMAGE_NAME=debian:10
+ARG FROM_IMAGE_DIGEST=@sha256:ab0ba5b78bfe01d61ac4f9919cd0e7bef8beefa0a77d3d710bfc8630d96804b8
+ARG FROM_IMAGE=$FROM_IMAGE_NAME$FROM_IMAGE_DIGEST
+FROM $FROM_IMAGE
+
+RUN : \
+ && apt-get update \
+ && apt-get install -y \
+ dpkg \
+ file \
+ gcc \
+ g++ \
+ gfortran \
+ qt5-default \
+ make \
+ ninja-build \
+ && apt-get clean \
+ && :
+
+COPY test-make.bash test-ninja.bash /
diff --git a/Utilities/Release/linux/aarch64/test/test-make.bash b/Utilities/Release/linux/aarch64/test/test-make.bash
new file mode 100644
index 0000000..10d30c3
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/test/test-make.bash
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+set -e
+set -x
+mkdir -p /opt/cmake/src/cmake-make
+cd /opt/cmake/src/cmake-make
+echo >CMakeCache.txt '
+CMake_TEST_IPO_WORKS_C:BOOL=ON
+CMake_TEST_IPO_WORKS_CXX:BOOL=ON
+CMake_TEST_IPO_WORKS_Fortran:BOOL=ON
+CMake_TEST_NO_NETWORK:BOOL=ON
+CMake_TEST_Qt5:BOOL=ON
+'
+cmake ../cmake -DCMake_TEST_HOST_CMAKE=1 -G "Unix Makefiles"
+make -j $(nproc)
+ctest --output-on-failure -j $(nproc)
diff --git a/Utilities/Release/linux/aarch64/test/test-ninja.bash b/Utilities/Release/linux/aarch64/test/test-ninja.bash
new file mode 100644
index 0000000..fe39e2e
--- /dev/null
+++ b/Utilities/Release/linux/aarch64/test/test-ninja.bash
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+set -e
+set -x
+mkdir -p /opt/cmake/src/cmake-ninja
+cd /opt/cmake/src/cmake-ninja
+echo >CMakeCache.txt '
+CMAKE_Fortran_COMPILER:STRING=
+CMake_TEST_IPO_WORKS_C:BOOL=ON
+CMake_TEST_IPO_WORKS_CXX:BOOL=ON
+CMake_TEST_NO_NETWORK:BOOL=ON
+CMake_TEST_Qt5:BOOL=ON
+'
+cmake ../cmake -DCMake_TEST_HOST_CMAKE=1 -G "Ninja"
+ninja
+ctest --output-on-failure -j $(nproc)