mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-07 14:20:06 -06:00
fileAPI: Expose CMAKE_<LANG>_COMPILER_ARG1
Compiler arguments coming from CC environment variables or multi-element CMAKE_<LANG>_COMPILER variables set by toolchain files were previously not exposed in the file API. Among other possible problems, this caused clients to determine wrong system include paths and built-in preprocessor macros by calling the compiler without these important arguments. This is fixed by adding an optional "commandFragment" attribute to the compiler description in the `toolchains` object, containing these arguments as a command line fragment. This is already the form in which they are internally stored in the CMAKE_<LANG>_COMPILER_ARG1 variable, so all that is required is adding this variable to the set of exported variables, besides some logic to omit it if empty. Issue: #22568
This commit is contained in:
committed by
Craig Scott
parent
1e02926c9a
commit
71a4e34d97
@@ -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
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/toolchainsObjV1_0"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/toolchainsObjV1_1"
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
@@ -36,6 +39,24 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"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)"
|
||||
@@ -101,7 +122,7 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"compiler": {
|
||||
"compilerV1_0": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {
|
||||
@@ -122,6 +143,30 @@
|
||||
},
|
||||
"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": {
|
||||
@@ -145,7 +190,42 @@
|
||||
"$ref": "#/definitions/language"
|
||||
},
|
||||
"compiler": {
|
||||
"$ref": "#/definitions/compiler"
|
||||
"$ref": "#/definitions/compilerV1_0"
|
||||
},
|
||||
"sourceFileExtensions": {
|
||||
"$ref": "#/definitions/sourceFileExtensions"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"toolchainsObjV1_1": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kind": {
|
||||
"$ref": "#/definitions/kind"
|
||||
},
|
||||
"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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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":{.*}}$
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,7 +62,8 @@ 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"])]
|
||||
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:
|
||||
@@ -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"])
|
||||
|
||||
@@ -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}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user