cargo: Fix handling of relative sysroots (#1371)
Currently, `cc_toolchain.sysroot` is appended as an argument to "CC" and
"CXX". This argument, however, will typically be overridden by any
--sysroot flag already present in "CFLAGS" and "CXXFLAGS". When sysroot
is relative, this fails because cargo_build_script_runner is not
executed from the execroot.
Do not append `--sysroot` to "CC" and "CXX". Instead, modify any
--sysroot arguments with relative paths to be absolute.
diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl
index ce5b5d9..d53c6e1 100644
--- a/cargo/cargo_build_script.bzl
+++ b/cargo/cargo_build_script.bzl
@@ -1,4 +1,5 @@
# buildifier: disable=module-docstring
+load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "CPP_COMPILE_ACTION_NAME", "C_COMPILE_ACTION_NAME")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("//rust:defs.bzl", "rust_binary", "rust_common")
@@ -43,6 +44,24 @@
)
return cc_c_args, cc_cxx_args, cc_env
+def _pwd_flags(args):
+ """Prefix execroot-relative paths of known arguments with ${pwd}.
+
+ Args:
+ args (list): List of tool arguments.
+
+ Returns:
+ list: The modified argument list.
+ """
+ res = []
+ for arg in args:
+ s, opt, path = arg.partition("--sysroot=")
+ if s == "" and not paths.is_absolute(path):
+ res.append("{}${{pwd}}/{}".format(opt, path))
+ else:
+ res.append(arg)
+ return res
+
def _build_script_impl(ctx):
"""The implementation for the `_build_script_run` rule.
@@ -111,7 +130,7 @@
linker, link_args, linker_env = get_linker_and_args(ctx, ctx.attr, cc_toolchain, feature_configuration, None)
env.update(**linker_env)
env["LD"] = linker
- env["LDFLAGS"] = " ".join(link_args)
+ env["LDFLAGS"] = " ".join(_pwd_flags(link_args))
# MSVC requires INCLUDE to be set
cc_c_args, cc_cxx_args, cc_env = get_cc_compile_args_and_env(cc_toolchain, feature_configuration)
@@ -129,14 +148,12 @@
ar_executable = cc_toolchain.ar_executable
if ar_executable:
env["AR"] = ar_executable
- if cc_toolchain.sysroot:
- env["SYSROOT"] = cc_toolchain.sysroot
# Populate CFLAGS and CXXFLAGS that cc-rs relies on when building from source, in particular
# to determine the deployment target when building for apple platforms (`macosx-version-min`
# for example, itself derived from the `macos_minimum_os` Bazel argument).
- env["CFLAGS"] = " ".join(cc_c_args)
- env["CXXFLAGS"] = " ".join(cc_cxx_args)
+ env["CFLAGS"] = " ".join(_pwd_flags(cc_c_args))
+ env["CXXFLAGS"] = " ".join(_pwd_flags(cc_cxx_args))
# Inform build scripts of rustc flags
# https://github.com/rust-lang/cargo/issues/9600
diff --git a/cargo/cargo_build_script_runner/bin.rs b/cargo/cargo_build_script_runner/bin.rs
index 58f0363..50adfca 100644
--- a/cargo/cargo_build_script_runner/bin.rs
+++ b/cargo/cargo_build_script_runner/bin.rs
@@ -89,14 +89,9 @@
}
}
- for compiler_env_var in &["CC", "CXX"] {
- if let Some(compiler_path) = env::var_os(compiler_env_var) {
- let mut compiler_path = exec_root.join(compiler_path).into_os_string();
- if let Some(sysroot_path) = env::var_os("SYSROOT") {
- compiler_path.push(" --sysroot=");
- compiler_path.push(&exec_root.join(sysroot_path));
- }
- command.env(compiler_env_var, compiler_path);
+ for tool_env_var in &["CC", "CXX", "LD"] {
+ if let Some(tool_path) = env::var_os(tool_env_var) {
+ command.env(tool_env_var, exec_root.join(tool_path));
}
}
@@ -111,10 +106,6 @@
}
}
- if let Some(ld_path) = env::var_os("LD") {
- command.env("LD", exec_root.join(ld_path));
- }
-
// replace env vars with a ${pwd} prefix with the exec_root
for (key, value) in env::vars() {
let exec_root_str = exec_root.to_str().expect("exec_root not in utf8");
diff --git a/test/cargo_build_script/build.rs b/test/cargo_build_script/build.rs
index 7ae8342..72e07bb 100644
--- a/test/cargo_build_script/build.rs
+++ b/test/cargo_build_script/build.rs
@@ -31,21 +31,10 @@
// Assert that the CC, CXX and LD env vars existed and were executable.
// We don't assert what happens when they're executed (in particular, we don't check for a
// non-zero exit code), but this asserts that it's an existing file which is executable.
- //
- // Unfortunately we need to shlex the path, because we add a `--sysroot=...` arg to the env var.
for env_var in &["CC", "CXX", "LD"] {
- let v = std::env::var(env_var)
+ let path = std::env::var(env_var)
.unwrap_or_else(|err| panic!("Error getting {}: {}", env_var, err));
- let (path, args) = if let Some(index) = v.find("--sysroot") {
- let (path, args) = v.split_at(index);
- (path, Some(args))
- } else {
- (v.as_str(), None)
- };
- std::process::Command::new(path)
- .args(args.into_iter())
- .status()
- .unwrap();
+ std::process::Command::new(path).status().unwrap();
}
// Assert that some env variables are set.