mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-21 23:00:50 +08:00
project(): Add new CMAKE_PROJECT_TOP_LEVEL_INCLUDES file injection point
Fixes: #22685
This commit is contained in:
@@ -123,28 +123,56 @@ The options are:
|
|||||||
The variables set through the ``VERSION``, ``DESCRIPTION`` and ``HOMEPAGE_URL``
|
The variables set through the ``VERSION``, ``DESCRIPTION`` and ``HOMEPAGE_URL``
|
||||||
options are intended for use as default values in package metadata and documentation.
|
options are intended for use as default values in package metadata and documentation.
|
||||||
|
|
||||||
|
.. _`Code Injection`:
|
||||||
|
|
||||||
Code Injection
|
Code Injection
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
If the :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` or
|
A number of variables can be defined by the user to specify files to include
|
||||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` variables are set,
|
at different points during the execution of the ``project()`` command.
|
||||||
the files they point to will be included as the first step of the
|
The following outlines the steps performed during a ``project()`` call:
|
||||||
``project()`` command.
|
|
||||||
If both are set, then :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` will be
|
|
||||||
included before :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`.
|
|
||||||
|
|
||||||
If the :variable:`CMAKE_PROJECT_INCLUDE` or
|
* .. versionadded:: 3.15
|
||||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` variables are set, the files
|
For every ``project()`` call regardless of the project
|
||||||
they point to will be included as the last step of the ``project()`` command.
|
name, include the file named by :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
|
||||||
If both are set, then :variable:`CMAKE_PROJECT_INCLUDE` will be included before
|
if set.
|
||||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`.
|
|
||||||
|
|
||||||
.. versionadded:: 3.15
|
* .. versionadded:: 3.17
|
||||||
Added the ``CMAKE_PROJECT_INCLUDE`` and ``CMAKE_PROJECT_INCLUDE_BEFORE``
|
If the ``project()`` command specifies ``<PROJECT-NAME>`` as its project
|
||||||
variables.
|
name, include the file named by
|
||||||
|
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`, if set.
|
||||||
|
|
||||||
.. versionadded:: 3.17
|
* Set the various project-specific variables detailed in the `Synopsis`_
|
||||||
Added the ``CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`` variable.
|
and `Options`_ sections above.
|
||||||
|
|
||||||
|
* For the very first ``project()`` call only:
|
||||||
|
|
||||||
|
* If :variable:`CMAKE_TOOLCHAIN_FILE` is set, read it at least once.
|
||||||
|
It may be read multiple times and it may also be read again when
|
||||||
|
enabling languages later (see below).
|
||||||
|
|
||||||
|
* Set the variables describing the host and target platforms.
|
||||||
|
Language-specific variables might or might not be set at this point.
|
||||||
|
On the first run, the only language-specific variables that might be
|
||||||
|
defined are those a toolchain file may have set. On subsequent runs,
|
||||||
|
language-specific variables cached from a previous run may be set.
|
||||||
|
|
||||||
|
* .. versionadded:: 3.24
|
||||||
|
Include each file listed in :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES`,
|
||||||
|
if set. The variable is ignored by CMake thereafter.
|
||||||
|
|
||||||
|
* Enable any languages specified in the call, or the default languages if
|
||||||
|
none were provided. The toolchain file may be re-read when enabling a
|
||||||
|
language for the first time.
|
||||||
|
|
||||||
|
* .. versionadded:: 3.15
|
||||||
|
For every ``project()`` call regardless of the project
|
||||||
|
name, include the file named by :variable:`CMAKE_PROJECT_INCLUDE`,
|
||||||
|
if set.
|
||||||
|
|
||||||
|
* If the ``project()`` command specifies ``<PROJECT-NAME>`` as its project
|
||||||
|
name, include the file named by
|
||||||
|
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`, if set.
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
^^^^^
|
^^^^^
|
||||||
|
@@ -243,6 +243,7 @@ Variables that Change Behavior
|
|||||||
/variable/CMAKE_PROJECT_INCLUDE_BEFORE
|
/variable/CMAKE_PROJECT_INCLUDE_BEFORE
|
||||||
/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
|
/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
|
||||||
/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE
|
/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE
|
||||||
|
/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES
|
||||||
/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName
|
/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName
|
||||||
/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
|
/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
|
||||||
/variable/CMAKE_STAGING_PREFIX
|
/variable/CMAKE_STAGING_PREFIX
|
||||||
|
6
Help/release/dev/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.rst
Normal file
6
Help/release/dev/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.rst
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
CMAKE_PROJECT_TOP_LEVEL_INCLUDES
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
* The :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable was added to allow
|
||||||
|
injecting custom code at the site of the first :command:`project` call,
|
||||||
|
after the host and target platform details have been determined.
|
@@ -5,8 +5,11 @@ CMAKE_PROJECT_INCLUDE
|
|||||||
|
|
||||||
A CMake language file or module to be included as the last step of all
|
A CMake language file or module to be included as the last step of all
|
||||||
:command:`project` command calls. This is intended for injecting custom code
|
:command:`project` command calls. This is intended for injecting custom code
|
||||||
into project builds without modifying their source.
|
into project builds without modifying their source. See :ref:`Code Injection`
|
||||||
|
for a more detailed discussion of files potentially included during a
|
||||||
|
:command:`project` call.
|
||||||
|
|
||||||
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
|
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
|
||||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
|
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
|
||||||
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
|
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE`, and
|
||||||
|
:variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variables.
|
||||||
|
@@ -5,8 +5,11 @@ CMAKE_PROJECT_INCLUDE_BEFORE
|
|||||||
|
|
||||||
A CMake language file or module to be included as the first step of all
|
A CMake language file or module to be included as the first step of all
|
||||||
:command:`project` command calls. This is intended for injecting custom code
|
:command:`project` command calls. This is intended for injecting custom code
|
||||||
into project builds without modifying their source.
|
into project builds without modifying their source. See :ref:`Code Injection`
|
||||||
|
for a more detailed discussion of files potentially included during a
|
||||||
|
:command:`project` call.
|
||||||
|
|
||||||
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
|
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
|
||||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
|
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
|
||||||
:variable:`CMAKE_PROJECT_INCLUDE` variables.
|
:variable:`CMAKE_PROJECT_INCLUDE`, and
|
||||||
|
:variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variables.
|
||||||
|
@@ -4,8 +4,9 @@ CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE
|
|||||||
A CMake language file or module to be included as the last step of any
|
A CMake language file or module to be included as the last step of any
|
||||||
:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
|
:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
|
||||||
name. This is intended for injecting custom code into project builds without
|
name. This is intended for injecting custom code into project builds without
|
||||||
modifying their source.
|
modifying their source. See :ref:`Code Injection` for a more detailed
|
||||||
|
discussion of files potentially included during a :command:`project` call.
|
||||||
|
|
||||||
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
|
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
|
||||||
:variable:`CMAKE_PROJECT_INCLUDE` and
|
:variable:`CMAKE_PROJECT_INCLUDE`, :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
|
||||||
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
|
and :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variables.
|
||||||
|
@@ -6,8 +6,9 @@ CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE
|
|||||||
A CMake language file or module to be included as the first step of any
|
A CMake language file or module to be included as the first step of any
|
||||||
:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
|
:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
|
||||||
name. This is intended for injecting custom code into project builds without
|
name. This is intended for injecting custom code into project builds without
|
||||||
modifying their source.
|
modifying their source. See :ref:`Code Injection` for a more detailed
|
||||||
|
discussion of files potentially included during a :command:`project` call.
|
||||||
|
|
||||||
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
|
See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
|
||||||
:variable:`CMAKE_PROJECT_INCLUDE` and
|
:variable:`CMAKE_PROJECT_INCLUDE`, :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
|
||||||
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
|
and :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variables.
|
||||||
|
27
Help/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.rst
Normal file
27
Help/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES.rst
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
CMAKE_PROJECT_TOP_LEVEL_INCLUDES
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. versionadded:: 3.24
|
||||||
|
|
||||||
|
:ref:`Semicolon-separated list <CMake Language Lists>` of CMake language
|
||||||
|
files to include as part of the very first :command:`project` call.
|
||||||
|
The files will be included immediately after the toolchain file has been read
|
||||||
|
(if one is specified) and platform variables have been set, but before any
|
||||||
|
languages have been enabled. Therefore, language-specific variables,
|
||||||
|
including things like :variable:`CMAKE_<LANG>_COMPILER`, might not be set.
|
||||||
|
See :ref:`Code Injection` for a more detailed discussion of files potentially
|
||||||
|
included during a :command:`project` call.
|
||||||
|
|
||||||
|
This variable is intended for specifying files that perform one-time setup
|
||||||
|
for the build. It provides an injection point for things like configuring
|
||||||
|
package managers, adding logic the user shares between projects (e.g. defining
|
||||||
|
their own custom build types), and so on. It is primarily for users to add
|
||||||
|
things specific to their environment, but not for specifying the toolchain
|
||||||
|
details (use :variable:`CMAKE_TOOLCHAIN_FILE` for that).
|
||||||
|
|
||||||
|
By default, this variable is empty. It is intended to be set by the user.
|
||||||
|
|
||||||
|
See also the :variable:`CMAKE_PROJECT_INCLUDE`,
|
||||||
|
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
|
||||||
|
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`, and
|
||||||
|
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` variables.
|
@@ -13,3 +13,6 @@ build directory, and if not found, relative to the source directory.
|
|||||||
|
|
||||||
This is initialized by the :envvar:`CMAKE_TOOLCHAIN_FILE` environment
|
This is initialized by the :envvar:`CMAKE_TOOLCHAIN_FILE` environment
|
||||||
variable if it is set when a new build tree is first created.
|
variable if it is set when a new build tree is first created.
|
||||||
|
|
||||||
|
See the :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable for setting
|
||||||
|
other things not directly related to the toolchain.
|
||||||
|
@@ -688,6 +688,33 @@ void cmGlobalGenerator::EnableLanguage(
|
|||||||
if (!this->FindMakeProgram(mf)) {
|
if (!this->FindMakeProgram(mf)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One-time includes of user-provided project setup files
|
||||||
|
std::string includes =
|
||||||
|
mf->GetSafeDefinition("CMAKE_PROJECT_TOP_LEVEL_INCLUDES");
|
||||||
|
std::vector<std::string> includesList = cmExpandedList(includes);
|
||||||
|
for (std::string const& setupFile : includesList) {
|
||||||
|
std::string absSetupFile = cmSystemTools::CollapseFullPath(
|
||||||
|
setupFile, mf->GetCurrentSourceDirectory());
|
||||||
|
if (!cmSystemTools::FileExists(absSetupFile)) {
|
||||||
|
cmSystemTools::Error(
|
||||||
|
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES file does not exist: " +
|
||||||
|
setupFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cmSystemTools::FileIsDirectory(absSetupFile)) {
|
||||||
|
cmSystemTools::Error(
|
||||||
|
"CMAKE_PROJECT_TOP_LEVEL_INCLUDES file is a directory: " +
|
||||||
|
setupFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!mf->ReadListFile(absSetupFile)) {
|
||||||
|
cmSystemTools::Error(
|
||||||
|
"Failed reading CMAKE_PROJECT_TOP_LEVEL_INCLUDES file: " +
|
||||||
|
setupFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the languages are supported by the generator and its
|
// Check that the languages are supported by the generator and its
|
||||||
|
10
Tests/RunCMake/project/CodeInjection-stdout.txt
Normal file
10
Tests/RunCMake/project/CodeInjection-stdout.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE
|
||||||
|
(-- )?Included CMAKE_TOOLCHAIN_FILE
|
||||||
|
.*Included CMAKE_PROJECT_TOP_LEVEL_INCLUDES first file
|
||||||
|
(-- )?Included CMAKE_PROJECT_TOP_LEVEL_INCLUDES second file
|
||||||
|
(-- )?Included CMAKE_PROJECT_INCLUDE
|
||||||
|
(-- )?Calling sub-project
|
||||||
|
(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE
|
||||||
|
(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE
|
||||||
|
(-- )?Included CMAKE_PROJECT_INCLUDE
|
||||||
|
(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE
|
1
Tests/RunCMake/project/CodeInjection.cmake
Normal file
1
Tests/RunCMake/project/CodeInjection.cmake
Normal file
@@ -0,0 +1 @@
|
|||||||
|
add_subdirectory(CodeInjection)
|
2
Tests/RunCMake/project/CodeInjection/CMakeLists.txt
Normal file
2
Tests/RunCMake/project/CodeInjection/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
message(STATUS "Calling sub-project")
|
||||||
|
project(SubProj LANGUAGES NONE)
|
@@ -0,0 +1 @@
|
|||||||
|
message(STATUS "Included CMAKE_PROJECT_INCLUDE")
|
@@ -0,0 +1 @@
|
|||||||
|
message(STATUS "Included CMAKE_PROJECT_INCLUDE_BEFORE")
|
@@ -0,0 +1 @@
|
|||||||
|
message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE")
|
@@ -0,0 +1 @@
|
|||||||
|
message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE")
|
@@ -0,0 +1 @@
|
|||||||
|
message(STATUS "Included CMAKE_PROJECT_TOP_LEVEL_INCLUDES first file")
|
@@ -0,0 +1 @@
|
|||||||
|
message(STATUS "Included CMAKE_PROJECT_TOP_LEVEL_INCLUDES second file")
|
10
Tests/RunCMake/project/CodeInjection/initial_cache.cmake
Normal file
10
Tests/RunCMake/project/CodeInjection/initial_cache.cmake
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/passthrough_toolchain_file.cmake" CACHE FILEPATH "")
|
||||||
|
set(CMAKE_PROJECT_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/cmake_project_include.cmake" CACHE FILEPATH "")
|
||||||
|
set(CMAKE_PROJECT_INCLUDE_BEFORE "${CMAKE_CURRENT_LIST_DIR}/cmake_project_include_before.cmake" CACHE FILEPATH "")
|
||||||
|
set(CMAKE_PROJECT_SubProj_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_include.cmake" CACHE FILEPATH "")
|
||||||
|
set(CMAKE_PROJECT_SubProj_INCLUDE_BEFORE "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_include_before.cmake" CACHE FILEPATH "")
|
||||||
|
set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/cmake_project_top_level_includes_1.cmake"
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/cmake_project_top_level_includes_2.cmake"
|
||||||
|
CACHE STRING ""
|
||||||
|
)
|
@@ -0,0 +1 @@
|
|||||||
|
message(STATUS "Included CMAKE_TOOLCHAIN_FILE")
|
@@ -1,5 +1,14 @@
|
|||||||
include(RunCMake)
|
include(RunCMake)
|
||||||
|
|
||||||
|
# Use an initial cache file to define the project() variables
|
||||||
|
# to avoid long command lines. Also see the CMakeOnly test case
|
||||||
|
# which tests some of the individual variables one at a time.
|
||||||
|
# Here, we are focused on testing that the variables are all injected
|
||||||
|
# at the expected points in the expected order.
|
||||||
|
run_cmake_with_options(CodeInjection
|
||||||
|
-C "${CMAKE_CURRENT_LIST_DIR}/CodeInjection/initial_cache.cmake"
|
||||||
|
)
|
||||||
|
|
||||||
if(CMake_TEST_RESOURCES)
|
if(CMake_TEST_RESOURCES)
|
||||||
run_cmake(ExplicitRC)
|
run_cmake(ExplicitRC)
|
||||||
endif()
|
endif()
|
||||||
|
Reference in New Issue
Block a user