Quellcode durchsuchen

VS: Add a mostly-undocumented hook to load custom JSON flag tables

The names and formats of our VS flag tables are internal implementation
details.  However, some institutions need to maintain support for
non-public VS platforms and toolsets.  Provide a hook that their
projects can use to load custom flag table files.  This helps avoid
distributing a custom CMake package within such institutions.

Document the hook itself, but explicitly specify that the files the
hook loads are not considered a stable interface.
Brad King vor 4 Jahren
Ursprung
Commit
608ef8a6fc

+ 24 - 0
Help/variable/CMAKE_GENERATOR_TOOLSET.rst

@@ -63,3 +63,27 @@ Supported pairs are:
   Specify an alternative ``VCTargetsPath`` value for Visual Studio
   project files.  This allows use of VS platform extension configuration
   files (``.props`` and ``.targets``) that are not installed with VS.
+
+Visual Studio Toolset Customization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+**These are unstable interfaces with no compatibility guarantees**
+because they hook into undocumented internal CMake implementation details.
+Institutions may use these to internally maintain support for non-public
+Visual Studio platforms and toolsets, but must accept responsibility to
+make updates as changes are made to CMake.
+
+Additional ``key=value`` pairs are available:
+
+``customFlagTableDir=<path>``
+  .. versionadded:: 3.21
+
+  Specify the absolute path to a directory from which to load custom
+  flag tables stored as JSON documents with file names of the form
+  ``<platform>_<toolset>_<tool>.json`` or ``<platform>_<tool>.json``,
+  where ``<platform>`` is the :variable:`CMAKE_VS_PLATFORM_NAME`,
+  ``<toolset>`` is the :variable:`CMAKE_VS_PLATFORM_TOOLSET`,
+  and ``<tool>`` is the tool for which the flag table is meant.
+  **This naming pattern is an internal CMake implementation detail.**
+  The ``<tool>`` names are undocumented.  The format of the ``.json``
+  flag table files is undocumented.

+ 36 - 0
Source/cmGlobalVisualStudio10Generator.cxx

@@ -231,6 +231,23 @@ bool cmGlobalVisualStudio10Generator::SetGeneratorToolset(
     return false;
   }
 
+  if (!this->CustomFlagTableDir.empty() &&
+      !(cmSystemTools::FileIsFullPath(this->CustomFlagTableDir) &&
+        cmSystemTools::FileIsDirectory(this->CustomFlagTableDir))) {
+    std::ostringstream e;
+    /* clang-format off */
+    e <<
+      "Generator\n"
+      "  " << this->GetName() << "\n"
+      "given toolset\n"
+      "  customFlagTableDir=" << this->CustomFlagTableDir << "\n"
+      "that is not an absolute path to an existing directory.";
+    /* clang-format on */
+    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    cmSystemTools::SetFatalErrorOccured();
+    return false;
+  }
+
   if (cmHasLiteralPrefix(this->GetPlatformToolsetString(), "v140")) {
     // The GenerateDebugInformation link setting for the v140 toolset
     // in VS 2015 was originally an enum with "No" and "Debug" values,
@@ -486,6 +503,11 @@ bool cmGlobalVisualStudio10Generator::ProcessGeneratorToolsetField(
     }
     return true;
   }
