Commit cc47f4eb authored by Brad King's avatar Brad King Committed by Kitware Robot
Browse files

Merge topic 'fileapi-toolchains'

6418dabb Tests: Add test for toolchains-v1 File API object
1c5bd1be Tests: Add toolchains kind to capabilities test
f72bb2ee Help: Add documentation for "toolchains" object kind
bb069c08

 cmFileAPI: Add "toolchains" object kind.
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !5678
parents 22495625 6418dabb
Pipeline #209167 failed with stages
in 68 minutes and 15 seconds
...@@ -1154,3 +1154,160 @@ The members specific to ``cmakeFiles`` objects are: ...@@ -1154,3 +1154,160 @@ The members specific to ``cmakeFiles`` objects are:
``isCMake`` ``isCMake``
Optional member that is present with boolean value ``true`` Optional member that is present with boolean value ``true``
if the path specifies a file in the CMake installation. 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 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.
``compiler``
A JSON object containing members:
``path``
Optional member that is present when the
:variable:`CMAKE_<LANG>_COMPILER` variable is defined for the current
language. Its value is a JSON string holding the path to the compiler.
``id``
Optional member that is present when the
:variable:`CMAKE_<LANG>_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 is present when the
:variable:`CMAKE_<LANG>_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 is present when the
:variable:`CMAKE_<LANG>_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 member that is present when the
:variable:`CMAKE_<LANG>_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 member that is present when the
:variable:`CMAKE_<LANG>_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 member that is present when the
:variable:`CMAKE_<LANG>_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 member that is present when the
:variable:`CMAKE_<LANG>_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 member that is present when the
:variable:`CMAKE_<LANG>_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.
...@@ -268,6 +268,8 @@ set(SRCS ...@@ -268,6 +268,8 @@ set(SRCS
cmFileAPICodemodel.h cmFileAPICodemodel.h
cmFileAPICMakeFiles.cxx cmFileAPICMakeFiles.cxx
cmFileAPICMakeFiles.h cmFileAPICMakeFiles.h
cmFileAPIToolchains.cxx
cmFileAPIToolchains.h
cmFileCopier.cxx cmFileCopier.cxx
cmFileCopier.h cmFileCopier.h
cmFileInstaller.cxx cmFileInstaller.cxx
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "cmFileAPICMakeFiles.h" #include "cmFileAPICMakeFiles.h"
#include "cmFileAPICache.h" #include "cmFileAPICache.h"
#include "cmFileAPICodemodel.h" #include "cmFileAPICodemodel.h"
#include "cmFileAPIToolchains.h"
#include "cmGlobalGenerator.h" #include "cmGlobalGenerator.h"
#include "cmStringAlgorithms.h" #include "cmStringAlgorithms.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
...@@ -262,6 +263,17 @@ bool cmFileAPI::ReadQuery(std::string const& query, ...@@ -262,6 +263,17 @@ bool cmFileAPI::ReadQuery(std::string const& query,
objects.push_back(o); objects.push_back(o);
return true; 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)) { if (kindName == ObjectKindName(ObjectKind::InternalTest)) {
Object o; Object o;
o.Kind = ObjectKind::InternalTest; o.Kind = ObjectKind::InternalTest;
...@@ -402,6 +414,7 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind) ...@@ -402,6 +414,7 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind)
"codemodel", // "codemodel", //
"cache", // "cache", //
"cmakeFiles", // "cmakeFiles", //
"toolchains", //
"__test" // "__test" //
}; };
return objectKindNames[size_t(kind)]; return objectKindNames[size_t(kind)];
...@@ -435,6 +448,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object) ...@@ -435,6 +448,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object)
case ObjectKind::CMakeFiles: case ObjectKind::CMakeFiles:
value = this->BuildCMakeFiles(object); value = this->BuildCMakeFiles(object);
break; break;
case ObjectKind::Toolchains:
value = this->BuildToolchains(object);
break;
case ObjectKind::InternalTest: case ObjectKind::InternalTest:
value = this->BuildInternalTest(object); value = this->BuildInternalTest(object);
break; break;
...@@ -491,6 +507,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest( ...@@ -491,6 +507,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
r.Kind = ObjectKind::Cache; r.Kind = ObjectKind::Cache;
} else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) { } else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) {
r.Kind = ObjectKind::CMakeFiles; r.Kind = ObjectKind::CMakeFiles;
} else if (kindName == this->ObjectKindName(ObjectKind::Toolchains)) {
r.Kind = ObjectKind::Toolchains;
} else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) { } else if (kindName == this->ObjectKindName(ObjectKind::InternalTest)) {
r.Kind = ObjectKind::InternalTest; r.Kind = ObjectKind::InternalTest;
} else { } else {
...@@ -518,6 +536,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest( ...@@ -518,6 +536,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest(
case ObjectKind::CMakeFiles: case ObjectKind::CMakeFiles:
this->BuildClientRequestCMakeFiles(r, versions); this->BuildClientRequestCMakeFiles(r, versions);
break; break;
case ObjectKind::Toolchains:
this->BuildClientRequestToolchains(r, versions);
break;
case ObjectKind::InternalTest: case ObjectKind::InternalTest:
this->BuildClientRequestInternalTest(r, versions); this->BuildClientRequestInternalTest(r, versions);
break; break;
...@@ -765,6 +786,40 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object const& object) ...@@ -765,6 +786,40 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
return cmakeFiles; return cmakeFiles;
} }
// The "toolchains" object kind.
static unsigned int const ToolchainsV1Minor = 0;
void cmFileAPI::BuildClientRequestToolchains(
ClientRequest& r, std::vector<RequestVersion> 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. // The "__test" object kind is for internal testing of CMake.
static unsigned int const InternalTestV1Minor = 3; static unsigned int const InternalTestV1Minor = 3;
...@@ -828,5 +883,13 @@ Json::Value cmFileAPI::ReportCapabilities() ...@@ -828,5 +883,13 @@ Json::Value cmFileAPI::ReportCapabilities()
requests.append(std::move(request)); // NOLINT(*) 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; return capabilities;
} }
...@@ -56,6 +56,7 @@ private: ...@@ -56,6 +56,7 @@ private:
CodeModel, CodeModel,
Cache, Cache,
CMakeFiles, CMakeFiles,
Toolchains,
InternalTest InternalTest
}; };
...@@ -200,6 +201,10 @@ private: ...@@ -200,6 +201,10 @@ private:
ClientRequest& r, std::vector<RequestVersion> const& versions); ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildCMakeFiles(Object const& object); Json::Value BuildCMakeFiles(Object const& object);
void BuildClientRequestToolchains(
ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildToolchains(Object const& object);
void BuildClientRequestInternalTest( void BuildClientRequestInternalTest(
ClientRequest& r, std::vector<RequestVersion> const& versions); ClientRequest& r, std::vector<RequestVersion> const& versions);
Json::Value BuildInternalTest(Object const& object); Json::Value BuildInternalTest(Object const& object);
......
/* 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 <memory>
#include <string>
#include <vector>
#include <cm3p/json/value.h>
#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<ToolchainVariable> CompilerVariables;
static const std::vector<ToolchainVariable> 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<ToolchainVariable> 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<ToolchainVariable> Toolchains::CompilerVariables{
{ "path", "COMPILER", false },
{ "id", "COMPILER_ID", false },
{ "version", "COMPILER_VERSION", false },
{ "target", "COMPILER_TARGET", false },
};
const std::vector<ToolchainVariable> 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<void>(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<ToolchainVariable> 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<std::string> 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();
}
/* 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 <cm3p/json/value.h>
class cmFileAPI;
extern Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI,
unsigned long version);
^{"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":{.*}}$
...@@ -24,6 +24,7 @@ function(check_python case) ...@@ -24,6 +24,7 @@ function(check_python case)
file(GLOB index ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply/index-*.json) file(GLOB index ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply/index-*.json)
execute_process( execute_process(
COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/${case}-check.py" "${index}" "${CMAKE_CXX_COMPILER_ID}" COMMAND ${PYTHON_EXECUTABLE} "${RunCMake_SOURCE_DIR}/${case}-check.py" "${index}" "${CMAKE_CXX_COMPILER_ID}"
"${RunCMake_TEST_BINARY_DIR}"
RESULT_VARIABLE result RESULT_VARIABLE result
OUTPUT_VARIABLE output OUTPUT_VARIABLE output
ERROR_VARIABLE output ERROR_VARIABLE output
...@@ -62,3 +63,4 @@ endfunction() ...@@ -62,3 +63,4 @@ endfunction()
run_object(codemodel-v2) run_object(codemodel-v2)
run_object(cache-v2) run_object(cache-v2)
run_object(cmakeFiles-v1) run_object(cmakeFiles-v1)
run_object(toolchains-v1)
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)
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 } ] }
]])
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)
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" "")
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)
file(REMOVE_RECURSE ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query)
file(WRITE "${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/toolchains-v1" "")
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": {