From 57986d1e5be0879b0ee19820c0d513b4a5c970dd Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Mon, 22 Feb 2021 12:41:19 +0100 Subject: [PATCH] Workaround erroneous response file expansion Bazel 4.0.0's own cc_wrapper expands response files. However, it fails to make exceptions for legitimate arguments starting with `@` on macOS, such as `-install_name @rpath/...` or `-rpath @loader_path/...`. We use `-Wl,...` syntax for these arguments as a workaround. --- haskell/private/cc_wrapper.py.tpl | 45 ++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/haskell/private/cc_wrapper.py.tpl b/haskell/private/cc_wrapper.py.tpl index 04aec91d2f..61a2c6cc04 100644 --- a/haskell/private/cc_wrapper.py.tpl +++ b/haskell/private/cc_wrapper.py.tpl @@ -46,7 +46,7 @@ used to avoid command line length limitations. See https://gitlab.haskell.org/ghc/ghc/issues/17185. -- Fixes invocations that handle temporary and intermediate binaries +- Fixes invocations that handle temporary and intermediate binaries. GHC with Template Haskell or tools like hsc2hs build temporary Haskell binaries (that e.g. generate other Haskell code) as part of the build @@ -54,6 +54,18 @@ used to avoid command line length limitations. matches the characteristics of the wider build (e.g. runpath configuration, etc.) +- Avoids arguments starting with `@`. + + Bazel 4.0.0 has its own cc_wrapper on macOS which attempts to expand any + argument starting with `@` as a response file. This will wrongly interpret + the follwoing types of arguments as referencing a response file: + + -install_name @rpath/... + -Xlinker -rpath -Xlinker @executable_path/... + -Xlinker -rpath -Xlinker @loader_path/... + + See https://github.com/bazelbuild/bazel/pull/13044 + """ from bazel_tools.tools.python.runfiles import runfiles as bazel_runfiles @@ -198,6 +210,8 @@ class Args: pass elif self._handle_linker_arg(arg, args, out): pass + elif self._handle_install_name(arg, args, out): + pass elif self._handle_print_file_name(arg, args, out): pass elif self._handle_compile(arg, args, out): @@ -324,7 +338,15 @@ class Args: raise RuntimeError("Unhandled _prev_ld_arg '{}'.".format(self._prev_ld_arg)) if forward_ld_args: - if use_xlinker: + # Avoid arguments starting with `@`, see module docstring. + # Use `-Wl,...` in those cases instead of `-Xlinker ...`. + starts_with_at = any( + ld_arg.startswith("@rpath") or + ld_arg.startswith("@loader_path") or + ld_arg.startswith("@executable_path") + for ld_arg in forward_ld_args + ) + if use_xlinker and not starts_with_at: out.extend( arg for ld_arg in forward_ld_args @@ -335,6 +357,18 @@ class Args: return True + def _handle_install_name(self, arg, args, out): + consumed, install_name = argument(arg, args, long = "-install_name") + + if consumed: + # Avoid arguments starting with `@`, see module docstring. + # The compiler wrapper forwards `-install_name` to the linker. + # Here we use `-Wl,-install_name,...` directly to send the flag to + # the linker and avoid an argument starting with `@`. + out.append("-Wl,-install_name,{}".format(install_name)) + + return consumed + def _handle_rpath(self, rpath, out): # Filter out all RPATH flags for now and manually add the needed ones # later on. @@ -518,11 +552,10 @@ def shorten_path(input_path): def rpath_args(rpaths): """Generate arguments for RUNPATHs.""" + # Avoid arguments starting with `@`, see module docstring. + # Pass `-rpath` flags using `-Wl,...` instead of `-Xlinker ...`. for rpath in rpaths: - yield "-Xlinker" - yield "-rpath" - yield "-Xlinker" - yield rpath + yield "-Wl,-rpath,{}".format(rpath) # --------------------------------------------------------------------