mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-21 06:10:16 +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``
|
||||
options are intended for use as default values in package metadata and documentation.
|
||||
|
||||
.. _`Code Injection`:
|
||||
|
||||
Code Injection
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
If the :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` or
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` variables are set,
|
||||
the files they point to will be included as the first step of the
|
||||
``project()`` command.
|
||||
If both are set, then :variable:`CMAKE_PROJECT_INCLUDE_BEFORE` will be
|
||||
included before :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`.
|
||||
A number of variables can be defined by the user to specify files to include
|
||||
at different points during the execution of the ``project()`` command.
|
||||
The following outlines the steps performed during a ``project()`` call:
|
||||
|
||||
If the :variable:`CMAKE_PROJECT_INCLUDE` or
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE` variables are set, the files
|
||||
they point to will be included as the last step of the ``project()`` command.
|
||||
If both are set, then :variable:`CMAKE_PROJECT_INCLUDE` will be included before
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`.
|
||||
* .. versionadded:: 3.15
|
||||
For every ``project()`` call regardless of the project
|
||||
name, include the file named by :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
|
||||
if set.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
Added the ``CMAKE_PROJECT_INCLUDE`` and ``CMAKE_PROJECT_INCLUDE_BEFORE``
|
||||
variables.
|
||||
* .. versionadded:: 3.17
|
||||
If the ``project()`` command specifies ``<PROJECT-NAME>`` as its project
|
||||
name, include the file named by
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`, if set.
|
||||
|
||||
.. versionadded:: 3.17
|
||||
Added the ``CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`` variable.
|
||||
* Set the various project-specific variables detailed in the `Synopsis`_
|
||||
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
|
||||
^^^^^
|
||||
|
@@ -243,6 +243,7 @@ Variables that Change Behavior
|
||||
/variable/CMAKE_PROJECT_INCLUDE_BEFORE
|
||||
/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE
|
||||
/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE
|
||||
/variable/CMAKE_PROJECT_TOP_LEVEL_INCLUDES
|
||||
/variable/CMAKE_REQUIRE_FIND_PACKAGE_PackageName
|
||||
/variable/CMAKE_SKIP_INSTALL_ALL_DEPENDENCY
|
||||
/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
|
||||
: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`,
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
|
||||
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
|
||||
: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
|
||||
: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`,
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE` and
|
||||
:variable:`CMAKE_PROJECT_INCLUDE` variables.
|
||||
:variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
|
||||
: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
|
||||
:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
|
||||
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`,
|
||||
:variable:`CMAKE_PROJECT_INCLUDE` and
|
||||
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
|
||||
:variable:`CMAKE_PROJECT_INCLUDE`, :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
|
||||
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
|
||||
:command:`project` command calls that specify ``<PROJECT-NAME>`` as the project
|
||||
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`,
|
||||
:variable:`CMAKE_PROJECT_INCLUDE` and
|
||||
:variable:`CMAKE_PROJECT_INCLUDE_BEFORE` variables.
|
||||
:variable:`CMAKE_PROJECT_INCLUDE`, :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
|
||||
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
|
||||
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)) {
|
||||
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
|
||||
|
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)
|
||||
|
||||
# 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)
|
||||
run_cmake(ExplicitRC)
|
||||
endif()
|
||||
|
Reference in New Issue
Block a user