d6be720337
Set the flag value to the default value, rather than waiting until the end to check if it was set anywhere. This matters when the flag is declared `appends=True`. Bug: none Test: manual Ignore-AOSP-First: Will CP, testing on internal first. Change-Id: I8384cf8e0e0caedb5fb5a343f8be23f37bf4dc87
243 lines
7.6 KiB
Text
243 lines
7.6 KiB
Text
# Copyright (C) 2023 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""
|
|
Export build flags (with values) to make.
|
|
"""
|
|
|
|
load("//build/bazel/utils:schema_validation.scl", "validate")
|
|
|
|
# Partitions that get build system flag summaries
|
|
_flag_partitions = [
|
|
"product",
|
|
"system",
|
|
"system_ext",
|
|
"vendor",
|
|
]
|
|
|
|
ALL = ["all"]
|
|
PRODUCT = ["product"]
|
|
SYSTEM = ["system"]
|
|
SYSTEM_EXT = ["system_ext"]
|
|
VENDOR = ["vendor"]
|
|
|
|
_valid_types = ["NoneType", "bool", "list", "string", "int"]
|
|
|
|
_all_flags_schema = {
|
|
"type": "list",
|
|
"of": {
|
|
"type": "dict",
|
|
"required_keys": {
|
|
"name": {"type": "string"},
|
|
"partitions": {
|
|
"type": "list",
|
|
"of": {
|
|
"type": "string",
|
|
"choices": _flag_partitions + ["all"],
|
|
},
|
|
"unique": True,
|
|
},
|
|
"default": {
|
|
"or": [
|
|
{"type": t}
|
|
for t in _valid_types
|
|
],
|
|
},
|
|
"origin": {"type": "string"},
|
|
"declared_in": {"type": "string"},
|
|
},
|
|
"optional_keys": {
|
|
"appends": {
|
|
"type": "bool",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_all_values_schema = {
|
|
"type": "list",
|
|
"of": {
|
|
"type": "dict",
|
|
"required_keys": {
|
|
"name": {"type": "string"},
|
|
"value": {
|
|
"or": [
|
|
{"type": t}
|
|
for t in _valid_types
|
|
],
|
|
},
|
|
"set_in": {"type": "string"},
|
|
},
|
|
},
|
|
}
|
|
|
|
def flag(name, partitions, default, *, origin = "Unknown", appends = False):
|
|
"""Declare a flag.
|
|
|
|
Args:
|
|
name: name of the flag
|
|
partitions: the partitions where this should be recorded.
|
|
default: the default value of the flag.
|
|
origin: The origin of this flag.
|
|
appends: Whether new values should be append (not replace) the old.
|
|
|
|
Returns:
|
|
A dictionary containing the flag declaration.
|
|
"""
|
|
if not partitions:
|
|
fail("At least 1 partition is required")
|
|
if not name.startswith("RELEASE_"):
|
|
fail("Release flag names must start with RELEASE_")
|
|
if " " in name or "\t" in name or "\n" in name:
|
|
fail("Flag names must not contain whitespace: \"" + name + "\"")
|
|
for partition in partitions:
|
|
if partition == "all":
|
|
if len(partitions) > 1:
|
|
fail("\"all\" can't be combined with other partitions: " + str(partitions))
|
|
elif partition not in _flag_partitions:
|
|
fail("Invalid partition: " + partition + ", allowed partitions: " +
|
|
str(_flag_partitions))
|
|
if type(default) not in _valid_types:
|
|
fail("Invalid type of default for flag \"" + name + "\" (" + type(default) + ")")
|
|
return {
|
|
"name": name,
|
|
"partitions": partitions,
|
|
"default": default,
|
|
"appends": appends,
|
|
"origin": origin,
|
|
}
|
|
|
|
def value(name, value):
|
|
"""Define the flag value for a particular configuration.
|
|
|
|
Args:
|
|
name: The name of the flag.
|
|
value: The value for the flag.
|
|
|
|
Returns:
|
|
A dictionary containing the name and value to be used.
|
|
"""
|
|
return {
|
|
"name": name,
|
|
"value": value,
|
|
}
|
|
|
|
def _format_value(val):
|
|
"""Format the starlark type correctly for make.
|
|
|
|
Args:
|
|
val: The value to format
|
|
|
|
Returns:
|
|
The value, formatted correctly for make.
|
|
"""
|
|
if type(val) == "NoneType":
|
|
return ""
|
|
elif type(val) == "bool":
|
|
return "true" if val else ""
|
|
else:
|
|
return val
|
|
|
|
def equal_flag_declaration(flag, other):
|
|
"""Return true if the flag declarations are equal.
|
|
|
|
Args:
|
|
flag: This flag declaration.
|
|
other: Another flag declaration.
|
|
|
|
Returns:
|
|
Whether the declarations are the same.
|
|
"""
|
|
for key in "name", "partitions", "default", "appends":
|
|
if flag[key] != other[key]:
|
|
return False
|
|
# For now, allow Unknown to match any other origin.
|
|
if flag["origin"] == "Unknown" or other["origin"] == "Unknown":
|
|
return True
|
|
return flag["origin"] == other["origin"]
|
|
|
|
def release_config(all_flags, all_values):
|
|
"""Return the make variables that should be set for this release config.
|
|
|
|
Args:
|
|
all_flags: A list of flag objects (from flag() calls).
|
|
all_values: A list of value objects (from value() calls).
|
|
|
|
Returns:
|
|
A dictionary of {name: value} variables for make.
|
|
"""
|
|
validate(all_flags, _all_flags_schema)
|
|
validate(all_values, _all_values_schema)
|
|
|
|
# Final values.
|
|
values = {}
|
|
# Validate flags
|
|
flag_names = []
|
|
flags_dict = {}
|
|
for flag in all_flags:
|
|
name = flag["name"]
|
|
if name in flag_names:
|
|
if equal_flag_declaration(flag, flags_dict[name]):
|
|
continue
|
|
else:
|
|
fail(flag["declared_in"] + ": Duplicate declaration of flag " + name +
|
|
" (declared first in " + flags_dict[name]["declared_in"] + ")")
|
|
flag_names.append(name)
|
|
flags_dict[name] = flag
|
|
# Set the flag value to the default value.
|
|
values[name] = {"name": name, "value": _format_value(flag["default"]), "set_in": flag["declared_in"]}
|
|
|
|
# Record which flags go on which partition
|
|
partitions = {}
|
|
for flag in all_flags:
|
|
for partition in flag["partitions"]:
|
|
if partition == "all":
|
|
if len(flag["partitions"]) > 1:
|
|
fail("\"all\" can't be combined with other partitions: " + str(flag["partitions"]))
|
|
for partition in _flag_partitions:
|
|
partitions.setdefault(partition, []).append(flag["name"])
|
|
else:
|
|
partitions.setdefault(partition, []).append(flag["name"])
|
|
|
|
# Generate final values.
|
|
# Only declared flags may have a value.
|
|
for value in all_values:
|
|
name = value["name"]
|
|
if name not in flag_names:
|
|
fail(value["set_in"] + ": Value set for undeclared build flag: " + name)
|
|
if flags_dict[name]["appends"]:
|
|
if name in values:
|
|
values[name]["value"] += " " + value["value"]
|
|
values[name]["set_in"] += " " + value["set_in"]
|
|
else:
|
|
values[name] = value
|
|
else:
|
|
values[name] = value
|
|
|
|
# Collect values
|
|
result = {
|
|
"_ALL_RELEASE_FLAGS": sorted(flag_names),
|
|
}
|
|
for partition, names in partitions.items():
|
|
result["_ALL_RELEASE_FLAGS.PARTITIONS." + partition] = names
|
|
for flag in all_flags:
|
|
val = _format_value(values[flag["name"]]["value"])
|
|
result[flag["name"]] = val
|
|
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".PARTITIONS"] = flag["partitions"]
|
|
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".DEFAULT"] = _format_value(flag["default"])
|
|
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".VALUE"] = val
|
|
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".DECLARED_IN"] = flag["declared_in"]
|
|
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".SET_IN"] = values[flag["name"]]["set_in"]
|
|
result["_ALL_RELEASE_FLAGS." + flag["name"] + ".ORIGIN"] = flag["origin"]
|
|
|
|
return result
|