diff options
author | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-02-20 23:22:32 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-02-20 23:22:32 +0000 |
commit | 8cd44ced35ae0d5537138c1f82ea3346f0f0abcb (patch) | |
tree | 4b11f2c588aa4c5db5bde5bc3e8e0e9d1b240731 | |
parent | 8c621bcbeb8d0330695ef5c0bfe2d80946f8157c (diff) | |
parent | 0188d416ac65a0c4a94ed5e2f79c1cdf5d76b1db (diff) | |
download | build-8cd44ced35ae0d5537138c1f82ea3346f0f0abcb.tar.gz |
kmi_defines: Removed need for .o.d.keep files am: 0188d416ac
Change-Id: Ib0ea54e3e7f78205e653b80edc7655851347063a
-rwxr-xr-x | abi/kmi_defines.py | 129 |
1 files changed, 66 insertions, 63 deletions
diff --git a/abi/kmi_defines.py b/abi/kmi_defines.py index 009700df..f3fbd37a 100755 --- a/abi/kmi_defines.py +++ b/abi/kmi_defines.py @@ -32,7 +32,7 @@ import pathlib import re import subprocess import sys -from typing import List, Tuple, Iterable +from typing import List, Optional, Tuple from typing import Set # pytype needs this, pylint: disable=unused-import COMPILER = "clang" # TODO(pantin): should be determined at run-time @@ -40,6 +40,24 @@ DEBUG = True # TODO(pantin): should be a program argument INDENT = 4 # number of spaces to indent for each depth level PROGRAM = os.path.basename(sys.argv[0]) +# Dependency that is hidden by the transformation of the .o.d file into +# the .o.cmd file as part of the Linux build environment. This header is +# purposely removed and replaced by fictitious set of empty header files +# that were never part of the actual compilation of the .o files. Those +# fictitious empty files are generated under the build environment output +# directory in this subdirectory: +# include/config +# +# This is the actual header file that was part of the compilation of every +# .o file, the HIDDEN_DEP are added to the dependencies of every .o file. +# +# It is important that this file be added because it is unknowable whether +# the #defines in it were depended upon by a module to alter its behaviour +# at compile time. For example to pass some flags or not pass some flags +# to a function. + +HIDDEN_DEP = "include/generated/autoconf.h" + class StopError(Exception): """Exception raised to stop work when an unexpected error occurs.""" @@ -144,55 +162,57 @@ def makefile_assignment_split(assignment: str) -> Tuple[str, str]: return result[0], result[1] # left, right -def extract_c_src(obj: str, dependencies: List[str]) -> Tuple[str, List[str]]: - """Separate the C source file from the other dependencies. - - Returns a tuple with the C source code file and a list with the remaining - dependencies. If the source file is not a C source file: - return "", [] - an ealier implementation used: - returne None, [] - but that caused type errors from ptype. Instead of obfuscating the type - of the value of this function, returning "", [] is appropriate. - """ - if not dependencies: - raise StopError("empty dependencies for: " + obj) - src = dependencies[0] - if not src.endswith(".c"): - return "", [] - return src, dependencies[1:] - - -def get_src_ccline_deps(obj: str) -> Tuple[str, str, List[str]]: +def get_src_ccline_deps(obj: str) -> Optional[Tuple[str, str, List[str]]]: """Get the C source file, its cc_line, and non C source dependencies. If the tool used to produce the object is not the compiler, or if the - source file is not a C source file then it returns: - "", "" [] + source file is not a C source file None is returned. Otherwise it returns a triplet with the C source file name, its cc_line, the remaining dependencies. """ - dot_obj = os.path.join(os.path.dirname(obj), "." + os.path.basename(obj)) - cmd = dot_obj + ".cmd" - content = readfile(cmd) - line = lines_get_first_line(content) - _, cc_line = makefile_assignment_split(line) + o_cmd = os.path.join(os.path.dirname(obj), + "." + os.path.basename(obj) + ".cmd") + + contents = readfile(o_cmd) + contents = re.sub(r"\$\(wildcard[^)]*\)", " ", contents) + contents = re.sub(r"[ \t]*\\\n[ \t]*", " ", contents) + lines = lines_to_list(contents) + + cc_line = None + deps = None + source = None + for line in lines: + if line.startswith("cmd_"): + cc_line = line + elif line.startswith("deps_"): + deps = line + elif line.startswith("source_"): + source = line + + if cc_line is None: + raise StopError("missing cmd_* variable in: " + o_cmd) + _, cc_line = makefile_assignment_split(cc_line) if cc_line.split(maxsplit=1)[0] != COMPILER: # The object file was made by strip, symbol renames, etc. # i.e. it was not the result of running the compiler, thus # it can not contribute to #define compile time constants. - return "", "", [] + return None + + if source is None: + raise StopError("missing source_* variable in: " + o_cmd) + _, source = makefile_assignment_split(source) + source = source.strip() + if not source.endswith(".c"): + return None - odkeep = dot_obj + ".d.keep" - file_must_exist(odkeep) - content = readfile(odkeep) - src, dependendencies = extract_c_src( - obj, makefile_depends_get_dependencies(content)) - if not src: - return "", "", [] + if deps is None: + raise StopError("missing deps_* variable in: " + o_cmd) + _, deps = makefile_assignment_split(deps) + dependendencies = deps.split() + dependendencies.append(HIDDEN_DEP) - return src, cc_line, dependendencies + return source, cc_line, dependendencies def lines_to_list(lines: str) -> List[str]: @@ -455,9 +475,9 @@ class KernelComponentBase: # pylint: disable=too-few-public-methods the risk of invoking member functions at run-time on objects that do not provide them. Having this class makes the code more reliable. """ - def get_error(self) -> str: # pylint: disable=no-self-use - """Return an empty error string, which means there was no error.""" - return "" + def get_error(self) -> Optional[str]: # pylint: disable=no-self-use + """Return None for the error, means there was no error.""" + return None def get_deps_set(self) -> Set[str]: # pylint: disable=no-self-use """Return the set of dependencies for the kernel component.""" @@ -480,7 +500,7 @@ class KernelComponentCreationError(KernelComponentBase): # pylint: disable=too- self._error = error self._filename = filename - def get_error(self) -> str: + def get_error(self) -> Optional[str]: """Return the error.""" return self._filename + ": " + self._error @@ -511,9 +531,10 @@ class KernelComponent(KernelComponentBase): self._targets = [] for obj in self._files_o: file_must_exist(obj) - src, cc_line, dependendencies = get_src_ccline_deps(obj) - if not cc_line or not src: + result = get_src_ccline_deps(obj) + if result is None: continue + src, cc_line, dependendencies = result file_must_exist(src) depends = [] @@ -566,24 +587,6 @@ def kernel_component_factory(filename: str) -> KernelComponentBase: " ".join([*stop_error.args])) -def all_ko_and_vmlinux() -> Iterable[str]: - """Generator that yields vmlinux.o and all the *.ko files.""" - - # TODO(pantin): remove if no measurable slowdown when using (below): - # - # components = pool.map(kernel_component_factory, ["vmlinux.o"] + - # [str(ko) for ko in pathlib.Path().rglob("*.ko")]) - # - # instead of: - # - # components = pool.map( - # kernel_component_factory, all_ko_and_vmlinux()) - # - yield "vmlinux.o" # yield vmlinux.o so its worked on first - for kofile in pathlib.Path().rglob("*.ko"): - yield str(kofile) - - def work_on_all_components() -> List[KernelComponentBase]: """Return a list of KernelComponentBase objects.""" @@ -605,7 +608,7 @@ def work_on_whole_build() -> int: failed = False for comp in components: error = comp.get_error() - if error != "": + if error: logging.error(error) failed = True continue @@ -646,7 +649,7 @@ def main() -> int: comp = kernel_component_factory(args.file) error = comp.get_error() - if error != "": + if error: logging.error(error) return 1 if DEBUG: |