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.