+  if (key == "customFlagTableDir") {
+    this->CustomFlagTableDir = value;
+    cmSystemTools::ConvertToUnixSlashes(this->CustomFlagTableDir);
+    return true;
+  }
   if (key == "version") {
     this->GeneratorToolsetVersion = value;
     return true;
@@ -1375,6 +1397,20 @@ static cmIDEFlagTable const* cmLoadFlagTableJson(
 cm::optional<std::string> cmGlobalVisualStudio10Generator::FindFlagTable(
   cm::string_view toolsetName, cm::string_view table) const
 {
+  if (!this->CustomFlagTableDir.empty()) {
+    std::string customFlagTableFile =
+      cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
+               toolsetName, '_', table, ".json");
+    if (cmSystemTools::FileExists(customFlagTableFile)) {
+      return customFlagTableFile;
+    }
+    customFlagTableFile =
+      cmStrCat(this->CustomFlagTableDir, '/', this->GetPlatformName(), '_',
+               table, ".json");
+    if (cmSystemTools::FileExists(customFlagTableFile)) {
+      return customFlagTableFile;
+    }
+  }
   std::string fullPath =
     cmStrCat(cmSystemTools::GetCMakeRoot(), "/Templates/MSBuild/FlagTables/",
              toolsetName, '_', table, ".json");

+ 2 - 0
Source/cmGlobalVisualStudio10Generator.h

@@ -262,6 +262,8 @@ private:
   cm::optional<std::string> FindFlagTable(cm::string_view toolsetName,
                                           cm::string_view table) const;
 
+  std::string CustomFlagTableDir;
+
   std::string CustomVCTargetsPath;
   std::string VCTargetsPath;
   bool FindVCTargetsPath(cmMakefile* mf);

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-result.txt

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

+ 11 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir-stderr.txt

@@ -0,0 +1,11 @@
+CMake Error at CMakeLists.txt:[0-9]+ \(project\):
+  Generator
+
+    Visual Studio [^
+]*
+
+  given toolset
+
+    customFlagTableDir=does_not_exist
+
+  that is not an absolute path to an existing directory.$

+ 1 - 0
Tests/RunCMake/GeneratorToolset/BadToolsetCustomFlagTableDir.cmake

@@ -0,0 +1 @@
+message(FATAL_ERROR "This should not be reached!")

+ 25 - 0
Tests/RunCMake/GeneratorToolset/RunCMakeTest.cmake

@@ -1,5 +1,11 @@
 include(RunCMake)
 
+if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[012456]")
+  run_cmake(VsNormal)
+  include("${RunCMake_BINARY_DIR}/VsNormal-build/defaults.cmake" OPTIONAL)
+  message(STATUS "VsNormal: platform='${VsNormal_Platform}' toolset='${VsNormal_Toolset}'")
+endif()
+
 set(RunCMake_GENERATOR_TOOLSET "")
 run_cmake(NoToolset)
 
@@ -18,6 +24,25 @@ if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[012456]")
   file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/CudaStandaloneToolset/CUDAVisualStudioIntegration")
   run_cmake(TestToolsetCudaPathOnlyOldLayout)
   file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/CudaStandaloneToolset")
+  if (VsNormal_Platform MATCHES "^(x64|Win32)$" AND
+      EXISTS "${CMAKE_ROOT}/Templates/MSBuild/FlagTables/${VsNormal_Toolset}_CL.json")
+    set(flagTableDir "${RunCMake_BINARY_DIR}/FlagTables")
+    file(READ "${CMAKE_ROOT}/Templates/MSBuild/FlagTables/${VsNormal_Toolset}_CL.json" flagTableContent)
+    string(REPLACE [["WX-"]] [["TESTWX-"]] flagTableContent "${flagTableContent}")
+    file(REMOVE_RECURSE "${flagTableDir}")
+    file(WRITE "${flagTableDir}/${VsNormal_Platform}_${VsNormal_Toolset}_CL.json" "${flagTableContent}")
+    set(RunCMake_GENERATOR_TOOLSET "${VsNormal_Toolset},customFlagTableDir=${flagTableDir}")
+    set(RunCMake_TEST_VARIANT_DESCRIPTION ":${VsNormal_Platform}_${VsNormal_Toolset}_CL.json")
+    run_cmake(TestToolsetCustomFlagTableDir)
+    file(REMOVE_RECURSE "${flagTableDir}")
+    file(WRITE "${flagTableDir}/${VsNormal_Platform}_CL.json" "${flagTableContent}")
+    set(RunCMake_GENERATOR_TOOLSET "${VsNormal_Toolset},customFlagTableDir=${flagTableDir}")
+    set(RunCMake_TEST_VARIANT_DESCRIPTION ":${VsNormal_Platform}_CL.json")
+    run_cmake(TestToolsetCustomFlagTableDir)
+    unset(RunCMake_TEST_VARIANT_DESCRIPTION)
+    set(RunCMake_GENERATOR_TOOLSET "${VsNormal_Toolset},customFlagTableDir=does_not_exist")
+    run_cmake(BadToolsetCustomFlagTableDir)
+  endif()
   if("${RunCMake_GENERATOR}" MATCHES "Visual Studio 1[2456]")
     set(RunCMake_GENERATOR_TOOLSET "Test Toolset,host=x64")
     run_cmake(TestToolsetHostArchBoth)

+ 24 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir-check.cmake

@@ -0,0 +1,24 @@
+set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/main.vcxproj")
+if(NOT EXISTS "${vcProjectFile}")
+  set(RunCMake_TEST_FAILED "Project file\n  ${vcProjectFile}\ndoes not exist.")
+  return()
+endif()
+
+set(TreatWarningAsError_FOUND FALSE)
+file(STRINGS "${vcProjectFile}" lines)
+foreach(line IN LISTS lines)
+  if(line MATCHES "^ *<TreatWarningAsError>([^<>]*)</TreatWarningAsError>$")
+    set(TreatWarningAsError_FOUND TRUE)
+    set(expectedValue "false")
+    set(actualValue "${CMAKE_MATCH_1}")
+    if(NOT (${actualValue} STREQUAL ${expectedValue}))
+      set(RunCMake_TEST_FAILED "TreatWarningAsError \"${actualValue}\" differs from expected value \"${expectedValue}\".")
+      return()
+    endif()
+  endif()
+endforeach()
+
+if(NOT TreatWarningAsError_FOUND)
+  set(RunCMake_TEST_FAILED "Property TreatWarningAsError not found in project file:\n ${vcProjectFile}.")
+  return()
+endif()

+ 3 - 0
Tests/RunCMake/GeneratorToolset/TestToolsetCustomFlagTableDir.cmake

@@ -0,0 +1,3 @@
+enable_language(C)
+string(APPEND CMAKE_C_FLAGS " -TESTWX-")
+add_executable(main main.c)

+ 2 - 0
Tests/RunCMake/GeneratorToolset/VsNormal-stdout.txt

@@ -0,0 +1,2 @@
+-- CMAKE_VS_PLATFORM_NAME='[^']+'
+-- CMAKE_VS_PLATFORM_TOOLSET='v[0-9]+'

+ 6 - 0
Tests/RunCMake/GeneratorToolset/VsNormal.cmake

@@ -0,0 +1,6 @@
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/defaults.cmake" "# VS Defaults
+set(VsNormal_Platform [[${CMAKE_VS_PLATFORM_NAME}]])
+set(VsNormal_Toolset [[${CMAKE_VS_PLATFORM_TOOLSET}]])
+")
+message(STATUS "CMAKE_VS_PLATFORM_NAME='${CMAKE_VS_PLATFORM_NAME}'")
+message(STATUS "CMAKE_VS_PLATFORM_TOOLSET='${CMAKE_VS_PLATFORM_TOOLSET}'")

+ 4 - 0
Tests/RunCMake/GeneratorToolset/main.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}