From bb069c08571b5dab3488342b03cc4e5705b3a0e2 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Thu, 7 Jan 2021 16:47:23 -0800 Subject: cmFileAPI: Add "toolchains" object kind. Fixes #19514 --- Source/CMakeLists.txt | 2 + Source/cmFileAPI.cxx | 63 +++++++++++++++++ Source/cmFileAPI.h | 5 ++ Source/cmFileAPIToolchains.cxx | 151 +++++++++++++++++++++++++++++++++++++++++ Source/cmFileAPIToolchains.h | 12 ++++ 5 files changed, 233 insertions(+) create mode 100644 Source/cmFileAPIToolchains.cxx create mode 100644 Source/cmFileAPIToolchains.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c5b67c0..dca94ee 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -268,6 +268,8 @@ set(SRCS cmFileAPICodemodel.h cmFileAPICMakeFiles.cxx cmFileAPICMakeFiles.h + cmFileAPIToolchains.cxx + cmFileAPIToolchains.h cmFileCopier.cxx cmFileCopier.h cmFileInstaller.cxx diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index c2ab2f1..d2a9bec 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -18,6 +18,7 @@ #include "cmFileAPICMakeFiles.h" #include "cmFileAPICache.h" #include "cmFileAPICodemodel.h" +#include "cmFileAPIToolchains.h" #include "cmGlobalGenerator.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -262,6 +263,17 @@ bool cmFileAPI::ReadQuery(std::string const& query, objects.push_back(o); return true; } + if (kindName == ObjectKindName(ObjectKind::Toolchains)) { + Object o; + o.Kind = ObjectKind::Toolchains; + if (verStr == "v1") { + o.Version = 1; + } else { + return false; + } + objects.push_back(o); + return true; + } if (kindName == ObjectKindName(ObjectKind::InternalTest)) { Object o; o.Kind = ObjectKind::InternalTest; @@ -402,6 +414,7 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind) "codemodel", // "cache", // "cmakeFiles", // + "toolchains", // "__test" // }; return objectKindNames[size_t(kind)]; @@ -435,6 +448,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object) case ObjectKind::CMakeFiles: value = this->BuildCMakeFiles(object); break; + case ObjectKind::Toolchains: + value = this->BuildToolchains(object); + break; case ObjectKind::InternalTest: value = this->BuildInternalTest(object); break; @@ -491,6 +507,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest( r.Kind = ObjectKind::Cache; } else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) { r.Kind = ObjectKind::CMakeFiles; + } else if (kindName == this->ObjectKindName(ObjectKind::Toolchains)) { + r.Kind = ObjectKind::Toolchains; } else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) { r.Kind = ObjectKind::InternalTest; } else { @@ -518,6 +536,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest( case ObjectKind::CMakeFiles: this->BuildClientRequestCMakeFiles(r, versions); break; + case ObjectKind::Toolchains: + this->BuildClientRequestToolchains(r, versions); + break; case ObjectKind::InternalTest: this->BuildClientRequestInternalTest(r, versions); break; @@ -765,6 +786,40 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object const& object) return cmakeFiles; } +// The "toolchains" object kind. + +static unsigned int const ToolchainsV1Minor = 0; + +void cmFileAPI::BuildClientRequestToolchains( + ClientRequest& r, std::vector const& versions) +{ + // Select a known version from those requested. + for (RequestVersion const& v : versions) { + if ((v.Major == 1 && v.Minor <= ToolchainsV1Minor)) { + r.Version = v.Major; + break; + } + } + if (!r.Version) { + r.Error = NoSupportedVersion(versions); + } +} + +Json::Value cmFileAPI::BuildToolchains(Object const& object) +{ + Json::Value toolchains = cmFileAPIToolchainsDump(*this, object.Version); + toolchains["kind"] = this->ObjectKindName(object.Kind); + + Json::Value& version = toolchains["version"]; + if (object.Version == 1) { + version = BuildVersion(1, ToolchainsV1Minor); + } else { + return toolchains; // should be unreachable + } + + return toolchains; +} + // The "__test" object kind is for internal testing of CMake. static unsigned int const InternalTestV1Minor = 3; @@ -828,5 +883,13 @@ Json::Value cmFileAPI::ReportCapabilities() requests.append(std::move(request)); // NOLINT(*) } + { + Json::Value request = Json::objectValue; + request["kind"] = ObjectKindName(ObjectKind::Toolchains); + Json::Value& versions = request["version"] = Json::arrayValue; + versions.append(BuildVersion(1, ToolchainsV1Minor)); + requests.append(std::move(request)); // NOLINT(*) + } + return capabilities; } diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h index 086a92a..22302b4 100644 --- a/Source/cmFileAPI.h +++ b/Source/cmFileAPI.h @@ -56,6 +56,7 @@ private: CodeModel, Cache, CMakeFiles, + Toolchains, InternalTest }; @@ -200,6 +201,10 @@ private: ClientRequest& r, std::vector const& versions); Json::Value BuildCMakeFiles(Object const& object); + void BuildClientRequestToolchains( + ClientRequest& r, std::vector const& versions); + Json::Value BuildToolchains(Object const& object); + void BuildClientRequestInternalTest( ClientRequest& r, std::vector const& versions); Json::Value BuildInternalTest(Object const& object); diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx new file mode 100644 index 0000000..722c114 --- /dev/null +++ b/Source/cmFileAPIToolchains.cxx @@ -0,0 +1,151 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFileAPIToolchains.h" + +#include +#include +#include + +#include + +#include "cmFileAPI.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmProperty.h" +#include "cmState.h" +#include "cmStringAlgorithms.h" +#include "cmake.h" + +namespace { + +struct ToolchainVariable +{ + std::string ObjectKey; + std::string VariableSuffix; + bool IsList; +}; + +class Toolchains +{ + cmFileAPI& FileAPI; + unsigned long Version; + + static const std::vector CompilerVariables; + static const std::vector CompilerImplicitVariables; + static const ToolchainVariable SourceFileExtensionsVariable; + + Json::Value DumpToolchains(); + Json::Value DumpToolchain(std::string const& lang); + Json::Value DumpToolchainVariables( + cmMakefile const* mf, std::string const& lang, + std::vector const& variables); + void DumpToolchainVariable(cmMakefile const* mf, Json::Value& object, + std::string const& lang, + ToolchainVariable const& variable); + +public: + Toolchains(cmFileAPI& fileAPI, unsigned long version); + Json::Value Dump(); +}; + +const std::vector Toolchains::CompilerVariables{ + { "path", "COMPILER", false }, + { "id", "COMPILER_ID", false }, + { "version", "COMPILER_VERSION", false }, + { "target", "COMPILER_TARGET", false }, +}; + +const std::vector Toolchains::CompilerImplicitVariables{ + { "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true }, + { "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true }, + { "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", true }, + { "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true }, +}; + +const ToolchainVariable Toolchains::SourceFileExtensionsVariable{ + "sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true +}; + +Toolchains::Toolchains(cmFileAPI& fileAPI, unsigned long version) + : FileAPI(fileAPI) + , Version(version) +{ + static_cast(this->Version); +} + +Json::Value Toolchains::Dump() +{ + Json::Value toolchains = Json::objectValue; + toolchains["toolchains"] = this->DumpToolchains(); + return toolchains; +} + +Json::Value Toolchains::DumpToolchains() +{ + Json::Value toolchains = Json::arrayValue; + + for (std::string const& lang : + this->FileAPI.GetCMakeInstance()->GetState()->GetEnabledLanguages()) { + toolchains.append(this->DumpToolchain(lang)); + } + + return toolchains; +} + +Json::Value Toolchains::DumpToolchain(std::string const& lang) +{ + const auto& mf = + this->FileAPI.GetCMakeInstance()->GetGlobalGenerator()->GetMakefiles()[0]; + Json::Value toolchain = Json::objectValue; + toolchain["language"] = lang; + toolchain["compiler"] = + this->DumpToolchainVariables(mf.get(), lang, CompilerVariables); + toolchain["compiler"]["implicit"] = + this->DumpToolchainVariables(mf.get(), lang, CompilerImplicitVariables); + this->DumpToolchainVariable(mf.get(), toolchain, lang, + SourceFileExtensionsVariable); + return toolchain; +} + +Json::Value Toolchains::DumpToolchainVariables( + cmMakefile const* mf, std::string const& lang, + std::vector const& variables) +{ + Json::Value object = Json::objectValue; + for (const auto& variable : variables) { + this->DumpToolchainVariable(mf, object, lang, variable); + } + return object; +} + +void Toolchains::DumpToolchainVariable(cmMakefile const* mf, + Json::Value& object, + std::string const& lang, + ToolchainVariable const& variable) +{ + std::string const variableName = + cmStrCat("CMAKE_", lang, "_", variable.VariableSuffix); + + if (variable.IsList) { + std::vector values; + if (mf->GetDefExpandList(variableName, values)) { + Json::Value jsonArray = Json::arrayValue; + for (std::string const& value : values) { + jsonArray.append(value); + } + object[variable.ObjectKey] = jsonArray; + } + } else { + cmProp def = mf->GetDefinition(variableName); + if (def) { + object[variable.ObjectKey] = *def; + } + } +} +} + +Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI, unsigned long version) +{ + Toolchains toolchains(fileAPI, version); + return toolchains.Dump(); +} diff --git a/Source/cmFileAPIToolchains.h b/Source/cmFileAPIToolchains.h new file mode 100644 index 0000000..c188807 --- /dev/null +++ b/Source/cmFileAPIToolchains.h @@ -0,0 +1,12 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include + +class cmFileAPI; + +extern Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI, + unsigned long version); -- cgit v0.12 From f72bb2ee0da6bc11fa6ec18e2628b0309ca02ceb Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Thu, 7 Jan 2021 17:28:12 -0800 Subject: Help: Add documentation for "toolchains" object kind --- Help/manual/cmake-file-api.7.rst | 166 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst index 6876e1c..f608d61 100644 --- a/Help/manual/cmake-file-api.7.rst +++ b/Help/manual/cmake-file-api.7.rst @@ -1154,3 +1154,169 @@ The members specific to ``cmakeFiles`` objects are: ``isCMake`` Optional member that is present with boolean value ``true`` if the path specifies a file in the CMake installation. + +Object Kind "toolchains" +------------------------ + +The ``toolchains`` object kind lists properties of the toolchains used during +the build. These include the language, compiler path, ID, and version. + +There is only one ``toolchains`` object major version, version 1. + +"toolchains" version 1 +^^^^^^^^^^^^^^^^^^^^^^ + +``toolchains`` object version 1 is a JSON object: + +.. code-block:: json + + { + "kind": "toolchains", + "version": { "major": 1, "minor": 0 }, + "toolchains": [ + { + "language": "C", + "compiler": { + "path": "/usr/bin/cc", + "id": "GNU", + "version": "9.3.0", + "implicit": { + "includeDirectories": [ + "/usr/lib/gcc/x86_64-linux-gnu/9/include", + "/usr/local/include", + "/usr/include/x86_64-linux-gnu", + "/usr/include" + ], + "linkDirectories": [ + "/usr/lib/gcc/x86_64-linux-gnu/9", + "/usr/lib/x86_64-linux-gnu", + "/usr/lib", + "/lib/x86_64-linux-gnu", + "/lib" + ], + "linkFrameworkDirectories": [], + "linkLibraries": [ + "gcc", + "gcc_s", + "c", + "gcc", + "gcc_s" + ] + } + }, + "sourceFileExtensions": [ + "c", + "m" + ] + }, + { + "language": "CXX", + "compiler": { + "path": "/usr/bin/c++", + "id": "GNU", + "version": "9.3.0", + "implicit": { + "includeDirectories": [ + "/usr/include/c++/9", + "/usr/include/x86_64-linux-gnu/c++/9", + "/usr/include/c++/9/backward", + "/usr/lib/gcc/x86_64-linux-gnu/9/include", + "/usr/local/include", + "/usr/include/x86_64-linux-gnu", + "/usr/include" + ], + "linkDirectories": [ + "/usr/lib/gcc/x86_64-linux-gnu/9", + "/usr/lib/x86_64-linux-gnu", + "/usr/lib", + "/lib/x86_64-linux-gnu", + "/lib" + ], + "linkFrameworkDirectories": [], + "linkLibraries": [ + "stdc++", + "m", + "gcc_s", + "gcc", + "c", + "gcc_s", + "gcc" + ] + } + }, + "sourceFileExtensions": [ + "C", + "M", + "c++", + "cc", + "cpp", + "cxx", + "mm", + "CPP" + ] + } + ] + } + +The members specific to ``toolchains`` objects are: + +``toolchains`` + A JSON array whose entries are each a JSON object specifying a toolchain + associated with a particular language. The members of each entry are: + + ``language`` + A string specifying the toolchain language, like C or CXX. Language + names are the same as langauge names that can be passed to the + :command:`project` command. Because CMake only supports a single toolchain + per language, this field can be used as a key. + + ``compiler`` + A JSON object containing members: + + ``path`` + Optional member that has the same value as + :variable:`CMAKE__COMPILER` if it is defined for the current + language. + + ``id`` + Optional member that has the same value as + :variable:`CMAKE__COMPILER_ID` if it is defined for the current + language. + + ``version`` + Optional member that has the same value as + :variable:`CMAKE__COMPILER_VERSION` if it is defined for the + current language. + + ``target`` + Optional member that has the same value as + :variable:`CMAKE__COMPILER_TARGET` if it is defined for the + current language. + + ``implicit`` + A JSON object containing members: + + ``includeDirectories`` + Optional JSON array that has the same value as + :variable:`CMAKE__IMPLICIT_INCLUDE_DIRECTORIES` if it is defined + for the current language. + + ``linkDirectories`` + Optional JSON array that has the same value as + :variable:`CMAKE__IMPLICIT_LINK_DIRECTORIES` if it is defined + for the current language. + + ``linkFrameworkDirectories`` + Optional JSON array that has the same value as + :variable:`CMAKE__IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` if it is + defined for the current language. + + ``linkLibraries`` + Optional JSON array that has the same value as + :variable:`CMAKE__IMPLICIT_LINK_LIBRARIES` if it is defined for + the current language. + + ``sourceFileExtensions`` + Optional JSON array that has the same value as + :variable:`CMAKE__SOURCE_FILE_EXTENSIONS` if it is defined for the + current language. -- cgit v0.12 From 1c5bd1bed59c00ae73e2c1b364c0437e16bd5cd7 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Tue, 12 Jan 2021 14:25:11 -0800 Subject: Tests: Add toolchains kind to capabilities test --- Tests/RunCMake/CommandLine/E_capabilities-stdout.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt index a8b6584..c76c92d 100644 --- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt +++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt @@ -1 +1 @@ -^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$ +^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$ -- cgit v0.12 From 6418dabb8797a0fe64ddde2e89ae688e984f59d3 Mon Sep 17 00:00:00 2001 From: Ben McMorran Date: Mon, 11 Jan 2021 18:37:32 -0800 Subject: Tests: Add test for toolchains-v1 File API object --- Help/manual/cmake-file-api.7.rst | 99 ++++++++++------------ Tests/RunCMake/FileAPI/RunCMakeTest.cmake | 2 + .../toolchains-v1-ClientStateful-check.cmake | 11 +++ .../toolchains-v1-ClientStateful-prep.cmake | 4 + .../toolchains-v1-ClientStateless-check.cmake | 11 +++ .../toolchains-v1-ClientStateless-prep.cmake | 2 + .../toolchains-v1-SharedStateless-check.cmake | 10 +++ .../toolchains-v1-SharedStateless-prep.cmake | 2 + Tests/RunCMake/FileAPI/toolchains-v1-check.py | 86 +++++++++++++++++++ Tests/RunCMake/FileAPI/toolchains-v1.cmake | 22 +++++ 10 files changed, 195 insertions(+), 54 deletions(-) create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1-check.py create mode 100644 Tests/RunCMake/FileAPI/toolchains-v1.cmake diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst index f608d61..89739b7 100644 --- a/Help/manual/cmake-file-api.7.rst +++ b/Help/manual/cmake-file-api.7.rst @@ -1195,19 +1195,10 @@ There is only one ``toolchains`` object major version, version 1. "/lib" ], "linkFrameworkDirectories": [], - "linkLibraries": [ - "gcc", - "gcc_s", - "c", - "gcc", - "gcc_s" - ] + "linkLibraries": [ "gcc", "gcc_s", "c", "gcc", "gcc_s" ] } }, - "sourceFileExtensions": [ - "c", - "m" - ] + "sourceFileExtensions": [ "c", "m" ] }, { "language": "CXX", @@ -1234,25 +1225,12 @@ There is only one ``toolchains`` object major version, version 1. ], "linkFrameworkDirectories": [], "linkLibraries": [ - "stdc++", - "m", - "gcc_s", - "gcc", - "c", - "gcc_s", - "gcc" + "stdc++", "m", "gcc_s", "gcc", "c", "gcc_s", "gcc" ] } }, "sourceFileExtensions": [ - "C", - "M", - "c++", - "cc", - "cpp", - "cxx", - "mm", - "CPP" + "C", "M", "c++", "cc", "cpp", "cxx", "mm", "CPP" ] } ] @@ -1265,7 +1243,7 @@ The members specific to ``toolchains`` objects are: associated with a particular language. The members of each entry are: ``language`` - A string specifying the toolchain language, like C or CXX. Language + A JSON string specifying the toolchain language, like C or CXX. Language names are the same as langauge names that can be passed to the :command:`project` command. Because CMake only supports a single toolchain per language, this field can be used as a key. @@ -1274,49 +1252,62 @@ The members specific to ``toolchains`` objects are: A JSON object containing members: ``path`` - Optional member that has the same value as - :variable:`CMAKE__COMPILER` if it is defined for the current - language. + Optional member that is present when the + :variable:`CMAKE__COMPILER` variable is defined for the current + language. Its value is a JSON string holding the path to the compiler. ``id`` - Optional member that has the same value as - :variable:`CMAKE__COMPILER_ID` if it is defined for the current - language. + Optional member that is present when the + :variable:`CMAKE__COMPILER_ID` variable is defined for the current + language. Its value is a JSON string holding the ID (GNU, MSVC, etc.) of + the compiler. ``version`` - Optional member that has the same value as - :variable:`CMAKE__COMPILER_VERSION` if it is defined for the - current language. + Optional member that is present when the + :variable:`CMAKE__COMPILER_VERSION` variable is defined for the + current language. Its value is a JSON string holding the version of the + compiler. ``target`` - Optional member that has the same value as - :variable:`CMAKE__COMPILER_TARGET` if it is defined for the - current language. + Optional member that is present when the + :variable:`CMAKE__COMPILER_TARGET` variable is defined for the + current language. Its value is a JSON string holding the cross-compiling + target of the compiler. ``implicit`` A JSON object containing members: ``includeDirectories`` - Optional JSON array that has the same value as - :variable:`CMAKE__IMPLICIT_INCLUDE_DIRECTORIES` if it is defined - for the current language. + Optional member that is present when the + :variable:`CMAKE__IMPLICIT_INCLUDE_DIRECTORIES` variable is + defined for the current language. Its value is a JSON array of JSON + strings where each string holds a path to an implicit include + directory for the compiler. ``linkDirectories`` - Optional JSON array that has the same value as - :variable:`CMAKE__IMPLICIT_LINK_DIRECTORIES` if it is defined - for the current language. + Optional member that is present when the + :variable:`CMAKE__IMPLICIT_LINK_DIRECTORIES` variable is + defined for the current language. Its value is a JSON array of JSON + strings where each string holds a path to an implicit link directory + for the compiler. ``linkFrameworkDirectories`` - Optional JSON array that has the same value as - :variable:`CMAKE__IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` if it is - defined for the current language. + Optional member that is present when the + :variable:`CMAKE__IMPLICIT_LINK_FRAMEWORK_DIRECTORIES` variable + is defined for the current language. Its value is a JSON array of JSON + strings where each string holds a path to an implicit link framework + directory for the compiler. ``linkLibraries`` - Optional JSON array that has the same value as - :variable:`CMAKE__IMPLICIT_LINK_LIBRARIES` if it is defined for - the current language. + Optional member that is present when the + :variable:`CMAKE__IMPLICIT_LINK_LIBRARIES` variable is defined + for the current language. Its value is a JSON array of JSON strings + where each string holds a path to an implicit link library for the + compiler. ``sourceFileExtensions`` - Optional JSON array that has the same value as - :variable:`CMAKE__SOURCE_FILE_EXTENSIONS` if it is defined for the - current language. + Optional member that is present when the + :variable:`CMAKE__SOURCE_FILE_EXTENSIONS` variable is defined for + the current language. Its value is a JSON array of JSON strings where each + each string holds a file extension (without the leading dot) for the + language. diff --git a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake index 2bb2765..ae3d179 100644 --- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake +++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake @@ -24,6 +24,7 @@ function(check_python case) file(GLOB index ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply/index-*.json) execute_process( COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/${case}-check.py" "${index}" "${CMAKE_CXX_COMPILER_ID}" + "${RunCMake_TEST_BINARY_DIR}" RESULT_VARIABLE result OUTPUT_VARIABLE output ERROR_VARIABLE output @@ -62,3 +63,4 @@ endfunction() run_object(codemodel-v2) run_object(cache-v2) run_object(cmakeFiles-v1) +run_object(toolchains-v1) diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake new file mode 100644 index 0000000..ce38461 --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake @@ -0,0 +1,11 @@ +set(expect + query + query/client-foo + query/client-foo/query.json + reply + reply/index-[0-9.T-]+.json + reply/toolchains-v1-[0-9a-f]+.json + ) +check_api("^${expect}$") + +check_python(toolchains-v1) diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake new file mode 100644 index 0000000..ca62edf --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-prep.cmake @@ -0,0 +1,4 @@ +file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query) +file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/query.json" [[ +{ "requests": [ { "kind": "toolchains", "version" : 1 } ] } +]]) diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake new file mode 100644 index 0000000..4676dd8 --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-check.cmake @@ -0,0 +1,11 @@ +set(expect + query + query/client-foo + query/client-foo/toolchains-v1 + reply + reply/index-[0-9.T-]+.json + reply/toolchains-v1-[0-9a-f]+.json + ) +check_api("^${expect}$") + +check_python(toolchains-v1) diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake new file mode 100644 index 0000000..7edff93 --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateless-prep.cmake @@ -0,0 +1,2 @@ +file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query) +file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client-foo/toolchains-v1" "") diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake new file mode 100644 index 0000000..8e83758 --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-check.cmake @@ -0,0 +1,10 @@ +set(expect + query + query/toolchains-v1 + reply + reply/index-[0-9.T-]+.json + reply/toolchains-v1-[0-9a-f]+.json + ) +check_api("^${expect}$") + +check_python(toolchains-v1) diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake new file mode 100644 index 0000000..2db73a1 --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1-SharedStateless-prep.cmake @@ -0,0 +1,2 @@ +file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query) +file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/toolchains-v1" "") diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-check.py b/Tests/RunCMake/FileAPI/toolchains-v1-check.py new file mode 100644 index 0000000..a0e50c2 --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1-check.py @@ -0,0 +1,86 @@ +from check_index import * +import os + +class ExpectedVar(object): + def __init__(self, name): + self.name = name + +class ExpectedList(object): + def __init__(self, name): + self.name = name + +EXPECTED_TOOLCHAIN = { + "language": "CXX", + "compiler": { + "path": ExpectedVar("CMAKE_CXX_COMPILER"), + "id": ExpectedVar("CMAKE_CXX_COMPILER_ID"), + "version": ExpectedVar("CMAKE_CXX_COMPILER_VERSION"), + "target": ExpectedVar("CMAKE_CXX_COMPILER_TARGET"), + "implicit": { + "includeDirectories": \ + ExpectedList("CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES"), + "linkDirectories": \ + ExpectedList("CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES"), + "linkFrameworkDirectories": \ + ExpectedList( + "CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"), + "linkLibraries": \ + ExpectedList("CMAKE_CXX_IMPLICIT_LINK_LIBRARIES"), + } + }, + "sourceFileExtensions": \ + ExpectedList("CMAKE_CXX_SOURCE_FILE_EXTENSIONS"), +} + +def check_objects(o): + assert is_list(o) + assert len(o) == 1 + check_index_object(o[0], "toolchains", 1, 0, check_object_toolchains) + +def check_object_toolchains(o): + assert sorted(o.keys()) == ["kind", "toolchains", "version"] + # The "kind" and "version" members are handled by check_index_object. + toolchains = o["toolchains"] + assert is_list(toolchains) + + # Other platform-specific toolchains may exist (like RC on Windows). + has_cxx_toolchain = False + for toolchain in toolchains: + assert is_dict(toolchain) + assert "language" in toolchain + if toolchain["language"] == "CXX": + check_object_toolchain(toolchain, EXPECTED_TOOLCHAIN) + has_cxx_toolchain = True + + assert has_cxx_toolchain + +def check_object_toolchain(o, expected): + expected_keys = [ + key for (key, value) in expected.items() + if is_string(value) or is_dict(value) + or (type(value) in (ExpectedVar, ExpectedList) + and variables[value.name]["defined"])] + assert sorted(o.keys()) == sorted(expected_keys) + + for key in expected_keys: + value = expected[key] + if is_string(value): + assert o[key] == value + elif is_dict(value): + check_object_toolchain(o[key], value) + elif type(value) == ExpectedVar: + assert o[key] == variables[value.name]["value"] + elif type(value) == ExpectedList: + expected_items = filter( + None, variables[value.name]["value"].split(";")) + check_list_match(lambda a, b: a == b, o[key], expected_items) + else: + assert False + +with open(os.path.join(sys.argv[3], "toolchain_variables.json")) as f: + variables = json.load(f) + +assert is_dict(variables) +assert is_dict(index) +assert sorted(index.keys()) == ["cmake", "objects", "reply"] +check_objects(index["objects"]) diff --git a/Tests/RunCMake/FileAPI/toolchains-v1.cmake b/Tests/RunCMake/FileAPI/toolchains-v1.cmake new file mode 100644 index 0000000..367aade --- /dev/null +++ b/Tests/RunCMake/FileAPI/toolchains-v1.cmake @@ -0,0 +1,22 @@ +enable_language(CXX) + +set(variable_suffixes + COMPILER COMPILER_ID COMPILER_VERSION COMPILER_TARGET + IMPLICIT_INCLUDE_DIRECTORIES IMPLICIT_LINK_DIRECTORIES + IMPLICIT_LINK_FRAMEWORK_DIRECTORIES IMPLICIT_LINK_LIBRARIES + SOURCE_FILE_EXTENSIONS) +set(language CXX) +set(json "{}") + +foreach(variable_suffix ${variable_suffixes}) + set(variable "CMAKE_${language}_${variable_suffix}") + string(JSON json SET "${json}" "${variable}" "{}") + if(DEFINED "${variable}") + string(JSON json SET "${json}" "${variable}" "defined" "true") + string(JSON json SET "${json}" "${variable}" "value" "\"${${variable}}\"") + else() + string(JSON json SET "${json}" "${variable}" "defined" "false") + endif() +endforeach() + +file(WRITE ${CMAKE_BINARY_DIR}/toolchain_variables.json "${json}") -- cgit v0.12