Merge topic 'fileapi-compilerargs'

71a4e34d97 fileAPI: Expose CMAKE_<LANG>_COMPILER_ARG1
1e02926c9a fileAPI: Refactor toolchains schema to prepare for new version
3caa572c05 fileAPI: Output more info for test failures

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !11419
This commit is contained in:
Craig Scott
2025-12-02 21:27:16 +00:00
committed by Kitware Robot
9 changed files with 266 additions and 100 deletions
+12 -1
View File
@@ -2109,12 +2109,13 @@ There is only one ``toolchains`` object major version, version 1.
{
"kind": "toolchains",
"version": { "major": 1, "minor": 0 },
"version": { "major": 1, "minor": 1 },
"toolchains": [
{
"language": "C",
"compiler": {
"path": "/usr/bin/cc",
"commandFragment": "--config x86_64-linux-gnu.cfg",
"id": "GNU",
"version": "9.3.0",
"implicit": {
@@ -2193,6 +2194,16 @@ The members specific to ``toolchains`` objects are:
:variable:`CMAKE_<LANG>_COMPILER` variable is defined for the current
language. Its value is a JSON string holding the path to the compiler.
``commandFragment``
Optional member that is present when the
:variable:`CMAKE_<LANG>_COMPILER` variable is a list containing multiple
elements or the :envvar:`CC` or similar environment variable contains
command line arguments after the compiler executable.
Its value is a JSON string holding the second and further elements
(mandatory arguments to the compiler) as a command line fragment.
This field was added in toolchains version 1.1.
``id``
Optional member that is present when the
:variable:`CMAKE_<LANG>_COMPILER_ID` variable is defined for the current
+196 -72
View File
@@ -7,13 +7,21 @@
"version",
"toolchains"
],
"properties": {
"oneOf": [
{
"$ref": "#/definitions/toolchainsObjV1_0"
},
{
"$ref": "#/definitions/toolchainsObjV1_1"
}
],
"definitions": {
"kind": {
"type": "string",
"const": "toolchains",
"description": "Specifies the object kind"
},
"version": {
"versionV1_0": {
"type": "object",
"required": [
"major",
@@ -31,87 +39,203 @@
},
"additionalProperties": false
},
"toolchains": {
"versionV1_1": {
"type": "object",
"required": [
"major",
"minor"
],
"properties": {
"major": {
"type": "integer",
"const": 1
},
"minor": {
"type": "integer",
"const": 1
}
},
"additionalProperties": false
},
"language": {
"type": "string",
"description": "Toolchain language identifier (e.g. C, CXX)"
},
"sourceFileExtensions": {
"type": "array",
"description": "Array of toolchain configurations per language",
"items": {
"type": "object",
"required": [
"language",
"compiler"
],
"properties": {
"language": {
"type": "string",
"description": "Toolchain language identifier (e.g. C, CXX)"
"type": "string"
},
"description": "List of source file extensions (without leading dot) supported by this toolchain"
},
"compilerPath": {
"type": "string",
"description": "Path to the compiler executable. This is present when the CMAKE_<LANG>_COMPILER variable is defined."
},
"compilerCommandFragment": {
"type": "string",
"description": "Mandatory arguments to the compiler, as a command line fragment. This is present when the CMAKE_<LANG>_COMPILER variable is a list containing multiple elements or the CC or similar environment variable contains command line arguments."
},
"compilerId": {
"type": "string",
"description": "Compiler identifier (e.g. GNU, MSVC). This is present when the CMAKE_<LANG>_COMPILER_ID variable is defined."
},
"compilerVersion": {
"type": "string",
"description": "Version of the compiler. This is present when the CMAKE_<LANG>_COMPILER_VERSION variable is defined."
},
"compilerTarget": {
"type": "string",
"description": "Cross-compiling target of the compiler. This is present when the CMAKE_<LANG>_COMPILER_TARGET variable is defined."
},
"compilerImplicit": {
"type": "object",
"properties": {
"includeDirectories": {
"type": "array",
"items": {
"type": "string"
},
"compiler": {
"description": "List of implicit include directories for the compiler. This is present when the CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES variable is defined."
},
"linkDirectories": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of implicit link directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES variable is defined."
},
"linkFrameworkDirectories": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of implicit link framework directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_FRAMEWORK_DIRECTORIES variable is defined."
},
"linkLibraries": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of implicit link libraries for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES variable is defined."
}
},
"additionalProperties": false
},
"compilerV1_0": {
"type": "object",
"properties": {
"path": {
"$ref": "#/definitions/compilerPath"
},
"id": {
"$ref": "#/definitions/compilerId"
},
"version": {
"$ref": "#/definitions/compilerVersion"
},
"target": {
"$ref": "#/definitions/compilerTarget"
},
"implicit": {
"$ref": "#/definitions/compilerImplicit"
}
},
"additionalProperties": false
},
"compilerV1_1": {
"type": "object",
"properties": {
"path": {
"$ref": "#/definitions/compilerPath"
},
"commandFragment": {
"$ref": "#/definitions/compilerCommandFragment"
},
"id": {
"$ref": "#/definitions/compilerId"
},
"version": {
"$ref": "#/definitions/compilerVersion"
},
"target": {
"$ref": "#/definitions/compilerTarget"
},
"implicit": {
"$ref": "#/definitions/compilerImplicit"
}
},
"additionalProperties": false
},
"toolchainsObjV1_0": {
"type": "object",
"properties": {
"kind": {
"$ref": "#/definitions/kind"
},
"version": {
"$ref": "#/definitions/versionV1_0"
},
"toolchains": {
"type": "array",
"description": "Array of toolchain configurations per language",
"items": {
"type": "object",
"required": [
"language",
"compiler"
],
"properties": {
"path": {
"type": "string",
"description": "Path to the compiler executable. This is present when the CMAKE_<LANG>_COMPILER variable is defined."
"language": {
"$ref": "#/definitions/language"
},
"id": {
"type": "string",
"description": "Compiler identifier (e.g. GNU, MSVC). This is present when the CMAKE_<LANG>_COMPILER_ID variable is defined."
"compiler": {
"$ref": "#/definitions/compilerV1_0"
},
"version": {
"type": "string",
"description": "Version of the compiler. This is present when the CMAKE_<LANG>_COMPILER_VERSION variable is defined."
},
"target": {
"type": "string",
"description": "Cross-compiling target of the compiler. This is present when the CMAKE_<LANG>_COMPILER_TARGET variable is defined."
},
"implicit": {
"type": "object",
"properties": {
"includeDirectories": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of implicit include directories for the compiler. This is present when the CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES variable is defined."
},
"linkDirectories": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of implicit link directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES variable is defined."
},
"linkFrameworkDirectories": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of implicit link framework directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_FRAMEWORK_DIRECTORIES variable is defined."
},
"linkLibraries": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of implicit link libraries for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES variable is defined."
}
},
"additionalProperties": false
"sourceFileExtensions": {
"$ref": "#/definitions/sourceFileExtensions"
}
},
"additionalProperties": false
},
"sourceFileExtensions": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of source file extensions (without leading dot) supported by this toolchain"
}
}
},
"additionalProperties": false
},
"toolchainsObjV1_1": {
"type": "object",
"properties": {
"kind": {
"$ref": "#/definitions/kind"
},
"additionalProperties": false
}
"version": {
"$ref": "#/definitions/versionV1_1"
},
"toolchains": {
"type": "array",
"description": "Array of toolchain configurations per language",
"items": {
"type": "object",
"required": [
"language",
"compiler"
],
"properties": {
"language": {
"$ref": "#/definitions/language"
},
"compiler": {
"$ref": "#/definitions/compilerV1_1"
},
"sourceFileExtensions": {
"$ref": "#/definitions/sourceFileExtensions"
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
}
+1 -1
View File
@@ -959,7 +959,7 @@ Json::Value cmFileAPI::BuildCMakeFiles(Object object)
// The "toolchains" object kind.
static unsigned int const ToolchainsV1Minor = 0;
static unsigned int const ToolchainsV1Minor = 1;
void cmFileAPI::BuildClientRequestToolchains(
ClientRequest& r, std::vector<RequestVersion> const& versions)
+19 -15
View File
@@ -24,6 +24,7 @@ struct ToolchainVariable
std::string ObjectKey;
std::string VariableSuffix;
bool IsList;
bool OmitEmpty;
};
class Toolchains
@@ -74,22 +75,23 @@ Json::Value Toolchains::DumpToolchains()
Json::Value Toolchains::DumpToolchain(std::string const& lang)
{
static std::vector<ToolchainVariable> const CompilerVariables{
{ "path", "COMPILER", false },
{ "id", "COMPILER_ID", false },
{ "version", "COMPILER_VERSION", false },
{ "target", "COMPILER_TARGET", false },
{ "path", "COMPILER", false, false },
{ "commandFragment", "COMPILER_ARG1", false, true },
{ "id", "COMPILER_ID", false, false },
{ "version", "COMPILER_VERSION", false, false },
{ "target", "COMPILER_TARGET", false, false },
};
static std::vector<ToolchainVariable> const CompilerImplicitVariables{
{ "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true },
{ "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true },
{ "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES",
true },
{ "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true },
{ "includeDirectories", "IMPLICIT_INCLUDE_DIRECTORIES", true, false },
{ "linkDirectories", "IMPLICIT_LINK_DIRECTORIES", true, false },
{ "linkFrameworkDirectories", "IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", true,
false },
{ "linkLibraries", "IMPLICIT_LINK_LIBRARIES", true, false },
};
static ToolchainVariable const SourceFileExtensionsVariable{
"sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true
"sourceFileExtensions", "SOURCE_FILE_EXTENSIONS", true, false
};
auto const& mf =
@@ -128,15 +130,17 @@ void Toolchains::DumpToolchainVariable(cmMakefile const* mf,
cmValue data = mf->GetDefinition(variableName);
if (data) {
cmList values(data);
Json::Value jsonArray = Json::arrayValue;
for (auto const& value : values) {
jsonArray.append(value);
if (!variable.OmitEmpty || !values.empty()) {
Json::Value jsonArray = Json::arrayValue;
for (auto const& value : values) {
jsonArray.append(value);
}
object[variable.ObjectKey] = jsonArray;
}
object[variable.ObjectKey] = jsonArray;
}
} else {
cmValue def = mf->GetDefinition(variableName);
if (def) {
if (def && (!variable.OmitEmpty || !def.IsEmpty())) {
object[variable.ObjectKey] = *def;
}
}
@@ -1 +1 @@
^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":9}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":1}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":9}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":1}]},{"kind":"toolchains","version":\[{"major":1,"minor":1}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
+1 -1
View File
@@ -30,7 +30,7 @@ cmake_file_api(
CODEMODEL 3
CACHE 3
CMAKEFILES 2
TOOLCHAINS 1.1
TOOLCHAINS 1.2
)
message(NOTICE "Requested versions too low check")
+3 -1
View File
@@ -146,7 +146,7 @@ run_cmake(FailConfigure)
function(run_object object)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${object}-build)
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0118=NEW)
list(APPEND RunCMake_TEST_OPTIONS ${ARGN} -DCMAKE_POLICY_DEFAULT_CMP0118=NEW)
run_cmake(${object})
list(POP_BACK RunCMake_TEST_OPTIONS)
set(RunCMake_TEST_NO_CLEAN 1)
@@ -161,3 +161,5 @@ run_object(configureLog-v1)
run_object(cache-v2)
run_object(cmakeFiles-v1)
run_object(toolchains-v1)
run_object(toolchains-v1 -DTOOLCHAINSV1_COMPILERARGS=1)
run_object(toolchains-v1 -DTOOLCHAINSV1_COMPILERARGS=2)
+16 -7
View File
@@ -2,17 +2,20 @@ from check_index import *
import os
class ExpectedVar(object):
def __init__(self, name):
def __init__(self, name, omitEmpty=False):
self.name = name
self.omitEmpty = omitEmpty
class ExpectedList(object):
def __init__(self, name):
def __init__(self, name, omitEmpty=False):
self.name = name
self.omitEmpty = omitEmpty
EXPECTED_TOOLCHAIN = {
"language": "CXX",
"compiler": {
"path": ExpectedVar("CMAKE_CXX_COMPILER"),
"commandFragment": ExpectedVar("CMAKE_CXX_COMPILER_ARG1", omitEmpty=True),
"id": ExpectedVar("CMAKE_CXX_COMPILER_ID"),
"version": ExpectedVar("CMAKE_CXX_COMPILER_VERSION"),
"target": ExpectedVar("CMAKE_CXX_COMPILER_TARGET"),
@@ -35,7 +38,7 @@ EXPECTED_TOOLCHAIN = {
def check_objects(o):
assert is_list(o)
assert len(o) == 1
check_index_object(o[0], "toolchains", 1, 0, check_object_toolchains)
check_index_object(o[0], "toolchains", 1, 1, check_object_toolchains)
def check_object_toolchains(o):
assert sorted(o.keys()) == ["kind", "toolchains", "version"]
@@ -59,17 +62,18 @@ def check_object_toolchain(o, expected):
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)
and variables[value.name]["defined"]
and not (value.omitEmpty and variables[value.name]["value"] == ''))]
assert sorted(o.keys()) == sorted(expected_keys), "actual object {!r}, expected keys {!r}".format(o, sorted(expected_keys))
for key in expected_keys:
value = expected[key]
if is_string(value):
assert o[key] == value
assert o[key] == value, "{!r}: actual {!r}, expected {!r}".format(key, o[key], value)
elif is_dict(value):
check_object_toolchain(o[key], value)
elif type(value) == ExpectedVar:
assert o[key] == variables[value.name]["value"]
assert o[key] == variables[value.name]["value"], "{!r}: actual {!r}, expected {!r} (from {})".format(key, o[key], variables[value.name]["value"], value.name)
elif type(value) == ExpectedList:
expected_items = filter(
None, variables[value.name]["value"].split(";"))
@@ -81,6 +85,11 @@ with open(os.path.join(args.build_dir, "toolchain_variables.json")) as f:
variables = json.load(f)
assert is_dict(variables)
if variables.get("TOOLCHAINSV1_COMPILERARGS", 0) == 1:
del EXPECTED_TOOLCHAIN["compiler"]["commandFragment"]
elif variables.get("TOOLCHAINSV1_COMPILERARGS", 0) == 2:
EXPECTED_TOOLCHAIN["compiler"]["commandFragment"] = "--hello world --something=other"
assert is_dict(index)
assert sorted(index.keys()) == ["cmake", "objects", "reply"]
check_objects(index["objects"])
+17 -1
View File
@@ -1,7 +1,22 @@
# If testing with a specific CMAKE_CXX_COMPILER_ARG1 value is requested, skip
# any checks that try to actually compile anything, because the compiler
# probably wouldn't understand these arguments or lack thereof.
if(DEFINED TOOLCHAINSV1_COMPILERARGS)
if(TOOLCHAINSV1_COMPILERARGS EQUAL 1)
set(CMAKE_CXX_COMPILER_ARG1 "")
elseif(TOOLCHAINSV1_COMPILERARGS EQUAL 2)
set(CMAKE_CXX_COMPILER_ARG1 "--hello world --something=other")
endif()
set(CMAKE_CXX_COMPILER_WORKS 1)
set(CMAKE_CXX_ABI_COMPILED 1)
else()
set(TOOLCHAINSV1_COMPILERARGS 0)
endif()
enable_language(CXX)
set(variable_suffixes
COMPILER COMPILER_ID COMPILER_VERSION COMPILER_TARGET
COMPILER COMPILER_ARG1 COMPILER_ID COMPILER_VERSION COMPILER_TARGET
IMPLICIT_INCLUDE_DIRECTORIES IMPLICIT_LINK_DIRECTORIES
IMPLICIT_LINK_FRAMEWORK_DIRECTORIES IMPLICIT_LINK_LIBRARIES
SOURCE_FILE_EXTENSIONS)
@@ -18,6 +33,7 @@ foreach(variable_suffix ${variable_suffixes})
string(JSON json SET "${json}" "${variable}" "defined" "false")
endif()
endforeach()
string(JSON json SET "${json}" "TOOLCHAINSV1_COMPILERARGS" "${TOOLCHAINSV1_COMPILERARGS}")
file(WRITE ${CMAKE_BINARY_DIR}/toolchain_variables.json "${json}")