summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-02-20 23:22:32 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-02-20 23:22:32 +0000
commit8cd44ced35ae0d5537138c1f82ea3346f0f0abcb (patch)
tree4b11f2c588aa4c5db5bde5bc3e8e0e9d1b240731
parent8c621bcbeb8d0330695ef5c0bfe2d80946f8157c (diff)
parent0188d416ac65a0c4a94ed5e2f79c1cdf5d76b1db (diff)
downloadbuild-8cd44ced35ae0d5537138c1f82ea3346f0f0abcb.tar.gz
kmi_defines: Removed need for .o.d.keep files am: 0188d416ac
Change-Id: Ib0ea54e3e7f78205e653b80edc7655851347063a
-rwxr-xr-xabi/kmi_defines.py129
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: