Browse Source

CMAKE_PROJECT_INCLUDE: Add support for including multiple files

Fixes: #25341
Signed-off-by: Cristian Le <[email protected]>
Cristian Le 2 years ago
parent
commit
704acca96b
26 changed files with 133 additions and 45 deletions
  1. 9 0
      Help/release/dev/project-include-multiple.rst
  2. 5 1
      Help/variable/CMAKE_PROJECT_INCLUDE.rst
  3. 5 1
      Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst
  4. 5 1
      Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst
  5. 5 1
      Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst
  6. 32 19
      Source/cmProjectCommand.cxx
  7. 0 10
      Tests/RunCMake/project/CodeInjection-stdout.txt
  8. 0 1
      Tests/RunCMake/project/CodeInjection/cmake_project_include.cmake
  9. 0 1
      Tests/RunCMake/project/CodeInjection/cmake_project_include_before.cmake
  10. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_includes_1.cmake
  11. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_includes_2.cmake
  12. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_includes_before_1.cmake
  13. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_includes_before_2.cmake
  14. 0 1
      Tests/RunCMake/project/CodeInjection/cmake_project_subproj_include.cmake
  15. 0 1
      Tests/RunCMake/project/CodeInjection/cmake_project_subproj_include_before.cmake
  16. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_1.cmake
  17. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_2.cmake
  18. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_before_1.cmake
  19. 1 0
      Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_before_2.cmake
  20. 5 6
      Tests/RunCMake/project/CodeInjection/initial_cache_1.cmake
  21. 27 0
      Tests/RunCMake/project/CodeInjection/initial_cache_2.cmake
  22. 9 0
      Tests/RunCMake/project/CodeInjection1-stdout.txt
  23. 0 0
      Tests/RunCMake/project/CodeInjection1.cmake
  24. 16 0
      Tests/RunCMake/project/CodeInjection2-stdout.txt
  25. 1 0
      Tests/RunCMake/project/CodeInjection2.cmake
  26. 6 2
      Tests/RunCMake/project/RunCMakeTest.cmake

+ 9 - 0
Help/release/dev/project-include-multiple.rst

@@ -0,0 +1,9 @@
+project-include-multiple
+------------------------
+
+* 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 learned
+  to support a :ref:`semicolon-separated list <CMake Language Lists>` of
+  CMake language files to be included sequentially.

+ 5 - 1
Help/variable/CMAKE_PROJECT_INCLUDE.rst

@@ -3,12 +3,16 @@ CMAKE_PROJECT_INCLUDE
 
 .. versionadded:: 3.15
 
-A CMake language file or module to be included as the last step of all
+A CMake language file 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.  See :ref:`Code Injection`
 for a more detailed discussion of files potentially included during a
 :command:`project` call.
 
+.. versionadded:: 3.29
+  This variable can be a :ref:`semicolon-separated list <CMake Language Lists>`
+  of CMake language files to be included sequentially.
+
 See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
 :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
 :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`, and

+ 5 - 1
Help/variable/CMAKE_PROJECT_INCLUDE_BEFORE.rst

@@ -3,12 +3,16 @@ CMAKE_PROJECT_INCLUDE_BEFORE
 
 .. versionadded:: 3.15
 
-A CMake language file or module to be included as the first step of all
+A CMake language file 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.  See :ref:`Code Injection`
 for a more detailed discussion of files potentially included during a
 :command:`project` call.
 
+.. versionadded:: 3.29
+  This variable can be a :ref:`semicolon-separated list <CMake Language Lists>`
+  of CMake language files to be included sequentially.
+
 See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
 :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
 :variable:`CMAKE_PROJECT_INCLUDE`, and

+ 5 - 1
Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE.rst

@@ -1,12 +1,16 @@
 CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE
 ------------------------------------
 
-A CMake language file or module to be included as the last step of any
+A CMake language file 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.  See :ref:`Code Injection` for a more detailed
 discussion of files potentially included during a :command:`project` call.
 
+.. versionadded:: 3.29
+  This variable can be a :ref:`semicolon-separated list <CMake Language Lists>`
+  of CMake language files to be included sequentially.
+
 See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE`,
 :variable:`CMAKE_PROJECT_INCLUDE`, :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
 and :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variables.

+ 5 - 1
Help/variable/CMAKE_PROJECT_PROJECT-NAME_INCLUDE_BEFORE.rst

@@ -3,12 +3,16 @@ CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE
 
 .. versionadded:: 3.17
 
-A CMake language file or module to be included as the first step of any
+A CMake language file 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.  See :ref:`Code Injection` for a more detailed
 discussion of files potentially included during a :command:`project` call.
 
+.. versionadded:: 3.29
+  This variable can be a :ref:`semicolon-separated list <CMake Language Lists>`
+  of CMake language files to be included sequentially.
+
 See also the :variable:`CMAKE_PROJECT_<PROJECT-NAME>_INCLUDE`,
 :variable:`CMAKE_PROJECT_INCLUDE`, :variable:`CMAKE_PROJECT_INCLUDE_BEFORE`,
 and :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variables.

+ 32 - 19
Source/cmProjectCommand.cxx

@@ -11,6 +11,7 @@
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmExecutionStatus.h"
+#include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
@@ -371,29 +372,41 @@ static bool IncludeByVariable(cmExecutionStatus& status,
   if (!include) {
     return true;
   }
+  cmList includeFiles{ *include };
+
+  bool failed = false;
+  for (auto const& filePath : includeFiles) {
+    std::string includeFile = cmSystemTools::CollapseFullPath(
+      filePath, mf.GetCurrentSourceDirectory());
+    if (!cmSystemTools::FileExists(includeFile)) {
+      status.SetError(
+        cmStrCat("could not find requested file:\n  ", filePath));
+      failed = true;
+      continue;
+    }
+    if (cmSystemTools::FileIsDirectory(includeFile)) {
+      status.SetError(
+        cmStrCat("requested file is a directory:\n  ", filePath));
+      failed = true;
+      continue;
+    }
 
-  std::string includeFile =
-    cmSystemTools::CollapseFullPath(*include, mf.GetCurrentSourceDirectory());
-  if (!cmSystemTools::FileExists(includeFile)) {
-    status.SetError(cmStrCat("could not find requested file:\n  ", *include));
-    return false;
-  }
-  if (cmSystemTools::FileIsDirectory(includeFile)) {
-    status.SetError(cmStrCat("requested file is a directory:\n  ", *include));
-    return false;
-  }
+    const bool readit = mf.ReadDependentFile(filePath);
+    if (readit) {
+      // If the included file ran successfully, continue to the next file
+      continue;
+    }
 
-  const bool readit = mf.ReadDependentFile(*include);
-  if (readit) {
-    return true;
-  }
+    if (cmSystemTools::GetFatalErrorOccurred()) {
+      failed = true;
+      continue;
+    }
 
-  if (cmSystemTools::GetFatalErrorOccurred()) {
-    return true;
+    status.SetError(cmStrCat("could not load requested file:\n  ", filePath));
+    failed = true;
   }
-
-  status.SetError(cmStrCat("could not load requested file:\n  ", *include));
-  return false;
+  // At this point all files were processed
+  return !failed;
 }
 
 static void TopLevelCMakeVarCondSet(cmMakefile& mf, std::string const& name,

+ 0 - 10
Tests/RunCMake/project/CodeInjection-stdout.txt

@@ -1,10 +0,0 @@
-(-- )?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

+ 0 - 1
Tests/RunCMake/project/CodeInjection/cmake_project_include.cmake

@@ -1 +0,0 @@
-message(STATUS "Included CMAKE_PROJECT_INCLUDE")

+ 0 - 1
Tests/RunCMake/project/CodeInjection/cmake_project_include_before.cmake

@@ -1 +0,0 @@
-message(STATUS "Included CMAKE_PROJECT_INCLUDE_BEFORE")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_includes_1.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_INCLUDE first file")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_includes_2.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_INCLUDE second file")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_includes_before_1.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_INCLUDE_BEFORE first file")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_includes_before_2.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_INCLUDE_BEFORE second file")

+ 0 - 1
Tests/RunCMake/project/CodeInjection/cmake_project_subproj_include.cmake

@@ -1 +0,0 @@
-message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE")

+ 0 - 1
Tests/RunCMake/project/CodeInjection/cmake_project_subproj_include_before.cmake

@@ -1 +0,0 @@
-message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_1.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE first file")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_2.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE second file")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_before_1.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE first file")

+ 1 - 0
Tests/RunCMake/project/CodeInjection/cmake_project_subproj_includes_before_2.cmake

@@ -0,0 +1 @@
+message(STATUS "Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE second file")

+ 5 - 6
Tests/RunCMake/project/CodeInjection/initial_cache.cmake → Tests/RunCMake/project/CodeInjection/initial_cache_1.cmake

@@ -1,10 +1,9 @@
 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_INCLUDE                "${CMAKE_CURRENT_LIST_DIR}/cmake_project_includes_1.cmake" CACHE FILEPATH "")
+set(CMAKE_PROJECT_INCLUDE_BEFORE         "${CMAKE_CURRENT_LIST_DIR}/cmake_project_includes_before_1.cmake" CACHE FILEPATH "")
+set(CMAKE_PROJECT_SubProj_INCLUDE        "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_includes_1.cmake" CACHE FILEPATH "")
+set(CMAKE_PROJECT_SubProj_INCLUDE_BEFORE "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_includes_before_1.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 ""
+  CACHE FILEPATH ""
 )

+ 27 - 0
Tests/RunCMake/project/CodeInjection/initial_cache_2.cmake

@@ -0,0 +1,27 @@
+set(CMAKE_TOOLCHAIN_FILE
+  "${CMAKE_CURRENT_LIST_DIR}/passthrough_toolchain_file.cmake" CACHE FILEPATH "")
+set(CMAKE_PROJECT_INCLUDE
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_includes_1.cmake"
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_includes_2.cmake"
+  CACHE STRING ""
+)
+set(CMAKE_PROJECT_INCLUDE_BEFORE
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_includes_before_1.cmake"
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_includes_before_2.cmake"
+  CACHE STRING ""
+)
+set(CMAKE_PROJECT_SubProj_INCLUDE
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_includes_1.cmake"
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_includes_2.cmake"
+  CACHE STRING ""
+)
+set(CMAKE_PROJECT_SubProj_INCLUDE_BEFORE
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_includes_before_1.cmake"
+  "${CMAKE_CURRENT_LIST_DIR}/cmake_project_subproj_includes_before_2.cmake"
+  CACHE STRING ""
+)
+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 ""
+)

+ 9 - 0
Tests/RunCMake/project/CodeInjection1-stdout.txt

@@ -0,0 +1,9 @@
+(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE first file
+(-- )?Included CMAKE_TOOLCHAIN_FILE
+.*Included CMAKE_PROJECT_TOP_LEVEL_INCLUDES first file
+(-- )?Included CMAKE_PROJECT_INCLUDE first file
+(-- )?Calling sub-project
+(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE first file
+(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE first file
+(-- )?Included CMAKE_PROJECT_INCLUDE first file
+(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE first file

+ 0 - 0
Tests/RunCMake/project/CodeInjection.cmake → Tests/RunCMake/project/CodeInjection1.cmake


+ 16 - 0
Tests/RunCMake/project/CodeInjection2-stdout.txt

@@ -0,0 +1,16 @@
+(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE first file
+(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE second file
+(-- )?Included CMAKE_TOOLCHAIN_FILE
+.*Included CMAKE_PROJECT_TOP_LEVEL_INCLUDES first file
+(-- )?Included CMAKE_PROJECT_TOP_LEVEL_INCLUDES second file
+(-- )?Included CMAKE_PROJECT_INCLUDE first file
+(-- )?Included CMAKE_PROJECT_INCLUDE second file
+(-- )?Calling sub-project
+(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE first file
+(-- )?Included CMAKE_PROJECT_INCLUDE_BEFORE second file
+(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE first file
+(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE_BEFORE second file
+(-- )?Included CMAKE_PROJECT_INCLUDE first file
+(-- )?Included CMAKE_PROJECT_INCLUDE second file
+(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE first file
+(-- )?Included CMAKE_PROJECT_SubProj_INCLUDE second file

+ 1 - 0
Tests/RunCMake/project/CodeInjection2.cmake

@@ -0,0 +1 @@
+add_subdirectory(CodeInjection)

+ 6 - 2
Tests/RunCMake/project/RunCMakeTest.cmake

@@ -5,8 +5,12 @@ include(RunCMake)
 # 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"
+run_cmake_with_options(CodeInjection1
+  -C "${CMAKE_CURRENT_LIST_DIR}/CodeInjection/initial_cache_1.cmake"
+)
+# This checks that List variables are allowed.
+run_cmake_with_options(CodeInjection2
+        -C "${CMAKE_CURRENT_LIST_DIR}/CodeInjection/initial_cache_2.cmake"
 )
 
 if(CMake_TEST_RESOURCES)