From a154421f99f8c5c76949474f7b83dcfb94a2511d Mon Sep 17 00:00:00 2001 From: Mike Hommey <mh+mozilla@glandium.org> Date: Tue, 23 Nov 2021 02:28:18 +0000 Subject: [PATCH] Bug 1740042 - Use llvm-readelf instead of readelf when available. r=firefox-build-system-reviewers,mhentges Differential Revision: https://phabricator.services.mozilla.com/D130949 --- build/moz.configure/checks.configure | 8 ++ build/unix/elfhack/Makefile.in | 2 +- moz.configure | 83 ++++++++++++++----- .../mozbuild/mozbuild/action/check_binary.py | 2 +- toolkit/library/build/dependentlibs.py | 2 +- 5 files changed, 72 insertions(+), 25 deletions(-) diff --git a/build/moz.configure/checks.configure b/build/moz.configure/checks.configure index a8ac81676ae38..6634933fbb808 100644 --- a/build/moz.configure/checks.configure +++ b/build/moz.configure/checks.configure @@ -95,6 +95,10 @@ def checking(what, callback=None): # passing $PATH (for example) as an element. # - `bootstrap` is a path relative to the bootstrap root path (e.g ~/.mozbuild) # where to find the program if it's bootstrapped. +# - `validate` is a callback function that takes a path and returns True if +# the program at that location is appropriate or not, or False if not. +# when the callback returns False, check_prog ignores the program and goes +# on to the next from the `progs` list. # # - `bootstrap_search_path` is not an argument that users of the template are # supposed to pass. See the override of check_prog in top-level moz.configure. @@ -115,6 +119,7 @@ def check_prog( paths=None, bootstrap=None, when=None, + validate=None, bootstrap_search_path=None, ): if input is not None: @@ -186,6 +191,9 @@ def check_prog( for prog in value or progs: log.debug("%s: Looking for %s", var.lower(), quote(prog)) result = find_program(prog, paths) + if validate and result and not validate(result): + log.debug("%s: %s found but didn't work", var.lower(), quote(result)) + continue if result: return result diff --git a/build/unix/elfhack/Makefile.in b/build/unix/elfhack/Makefile.in index 08cc3d6852956..57ad54f1134e0 100644 --- a/build/unix/elfhack/Makefile.in +++ b/build/unix/elfhack/Makefile.in @@ -14,7 +14,7 @@ test-array$(DLL_SUFFIX) test-ctors$(DLL_SUFFIX): %$(DLL_SUFFIX): %.$(OBJ_SUFFIX) @echo === Use --disable-elf-hack until this is fixed. @echo === # Fail if the library doesn't have $(DT_TYPE) .dynamic info - $(TOOLCHAIN_PREFIX)readelf -d $@ | grep '($(DT_TYPE))' + $(READELF) -d $@ | grep '($(DT_TYPE))' @rm -f $@.bak $(CURDIR)/elfhack -b -f $@ # Fail if the backup file doesn't exist diff --git a/moz.configure b/moz.configure index 5a103d844cc15..46795bd4fe4d5 100755 --- a/moz.configure +++ b/moz.configure @@ -946,32 +946,36 @@ check_prog("7Z", ("7z", "7za"), allow_missing=True, when=target_is_windows) check_prog("UPX", ("upx",), allow_missing=True, when=target_is_windows) -@depends(host_c_compiler, c_compiler, bindgen_config_paths) -def llvm_objdump(host_c_compiler, c_compiler, bindgen_config_paths): - clang = None - for compiler in (host_c_compiler, c_compiler): - if compiler and compiler.type == "clang": - clang = compiler.compiler - break - elif compiler and compiler.type == "clang-cl": - clang = os.path.join(os.path.dirname(compiler.compiler), "clang") - break - - if not clang and bindgen_config_paths: - clang = bindgen_config_paths.clang_path - llvm_objdump = "llvm-objdump" - if clang: - out = check_cmd_output( - clang, "--print-prog-name=llvm-objdump", onerror=lambda: None - ) - if out: - llvm_objdump = out.rstrip() - return (llvm_objdump,) +@template +def llvm_tool(name): + @depends(host_c_compiler, c_compiler, bindgen_config_paths) + def llvm_tool(host_c_compiler, c_compiler, bindgen_config_paths): + clang = None + for compiler in (host_c_compiler, c_compiler): + if compiler and compiler.type == "clang": + clang = compiler.compiler + break + elif compiler and compiler.type == "clang-cl": + clang = os.path.join(os.path.dirname(compiler.compiler), "clang") + break + + if not clang and bindgen_config_paths: + clang = bindgen_config_paths.clang_path + tool = name + if clang: + out = check_cmd_output( + clang, "--print-prog-name=%s" % tool, onerror=lambda: None + ) + if out: + tool = out.rstrip() + return (tool,) + + return llvm_tool llvm_objdump = check_prog( "LLVM_OBJDUMP", - llvm_objdump, + llvm_tool("llvm-objdump"), what="llvm-objdump", when="--enable-compile-environment", paths=clang_search_path, @@ -980,6 +984,41 @@ llvm_objdump = check_prog( add_old_configure_assignment("LLVM_OBJDUMP", llvm_objdump) +@depends(llvm_tool("llvm-readelf"), toolchain_prefix) +def readelf(llvm_readelf, toolchain_prefix): + commands = [llvm_readelf[0], "readelf"] + for prefix in toolchain_prefix or (): + commands.insert(1, "%sreadelf" % prefix) + return tuple(commands) + + +def validate_readelf(path): + # llvm-readelf from llvm < 8 doesn't support the GNU binutils-compatible `-d` + # flag. We could try running `$path -d $some_binary` but we might be cross + # compiling and not have a binary at hand to run that against. `$path -d` alone + # would fail whether the flag is supported or not. So we resort to look for the + # option in the `--help` output, which fortunately, s compatible between + # llvm-readelf and readelf. + retcode, stdout, stderr = get_cmd_output(path, "--help") + return retcode == 0 and any(l.startswith(" -d ") for l in stdout.splitlines()) + + +@depends("--enable-compile-environment", target, host) +def readelf_when(compile_env, target, host): + return compile_env and any( + x.kernel not in ("Darwin", "WINNT") for x in (target, host) + ) + + +check_prog( + "READELF", + readelf, + what="readelf", + when=readelf_when, + paths=clang_search_path, + validate=validate_readelf, +) + option("--enable-dtrace", help="Build with dtrace support") dtrace = check_header( diff --git a/python/mozbuild/mozbuild/action/check_binary.py b/python/mozbuild/mozbuild/action/check_binary.py index a2a566df6fe62..44362126210e5 100644 --- a/python/mozbuild/mozbuild/action/check_binary.py +++ b/python/mozbuild/mozbuild/action/check_binary.py @@ -27,7 +27,7 @@ HOST = {"platform": buildconfig.substs["HOST_OS_ARCH"], "readelf": "readelf"} TARGET = { "platform": buildconfig.substs["OS_TARGET"], - "readelf": "{}readelf".format(buildconfig.substs.get("TOOLCHAIN_PREFIX", "")), + "readelf": buildconfig.substs.get("READELF", "readelf"), } ADDR_RE = re.compile(r"[0-9a-f]{8,16}") diff --git a/toolkit/library/build/dependentlibs.py b/toolkit/library/build/dependentlibs.py index 974f5d7a70b9c..d7559844d40d2 100644 --- a/toolkit/library/build/dependentlibs.py +++ b/toolkit/library/build/dependentlibs.py @@ -44,7 +44,7 @@ def dependentlibs_win32_objdump(lib): def dependentlibs_readelf(lib): """Returns the list of dependencies declared in the given ELF .so""" proc = subprocess.Popen( - [substs.get("TOOLCHAIN_PREFIX", "") + "readelf", "-d", lib], + [substs.get("READELF", "readelf"), "-d", lib], stdout=subprocess.PIPE, universal_newlines=True, ) -- GitLab