Преглед на файлове

Merge topic 'project-compat-version'

0138df29dc project: add COMPAT_VERSION keyword

Acked-by: Kitware Robot <[email protected]>
Tested-by: buildbot <[email protected]>
Merge-request: !10696
Brad King преди 7 месеца
родител
ревизия
456cff9ebd
променени са 25 файла, в които са добавени 189 реда и са изтрити 15 реда
  1. 19 0
      Help/command/project.rst
  2. 3 0
      Help/manual/cmake-variables.7.rst
  3. 6 0
      Help/release/dev/project-compat-version.rst
  4. 39 0
      Help/variable/CMAKE_PROJECT_COMPAT_VERSION.rst
  5. 9 0
      Help/variable/PROJECT-NAME_COMPAT_VERSION.rst
  6. 10 0
      Help/variable/PROJECT_COMPAT_VERSION.rst
  7. 55 15
      Source/cmProjectCommand.cxx
  8. 3 0
      Tests/RunCMake/project/ProjectCompatVersion-stdout.txt
  9. 13 0
      Tests/RunCMake/project/ProjectCompatVersion.cmake
  10. 1 0
      Tests/RunCMake/project/ProjectCompatVersion2-result.txt
  11. 1 0
      Tests/RunCMake/project/ProjectCompatVersion2-stderr.txt
  12. 1 0
      Tests/RunCMake/project/ProjectCompatVersion2.cmake
  13. 1 0
      Tests/RunCMake/project/ProjectCompatVersionEqual.cmake
  14. 1 0
      Tests/RunCMake/project/ProjectCompatVersionInvalid-result.txt
  15. 4 0
      Tests/RunCMake/project/ProjectCompatVersionInvalid-stderr.txt
  16. 1 0
      Tests/RunCMake/project/ProjectCompatVersionInvalid.cmake
  17. 1 0
      Tests/RunCMake/project/ProjectCompatVersionMissingVersion-result.txt
  18. 1 0
      Tests/RunCMake/project/ProjectCompatVersionMissingVersion-stderr.txt
  19. 1 0
      Tests/RunCMake/project/ProjectCompatVersionMissingVersion.cmake
  20. 1 0
      Tests/RunCMake/project/ProjectCompatVersionNewer-result.txt
  21. 1 0
      Tests/RunCMake/project/ProjectCompatVersionNewer-stderr.txt
  22. 1 0
      Tests/RunCMake/project/ProjectCompatVersionNewer.cmake
  23. 2 0
      Tests/RunCMake/project/ProjectCompatVersionNoArg-stderr.txt
  24. 1 0
      Tests/RunCMake/project/ProjectCompatVersionNoArg.cmake
  25. 13 0
      Tests/RunCMake/project/RunCMakeTest.cmake

+ 19 - 0
Help/command/project.rst

@@ -11,6 +11,7 @@ Synopsis
  project(<PROJECT-NAME> [<language-name>...])
  project(<PROJECT-NAME>
          [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
+         [COMPAT_VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
          [DESCRIPTION <project-description-string>]
          [HOMEPAGE_URL <url-string>]
          [LANGUAGES <language-name>...])
@@ -86,6 +87,24 @@ The options are:
     ``CMakeLists.txt``, then the version is also stored in the variable
     :variable:`CMAKE_PROJECT_VERSION`.
 
+``COMPAT_VERSION <version>``
+  .. note::
+
+    Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+  Optional; requires ``VERSION`` also be set.
+
+  Takes a ``<version>`` argument composed of non-negative integer components,
+  i.e. ``<major>[.<minor>[.<patch>[.<tweak>]]]``,
+  and sets the variables
+
+  * :variable:`PROJECT_COMPAT_VERSION`,
+    :variable:`<PROJECT-NAME>_COMPAT_VERSION`
+
+    When the ``project()`` command is called from the top-level
+    ``CMakeLists.txt``, then the compatibility version is also stored in the
+    variable :variable:`CMAKE_PROJECT_COMPAT_VERSION`.
+
 ``DESCRIPTION <project-description-string>``
   .. versionadded:: 3.9
 

+ 3 - 0
Help/manual/cmake-variables.7.rst

@@ -105,6 +105,7 @@ Variables that Provide Information
    /variable/CMAKE_PROJECT_VERSION_MINOR
    /variable/CMAKE_PROJECT_VERSION_PATCH
    /variable/CMAKE_PROJECT_VERSION_TWEAK
+   /variable/CMAKE_PROJECT_COMPAT_VERSION
    /variable/CMAKE_RANLIB
    /variable/CMAKE_ROOT
    /variable/CMAKE_RULE_MESSAGES
@@ -161,6 +162,7 @@ Variables that Provide Information
    /variable/PROJECT-NAME_VERSION_MINOR
    /variable/PROJECT-NAME_VERSION_PATCH
    /variable/PROJECT-NAME_VERSION_TWEAK
+   /variable/PROJECT-NAME_COMPAT_VERSION
    /variable/PROJECT_BINARY_DIR
    /variable/PROJECT_DESCRIPTION
    /variable/PROJECT_HOMEPAGE_URL
@@ -172,6 +174,7 @@ Variables that Provide Information
    /variable/PROJECT_VERSION_MINOR
    /variable/PROJECT_VERSION_PATCH
    /variable/PROJECT_VERSION_TWEAK
+   /variable/PROJECT_COMPAT_VERSION
 
 Variables that Change Behavior
 ==============================

+ 6 - 0
Help/release/dev/project-compat-version.rst

@@ -0,0 +1,6 @@
+project-compat-version
+----------------------
+
+* The :command:`project` command now has experimental support for the
+  ``COMPAT_VERSION`` keyword, gated by
+  ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.

+ 39 - 0
Help/variable/CMAKE_PROJECT_COMPAT_VERSION.rst

@@ -0,0 +1,39 @@
+CMAKE_PROJECT_COMPAT_VERSION
+----------------------------
+
+.. note::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+The compatibility version of the top level project.
+
+This variable holds the compatibility version of the project as specified in the
+top level CMakeLists.txt file by a :command:`project` command.  In the event
+that the top level CMakeLists.txt contains multiple :command:`project` calls,
+the most recently called one from that top level CMakeLists.txt will determine
+the value that ``CMAKE_PROJECT_COMPAT_VERSION`` contains.  For example, consider
+the following top level CMakeLists.txt:
+
+.. code-block:: cmake
+
+  cmake_minimum_required(VERSION 4.1)
+  project(First VERSION 9.0 COMPAT_VERSION 1.2.3)
+  project(Second VERSION 9.0 COMPAT_VERSION 3.4.5)
+  add_subdirectory(sub)
+  project(Third VERSION 9.0 COMPAT_VERSION 6.7.8)
+
+And ``sub/CMakeLists.txt`` with the following contents:
+
+.. code-block:: cmake
+
+  project(SubProj VERSION 2.0 COMPAT_VERSION 1.0)
+  message("CMAKE_PROJECT_VERSION = ${CMAKE_PROJECT_VERSION}")
+
+The most recently seen :command:`project` command from the top level
+CMakeLists.txt would be ``project(Second ...)``, so this will print::
+
+  CMAKE_PROJECT_COMPAT_VERSION = 3.4.5
+
+To obtain the version from the most recent call to :command:`project` in
+the current directory scope or above, see the :variable:`PROJECT_COMPAT_VERSION`
+variable.

+ 9 - 0
Help/variable/PROJECT-NAME_COMPAT_VERSION.rst

@@ -0,0 +1,9 @@
+<PROJECT-NAME>_COMPAT_VERSION
+-----------------------------
+
+.. note::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+Value given to the ``COMPAT_VERSION`` option of the most recent call to the
+:command:`project` command with project name ``<PROJECT-NAME>``, if any.

+ 10 - 0
Help/variable/PROJECT_COMPAT_VERSION.rst

@@ -0,0 +1,10 @@
+PROJECT_COMPAT_VERSION
+----------------------
+
+.. note::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+Value given to the ``COMPAT_VERSION`` option of the most recent call to the
+:command:`project` command, if any. To obtain the compatibility version of the
+top level project, see the :variable:`CMAKE_PROJECT_COMPAT_VERSION` variable.

+ 55 - 15
Source/cmProjectCommand.cxx

@@ -17,6 +17,7 @@
 #include "cmArgumentParser.h"
 #include "cmArgumentParserTypes.h"
 #include "cmExecutionStatus.h"
+#include "cmExperimental.h"
 #include "cmList.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -36,6 +37,7 @@ struct ProjectArguments : ArgumentParser::ParseResult
 {
   cm::optional<std::string> ProjectName;
   cm::optional<std::string> Version;
+  cm::optional<std::string> CompatVersion;
   cm::optional<std::string> Description;
   cm::optional<std::string> HomepageURL;
   cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Languages;
@@ -61,22 +63,30 @@ bool cmProjectCommand(std::vector<std::string> const& args,
   std::vector<cm::string_view> missingValueKeywords;
   std::vector<cm::string_view> parsedKeywords;
   ProjectArguments prArgs;
-  ProjectArgumentParser{}
-    .BindKeywordMissingValue(missingValueKeywords)
+  ProjectArgumentParser parser;
+  parser.BindKeywordMissingValue(missingValueKeywords)
     .BindParsedKeywords(parsedKeywords)
     .Bind(0, prArgs.ProjectName)
     .Bind("VERSION"_s, prArgs.Version)
     .Bind("DESCRIPTION"_s, prArgs.Description)
     .Bind("HOMEPAGE_URL"_s, prArgs.HomepageURL)
-    .Bind("LANGUAGES"_s, prArgs.Languages)
-    .Parse(args, &unparsedArgs, 0);
+    .Bind("LANGUAGES"_s, prArgs.Languages);
+
+  cmMakefile& mf = status.GetMakefile();
+  bool enableCompatVersion = cmExperimental::HasSupportEnabled(
+    mf, cmExperimental::Feature::ExportPackageInfo);
+
+  if (enableCompatVersion) {
+    parser.Bind("COMPAT_VERSION"_s, prArgs.CompatVersion);
+  }
+
+  parser.Parse(args, &unparsedArgs, 0);
 
   if (!prArgs.ProjectName) {
     status.SetError("PROJECT called with incorrect number of arguments");
     return false;
   }
 
-  cmMakefile& mf = status.GetMakefile();
   if (mf.IsRootMakefile() &&
       !mf.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
     mf.IssueMessage(
@@ -168,13 +178,21 @@ bool cmProjectCommand(std::vector<std::string> const& args,
     prArgs.Languages->emplace_back("NONE");
   }
 
+  if (prArgs.CompatVersion && !prArgs.Version) {
+    mf.IssueMessage(MessageType::FATAL_ERROR,
+                    "project with COMPAT_VERSION must also provide VERSION.");
+    cmSystemTools::SetFatalErrorOccurred();
+    return true;
+  }
+
+  cmsys::RegularExpression vx(
+    R"(^([0-9]+(\.[0-9]+(\.[0-9]+(\.[0-9]+)?)?)?)?$)");
+
   constexpr std::size_t MAX_VERSION_COMPONENTS = 4u;
   std::string version_string;
   std::array<std::string, MAX_VERSION_COMPONENTS> version_components;
 
   if (prArgs.Version) {
-    cmsys::RegularExpression vx(
-      R"(^([0-9]+(\.[0-9]+(\.[0-9]+(\.[0-9]+)?)?)?)?$)");
     if (!vx.find(*prArgs.Version)) {
       std::string e =
         R"(VERSION ")" + *prArgs.Version + R"(" format invalid.)";
@@ -215,19 +233,41 @@ bool cmProjectCommand(std::vector<std::string> const& args,
     }
   }
 
-  auto create_variables = [&](cm::string_view var, std::string const& val) {
+  if (prArgs.CompatVersion) {
+    if (!vx.find(*prArgs.CompatVersion)) {
+      std::string e =
+        R"(COMPAT_VERSION ")" + *prArgs.CompatVersion + R"(" format invalid.)";
+      mf.IssueMessage(MessageType::FATAL_ERROR, e);
+      cmSystemTools::SetFatalErrorOccurred();
+      return true;
+    }
+
+    if (cmSystemTools::VersionCompareGreater(*prArgs.CompatVersion,
+                                             *prArgs.Version)) {
+      mf.IssueMessage(MessageType::FATAL_ERROR,
+                      "COMPAT_VERSION must be less than or equal to VERSION");
+      cmSystemTools::SetFatalErrorOccurred();
+      return true;
+    }
+  }
+
+  auto createVariables = [&](cm::string_view var, std::string const& val) {
     mf.AddDefinition(cmStrCat("PROJECT_"_s, var), val);
     mf.AddDefinition(cmStrCat(*prArgs.ProjectName, "_"_s, var), val);
     TopLevelCMakeVarCondSet(mf, cmStrCat("CMAKE_PROJECT_"_s, var), val);
   };
 
-  create_variables("VERSION"_s, version_string);
-  create_variables("VERSION_MAJOR"_s, version_components[0]);
-  create_variables("VERSION_MINOR"_s, version_components[1]);
-  create_variables("VERSION_PATCH"_s, version_components[2]);
-  create_variables("VERSION_TWEAK"_s, version_components[3]);
-  create_variables("DESCRIPTION"_s, prArgs.Description.value_or(""));
-  create_variables("HOMEPAGE_URL"_s, prArgs.HomepageURL.value_or(""));
+  createVariables("VERSION"_s, version_string);
+  createVariables("VERSION_MAJOR"_s, version_components[0]);
+  createVariables("VERSION_MINOR"_s, version_components[1]);
+  createVariables("VERSION_PATCH"_s, version_components[2]);
+  createVariables("VERSION_TWEAK"_s, version_components[3]);
+  createVariables("DESCRIPTION"_s, prArgs.Description.value_or(""));
+  createVariables("HOMEPAGE_URL"_s, prArgs.HomepageURL.value_or(""));
+
+  if (enableCompatVersion) {
+    createVariables("COMPAT_VERSION"_s, prArgs.CompatVersion.value_or(""));
+  }
 
   if (unparsedArgs.empty() && !prArgs.Languages) {
     // if no language is specified do c and c++

+ 3 - 0
Tests/RunCMake/project/ProjectCompatVersion-stdout.txt

@@ -0,0 +1,3 @@
+-- PROJECT_COMPAT_VERSION=1.0.0
+-- CMAKE_PROJECT_COMPAT_VERSION=1.0.0
+-- ProjectCompatVersionTest_COMPAT_VERSION=1.0.0

+ 13 - 0
Tests/RunCMake/project/ProjectCompatVersion.cmake

@@ -0,0 +1,13 @@
+project(ProjectCompatVersionTest VERSION 1.5.0 COMPAT_VERSION 1.0.0 LANGUAGES)
+if(NOT PROJECT_COMPAT_VERSION)
+  message(FATAL_ERROR "PROJECT_COMPAT_VERSION expected to be set")
+endif()
+if(NOT CMAKE_PROJECT_COMPAT_VERSION)
+  message(FATAL_ERROR "CMAKE_PROJECT_COMPAT_VERSION expected to be set")
+endif()
+if(NOT ProjectCompatVersionTest_COMPAT_VERSION)
+  message(FATAL_ERROR "ProjectCompatVersionTest_COMPAT_VERSION expected to be set")
+endif()
+message(STATUS "PROJECT_COMPAT_VERSION=${PROJECT_COMPAT_VERSION}")
+message(STATUS "CMAKE_PROJECT_COMPAT_VERSION=${CMAKE_PROJECT_COMPAT_VERSION}")
+message(STATUS "ProjectCompatVersionTest_COMPAT_VERSION=${ProjectCompatVersionTest_COMPAT_VERSION}")

+ 1 - 0
Tests/RunCMake/project/ProjectCompatVersion2-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/project/ProjectCompatVersion2-stderr.txt

@@ -0,0 +1 @@
+  COMPAT_VERSION may be specified at most once.

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

@@ -0,0 +1 @@
+project(ProjectCompatVersionTest VERSION 1.5.0 COMPAT_VERSION 1.0.0 COMPAT_VERSION 1.0.0 LANGUAGES)

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

@@ -0,0 +1 @@
+project(ProjectCompatVersionTest VERSION 1.0.0 COMPAT_VERSION 1.0.0 LANGUAGES)

+ 1 - 0
Tests/RunCMake/project/ProjectCompatVersionInvalid-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/project/ProjectCompatVersionInvalid-stderr.txt

@@ -0,0 +1,4 @@
+CMake Error at ProjectCompatVersionInvalid.cmake:[0-9]+ \(project\):
+  COMPAT_VERSION "NONE" format invalid.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)$

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

@@ -0,0 +1 @@
+project(ProjectCompatVersionTest VERSION 1.5.0 COMPAT_VERSION NONE LANGUAGES)

+ 1 - 0
Tests/RunCMake/project/ProjectCompatVersionMissingVersion-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/project/ProjectCompatVersionMissingVersion-stderr.txt

@@ -0,0 +1 @@
+  project with COMPAT_VERSION must also provide VERSION.

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

@@ -0,0 +1 @@
+project(ProjectCompatVersionTest COMPAT_VERSION 1.0.0 LANGUAGES)

+ 1 - 0
Tests/RunCMake/project/ProjectCompatVersionNewer-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/project/ProjectCompatVersionNewer-stderr.txt

@@ -0,0 +1 @@
+  COMPAT_VERSION must be less than or equal to VERSION

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

@@ -0,0 +1 @@
+project(ProjectCompatVersionTest VERSION 1.0.0 COMPAT_VERSION 1.5.0 LANGUAGES)

+ 2 - 0
Tests/RunCMake/project/ProjectCompatVersionNoArg-stderr.txt

@@ -0,0 +1,2 @@
+  COMPAT_VERSION keyword not followed by a value or was followed by a value
+  that expanded to nothing.

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

@@ -0,0 +1 @@
+project(ProjectCompatVersionTest VERSION 1.5.0 COMPAT_VERSION LANGUAGES)

+ 13 - 0
Tests/RunCMake/project/RunCMakeTest.cmake

@@ -53,6 +53,19 @@ run_cmake(VersionMissingValueOkay)
 run_cmake(VersionTwice)
 run_cmake(VersionMax)
 
+set(opts
+  "-DCMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO=b80be207-778e-46ba-8080-b23bba22639e"
+  "-Wno-dev"
+)
+
+run_cmake_with_options(ProjectCompatVersion ${opts})
+run_cmake_with_options(ProjectCompatVersion2 ${opts})
+run_cmake_with_options(ProjectCompatVersionEqual ${opts})
+run_cmake_with_options(ProjectCompatVersionInvalid ${opts})
+run_cmake_with_options(ProjectCompatVersionMissingVersion ${opts})
+run_cmake_with_options(ProjectCompatVersionNewer ${opts})
+run_cmake_with_options(ProjectCompatVersionNoArg ${opts})
+
 run_cmake(CMP0048-NEW)
 
 run_cmake(CMP0096-WARN)