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.
This commit is contained in:
Brad King 2021-03-04 16:47:49 -05:00
parent 8dd8d63665
commit 608ef8a6fc
12 changed files with 139 additions and 0 deletions

View File

@ -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.

View File

@ -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");

View File

@ -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);

View File

@ -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.$

View File

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

View File

@ -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)

View File

@ -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()

View File

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

View File

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

View File

@ -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}'")

View File

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