Quelle generate_static_pref_list.py
Sprache: Python
# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/.
import os import sys from collections import defaultdict
import buildconfig import yaml from mozbuild.dirutils import ensureParentDir from mozbuild.preprocessor import Preprocessor from mozbuild.util import FileAvoidWrite from six import StringIO
# Each key is a C++ type; its value is the equivalent non-atomic C++ type.
VALID_BOOL_TYPES = { "bool": "bool", # These ones are defined in StaticPrefsBase.h. "RelaxedAtomicBool": "bool", "ReleaseAcquireAtomicBool": "bool", "SequentiallyConsistentAtomicBool": "bool",
}
VALID_TYPES = VALID_BOOL_TYPES.copy()
VALID_TYPES.update(
{ "int32_t": "int32_t", "uint32_t": "uint32_t", "float": "float", # These ones are defined in StaticPrefsBase.h. "RelaxedAtomicInt32": "int32_t", "RelaxedAtomicUint32": "uint32_t", "ReleaseAcquireAtomicInt32": "int32_t", "ReleaseAcquireAtomicUint32": "uint32_t", "SequentiallyConsistentAtomicInt32": "int32_t", "SequentiallyConsistentAtomicUint32": "uint32_t", "AtomicFloat": "float", "String": None, "DataMutexString": "nsACString",
}
)
def mk_id(name): "Replace '.' and '-' with '_', e.g. 'foo.bar-baz' becomes 'foo_bar_baz'." return name.replace(".", "_").replace("-", "_")
def mk_group(pref):
name = pref["name"] return mk_id(name.split(".", 1)[0])
def check_pref_list(pref_list): # Pref names seen so far. Used to detect any duplicates.
seen_names = set()
# The previous pref. Used to detect mis-ordered prefs.
prev_pref = None
for pref in pref_list: # Check all given keys are known ones. for key in pref: if key notin VALID_KEYS:
error("invalid key `{}`".format(key))
# 'name' must be present, valid, and in the right section. if"name"notin pref:
error("missing `name` key")
name = pref["name"] if type(name) isnot str:
error("non-string `name` value `{}`".format(name)) if"."notin name:
error("`name` value `{}` lacks a '.'".format(name)) if name in seen_names:
error("`{}` pref is defined more than once".format(name))
seen_names.add(name)
# Prefs must be ordered appropriately. if prev_pref: if mk_group(prev_pref) > mk_group(pref):
error( "`{}` pref must come before `{}` pref".format(
name, prev_pref["name"]
)
)
# 'type' must be present and valid. if"type"notin pref:
error("missing `type` key for pref `{}`".format(name))
typ = pref["type"] if typ notin VALID_TYPES:
error("invalid `type` value `{}` for pref `{}`".format(typ, name))
# 'value' must be present and valid. if"value"notin pref:
error("missing `value` key for pref `{}`".format(name))
value = pref["value"] if typ == "String"or typ == "DataMutexString": if type(value) isnot str:
error( "non-string `value` value `{}` for `{}` pref `{}`; " "add double quotes".format(value, typ, name)
) elif typ in VALID_BOOL_TYPES: if value notin (True, False):
error("invalid boolean value `{}` for pref `{}`".format(value, name))
# 'mirror' must be present and valid. if"mirror"notin pref:
error("missing `mirror` key for pref `{}`".format(name))
mirror = pref["mirror"] if typ.startswith("DataMutex"):
mirror += "_datamutex" if mirror notin MIRROR_TEMPLATES:
error("invalid `mirror` value `{}` for pref `{}`".format(mirror, name))
# Check 'do_not_use_directly' if present. if"do_not_use_directly"in pref:
do_not_use_directly = pref["do_not_use_directly"] if type(do_not_use_directly) isnot bool:
error( "non-boolean `do_not_use_directly` value `{}` for pref " "`{}`".format(do_not_use_directly, name)
) if do_not_use_directly and mirror == "never":
error( "`do_not_use_directly` uselessly set with `mirror` value " "`never` for pref `{}`".format(pref["name"])
)
# Check 'include' if present. if"include"in pref:
include = pref["include"] if type(include) isnot str:
error( "non-string `include` value `{}` for pref `{}`".format(
include, name
)
) if include.startswith("<") andnot include.endswith(">"):
error( "`include` value `{}` starts with `<` but does not " "end with `>` for pref `{}`".format(include, name)
)
# Check 'rust' if present. if"rust"in pref:
rust = pref["rust"] if type(rust) isnot bool:
error("non-boolean `rust` value `{}` for pref `{}`".format(rust, name)) if rust and mirror == "never":
error( "`rust` uselessly set with `mirror` value `never` for " "pref `{}`".format(pref["name"])
)
# The required includes for StaticPrefs_<group>.h.
includes = defaultdict(set)
# StaticPrefList_<group>.h contains all the pref definitions for this # group.
static_pref_list_group_h = defaultdict(lambda: [first_line, ""])
# StaticPrefsCGetters.cpp contains C getters for all the mirrored prefs, # for use by Rust code.
static_prefs_c_getters_cpp = [first_line, ""]
# static_prefs.rs contains C getter declarations and a macro.
static_prefs_rs_decls = []
static_prefs_rs_macro = []
# Generate the per-pref code (spread across multiple files). for pref in pref_list:
name = pref["name"]
typ = pref["type"]
value = pref["value"]
mirror = pref["mirror"]
do_not_use_directly = pref.get("do_not_use_directly")
include = pref.get("include")
rust = pref.get("rust")
base_id = mk_id(pref["name"])
full_id = base_id if mirror == "once":
full_id += "_AtStartup" if do_not_use_directly:
full_id += "_DoNotUseDirectly" if typ.startswith("DataMutex"):
mirror += "_datamutex"
group = mk_group(pref)
if include: ifnot include.startswith("<"): # It's not a system header. Add double quotes.
include = '"{}"'.format(include)
includes[group].add(include)
if typ == "String": # Quote string literals, and escape double-quote chars.
value = '"{}"'.format(value.replace('"', '\\"')) elif typ == "DataMutexString": # Quote string literals, and escape double-quote chars.
value = '"{}"_ns'.format(value.replace('"', '\\"')) elif typ in VALID_BOOL_TYPES: # Convert Python bools to C++ bools. if value isTrue:
value = "true" elif value isFalse:
value = "false"
# Append the C++ definition to the relevant output file's code.
static_pref_list_group_h[group].append(
MIRROR_TEMPLATES[mirror].format(
name=name,
base_id=base_id,
full_id=full_id,
typ=typ,
value=value,
)
)
if rust:
passed_type = VALID_TYPES[typ] if passed_type == "nsACString": # Generate the C getter.
static_prefs_c_getters_cpp.append(
STATIC_PREFS_C_GETTERS_NSSTRING_TEMPLATE.format(full_id=full_id)
)
# Generate the C getter declaration, in Rust.
decl = " pub fn StaticPrefs_{full_id}(result: *mut nsstring::nsACString);"
static_prefs_rs_decls.append(decl.format(full_id=full_id))
# Generate the Rust macro entry.
macro = ' ("{name}") => (unsafe {{ let mut result = $crate::nsCString::new(); $crate::StaticPrefs_{full_id}(&mut *result); result }});'
static_prefs_rs_macro.append(macro.format(name=name, full_id=full_id))
else: # Generate the C getter.
static_prefs_c_getters_cpp.append(
STATIC_PREFS_C_GETTERS_TEMPLATE.format(
typ=passed_type, full_id=full_id
)
)
# Generate the C getter declaration, in Rust.
decl = " pub fn StaticPrefs_{full_id}() -> {typ};"
static_prefs_rs_decls.append(
decl.format(full_id=full_id, typ=RUST_TYPES[passed_type])
)
# Delete this so that `group` can be reused below without Flake8 # complaining. del group
# StaticPrefListAll.h contains one `#include "mozilla/StaticPrefList_X.h` # line per pref group.
static_pref_list_all_h = [first_line, ""]
static_pref_list_all_h.extend( '#include "mozilla/StaticPrefList_{}.h"'.format(group) for group in sorted(static_pref_list_group_h)
)
static_pref_list_all_h.append("")
# StaticPrefsAll.h contains one `#include "mozilla/StaticPrefs_X.h` line per # pref group.
static_prefs_all_h = [first_line, ""]
static_prefs_all_h.extend( '#include "mozilla/StaticPrefs_{}.h"'.format(group) for group in sorted(static_pref_list_group_h)
)
static_prefs_all_h.append("")
# StaticPrefs_<group>.h wraps StaticPrefList_<group>.h. It is the header # used directly by application code.
static_prefs_group_h = defaultdict(list) for group in sorted(static_pref_list_group_h):
static_prefs_group_h[group] = [first_line]
static_prefs_group_h[group].append(
STATIC_PREFS_GROUP_H_TEMPLATE1.format(group=group)
) if group in includes: # Add any necessary includes, from 'h_include' values. for include in sorted(includes[group]):
static_prefs_group_h[group].append("#include {}".format(include))
static_prefs_group_h[group].append("")
static_prefs_group_h[group].append(
STATIC_PREFS_GROUP_H_TEMPLATE2.format(group=group)
)
return { "static_pref_list_all_h": fold(static_pref_list_all_h), "static_prefs_all_h": fold(static_prefs_all_h), "static_pref_list_group_h": {
k: fold(v) for k, v in static_pref_list_group_h.items()
}, "static_prefs_group_h": {k: fold(v) for k, v in static_prefs_group_h.items()}, "static_prefs_c_getters_cpp": fold(static_prefs_c_getters_cpp), "static_prefs_rs": fold(static_prefs_rs),
}
# When generating multiple files from a script, the build system treats the # first named output file (StaticPrefListAll.h in this case) specially -- it # is created elsewhere, and written to via `fd`.
fd.write(code["static_pref_list_all_h"])
# We must create the remaining output files ourselves. This requires # creating the output directory directly if it doesn't already exist.
ensureParentDir(fd.name)
init_dirname = os.path.dirname(fd.name)
with FileAvoidWrite("StaticPrefsAll.h") as fd:
fd.write(code["static_prefs_all_h"])
for group, text in sorted(code["static_pref_list_group_h"].items()):
filename = "StaticPrefList_{}.h".format(group) with FileAvoidWrite(os.path.join(init_dirname, filename)) as fd:
fd.write(text)
for group, text in sorted(code["static_prefs_group_h"].items()):
filename = "StaticPrefs_{}.h".format(group) with FileAvoidWrite(filename) as fd:
fd.write(text)
with FileAvoidWrite(os.path.join(init_dirname, "StaticPrefsCGetters.cpp")) as fd:
fd.write(code["static_prefs_c_getters_cpp"])
with FileAvoidWrite("static_prefs.rs") as fd:
fd.write(code["static_prefs_rs"])
¤ Dauer der Verarbeitung: 0.33 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.