Add a cargo_build_script_run rule (#320)
This rule allows to run a build.rs file (cf. https://doc.rust-lang.org/cargo/reference/build-scripts.html), get its output (environment variable, rust flags and generated flags) and pass it to `rust_binary` and `rust_library` in order to build crate with build script.
Example of use:
```rust
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_library")
load("@io_bazel_rules_rust//cargo:cargo_build_script.bzl", "cargo_build_script")
cargo_build_script(
name = "build_script",
srcs = ["build_script.rs"],
data = ["test.txt"],
)
rust_library(
name = "lib",
srcs = ["lib.rs"],
deps = [":build_script_run"],
deps = [":build_script"],
)
```
diff --git a/cargo/BUILD b/cargo/BUILD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cargo/BUILD
diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl
new file mode 100644
index 0000000..79326c9
--- /dev/null
+++ b/cargo/cargo_build_script.bzl
@@ -0,0 +1,122 @@
+load("@io_bazel_rules_rust//rust:private/rustc.bzl", "BuildInfo", "rustc_compile_action")
+load("@io_bazel_rules_rust//rust:private/utils.bzl", "find_toolchain")
+load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")
+
+def _cargo_build_script_run(ctx, script):
+ toolchain = find_toolchain(ctx)
+ out_dir = ctx.actions.declare_directory(ctx.label.name + ".out_dir")
+ env_out = ctx.actions.declare_file(ctx.label.name + ".env")
+ flags_out = ctx.actions.declare_file(ctx.label.name + ".flags")
+ manifest_dir = "%s.runfiles/%s" % (script.path, ctx.label.workspace_name or ctx.workspace_name)
+ env = {
+ "CARGO_MANIFEST_DIR": manifest_dir,
+ "RUSTC": toolchain.rustc.path,
+ "TARGET": toolchain.target_triple,
+ "OUT_DIR": out_dir.path,
+ }
+
+ for f in ctx.attr.crate_features:
+ env["CARGO_FEATURE_" + f.upper().replace("-", "_")] = "1"
+
+ ctx.actions.run(
+ executable = ctx.executable._cargo_build_script_runner,
+ arguments = [script.path, env_out.path, flags_out.path],
+ outputs = [out_dir, env_out, flags_out],
+ tools = [script, ctx.executable._cargo_build_script_runner],
+ inputs = [script, toolchain.rustc],
+ mnemonic = "CargoBuildScriptRun",
+ env = env,
+ )
+
+ return [
+ BuildInfo(
+ out_dir = out_dir,
+ rustc_env = env_out,
+ flags = flags_out,
+ ),
+ ]
+
+def _build_script_impl(ctx):
+ return _cargo_build_script_run(ctx, ctx.executable.script)
+
+_build_script_run = rule(
+ _build_script_impl,
+ attrs = {
+ "script": attr.label(
+ executable = True,
+ allow_files = True,
+ mandatory = True,
+ cfg = "host",
+ doc = "The binary script to run, generally a rust_binary target. ",
+ ),
+ "crate_features": attr.string_list(doc = "The list of rust features that the build script should consider activated."),
+ "_cargo_build_script_runner": attr.label(
+ executable = True,
+ allow_files = True,
+ default = Label("//cargo/cargo_build_script_runner:cargo_build_script_runner"),
+ cfg = "host",
+ ),
+ },
+ toolchains = [
+ "@io_bazel_rules_rust//rust:toolchain",
+ ],
+)
+
+def cargo_build_script(name, crate_features=[], **kwargs):
+ """
+ Compile and execute a rust build script to generate build attributes
+
+ This rules take the same arguments as rust_binary.
+
+ Example:
+
+ Suppose you have a crate with a cargo build script `build.rs`:
+
+ ```
+ [workspace]/
+ hello_lib/
+ BUILD
+ build.rs
+ src/
+ lib.rs
+ ```
+
+ Then you want to use the build script in the following:
+
+ `hello_lib/BUILD`:
+ ```python
+ package(default_visibility = ["//visibility:public"])
+
+ load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary", "rust_library")
+ load("@io_bazel_rules_rust//cargo:cargo_build_script.bzl", "cargo_build_script")
+
+ # This will run the build script from the root of the workspace, and
+ # collect the outputs.
+ cargo_build_script(
+ name = "build_script",
+ srcs = ["build.rs"],
+ # Data are shipped during execution.
+ data = ["src/lib.rs"],
+ )
+
+ rust_library(
+ name = "hello_lib",
+ srcs = [
+ "src/lib.rs",
+ ],
+ deps = [":build_script"],
+ )
+ ```
+
+ The `hello_lib` target will be build with the flags and the environment variables declared by the
+ build script in addition to the file generated by it.
+ """
+ rust_binary(name = name + "_script_",
+ crate_features = crate_features,
+ **kwargs,
+ )
+ _build_script_run(
+ name = name,
+ script = ":%s_script_" % name,
+ crate_features = crate_features,
+ )
diff --git a/cargo/cargo_build_script_runner/BUILD b/cargo/cargo_build_script_runner/BUILD
new file mode 100644
index 0000000..15ad96c
--- /dev/null
+++ b/cargo/cargo_build_script_runner/BUILD
@@ -0,0 +1,18 @@
+load("//rust:rust.bzl", "rust_binary", "rust_library", "rust_test")
+
+rust_library(
+ name = "cargo_build_script_output_parser",
+ srcs = ["lib.rs"],
+)
+
+rust_test(
+ name = "test",
+ crate = ":cargo_build_script_output_parser",
+)
+
+rust_binary(
+ name = "cargo_build_script_runner",
+ srcs = ["bin.rs"],
+ visibility = ["//visibility:public"],
+ deps = [":cargo_build_script_output_parser"],
+)
diff --git a/cargo/cargo_build_script_runner/bin.rs b/cargo/cargo_build_script_runner/bin.rs
new file mode 100644
index 0000000..7946e93
--- /dev/null
+++ b/cargo/cargo_build_script_runner/bin.rs
@@ -0,0 +1,60 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// A simple wrapper around a build_script execution to generate file to reuse
+// by rust_library/rust_binary.
+extern crate cargo_build_script_output_parser;
+
+use cargo_build_script_output_parser::BuildScriptOutput;
+use std::env;
+use std::fs::{File, canonicalize, create_dir_all};
+use std::io::Write;
+use std::process::{exit, Command};
+
+fn main() {
+ let mut args = env::args().skip(1);
+ let manifest_dir_env = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR was not set");
+ let out_dir_env = env::var("OUT_DIR").expect("OUT_DIR was not set");
+ // For some reason RBE does not creat the output directory, force create it
+ create_dir_all(out_dir_env.clone()).expect(&format!("Failed to create OUT_DIR: {}", out_dir_env));
+ let rustc_env = env::var("RUSTC").expect("RUSTC was not set");
+ // Because of the Bazel's sandbox, bazel cannot provide full path, convert all relative path to correct path.
+ let manifest_dir = canonicalize(&manifest_dir_env).expect(&format!("Failed to canonicalize '{}'", manifest_dir_env));
+ let out_dir = canonicalize(&out_dir_env).expect(&format!("Failed to canonicalize '{}'", out_dir_env));
+ let rustc = canonicalize(&rustc_env).expect(&format!("Failed to canonicalize '{}'", rustc_env));
+ match (args.next(), args.next(), args.next()) {
+ (Some(progname), Some(envfile), Some(flagfile)) => {
+ let output = BuildScriptOutput::from_command(
+ Command::new(
+ canonicalize(&progname).expect(&format!("Failed to canonicalize '{}'", progname)))
+ .args(args)
+ .current_dir(manifest_dir.clone())
+ .env("OUT_DIR", out_dir)
+ .env("CARGO_MANIFEST_DIR", manifest_dir)
+ .env("RUSTC", rustc));
+ let mut f =
+ File::create(&envfile).expect(&format!("Unable to create file {}", envfile));
+ f.write_all(BuildScriptOutput::to_env(&output).as_bytes())
+ .expect(&format!("Unable to write file {}", envfile));
+ let mut f =
+ File::create(&flagfile).expect(&format!("Unable to create file {}", flagfile));
+ f.write_all(BuildScriptOutput::to_flags(&output).as_bytes())
+ .expect(&format!("Unable to write file {}", flagfile));
+ }
+ _ => {
+ eprintln!("Usage: $0 progname envfile flagfile [arg1...argn]");
+ exit(1);
+ }
+ }
+}
diff --git a/cargo/cargo_build_script_runner/lib.rs b/cargo/cargo_build_script_runner/lib.rs
new file mode 100644
index 0000000..387626f
--- /dev/null
+++ b/cargo/cargo_build_script_runner/lib.rs
@@ -0,0 +1,169 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Parse the output of a cargo build.rs script and generate a list of flags and
+//! environment variable for the build.
+use std::io::{BufRead, BufReader, Read};
+use std::process::{Command, Stdio};
+
+/// Enum containing all the considered return value from the script
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum BuildScriptOutput {
+ /// cargo:rustc-link-lib
+ LinkLib(String),
+ /// cargo:rustc-link-search
+ LinkSearch(String),
+ /// cargo:rustc-cfg
+ Cfg(String),
+ /// cargo:rustc-flags
+ Flags(String),
+ /// cargo:rustc-env
+ Env(String),
+}
+
+impl BuildScriptOutput {
+ /// Converts a line into a [BuildScriptOutput] enum.
+ ///
+ /// Examples
+ /// ```rust
+ /// assert_eq!(BuildScriptOutput::new("cargo:rustc-link-lib=lib"), Some(BuildScriptOutput::LinkLib("lib".to_owned())));
+ /// ```
+ fn new(line: &str) -> Option<BuildScriptOutput> {
+ let split = line.splitn(2, '=').collect::<Vec<_>>();
+ if split.len() <= 1 {
+ return None;
+ }
+ let param = split[1].trim().to_owned();
+ match split[0] {
+ "cargo:rustc-link-lib" => Some(BuildScriptOutput::LinkLib(param)),
+ "cargo:rustc-link-search" => Some(BuildScriptOutput::LinkSearch(param)),
+ "cargo:rustc-cfg" => Some(BuildScriptOutput::Cfg(param)),
+ "cargo:rustc-flags" => Some(BuildScriptOutput::Flags(param)),
+ "cargo:rustc-env" => Some(BuildScriptOutput::Env(param)),
+ "cargo:rerun-if-changed" | "cargo:rerun-if-env-changed" =>
+ // Ignored because Bazel will re-run if those change all the time.
+ None,
+ "cargo:warning" => {
+ eprintln!("Build Script Warning: {}", split[1]);
+ None
+ },
+ _ => {
+ // Not yet supported:
+ // cargo:KEY=VALUE — Metadata, used by links scripts.
+ // cargo:rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates.
+ eprintln!("Warning: build script returned unsupported directive `{}`", split[0]);
+ None
+ },
+ }
+ }
+
+ /// Converts a [BufReader] into a vector of [BuildScriptOutput] enums.
+ fn from_reader<T: Read>(mut reader: BufReader<T>) -> Vec<BuildScriptOutput> {
+ let mut result = Vec::<BuildScriptOutput>::new();
+ let mut line = String::new();
+ while reader.read_line(&mut line).expect("Cannot read line") != 0 {
+ if let Some(bso) = BuildScriptOutput::new(&line) {
+ result.push(bso);
+ }
+ line.clear();
+ }
+ result
+ }
+
+ /// Take a [Command], execute it and converts its input into a vector of [BuildScriptOutput]
+ pub fn from_command(cmd: &mut Command) -> Vec<BuildScriptOutput> {
+ let mut child = cmd.stdout(Stdio::piped()).spawn().expect("Unable to start binary");
+ let ecode = child.wait().expect("failed to wait on child");
+ let reader = BufReader::new(
+ child
+ .stdout
+ .as_mut()
+ .expect("Failed to open stdout"),
+ );
+ assert!(ecode.success());
+ Self::from_reader(reader)
+ }
+
+ /// Convert a vector of [BuildScriptOutput] into a list of environment variables.
+ pub fn to_env(v: &Vec<BuildScriptOutput>) -> String {
+ v.iter()
+ .filter_map(|x| {
+ if let BuildScriptOutput::Env(env) = x {
+ Some(env.to_owned())
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>()
+ .join(" ")
+ }
+
+ /// Convert a vector of [BuildScriptOutput] into a flagfile.
+ pub fn to_flags(v: &Vec<BuildScriptOutput>) -> String {
+ v.iter()
+ .filter_map(|x| match x {
+ BuildScriptOutput::Cfg(e) => Some(format!("--cfg={}", e)),
+ BuildScriptOutput::Flags(e) => Some(e.to_owned()),
+ BuildScriptOutput::LinkLib(e) => Some(format!("-l{}", e)),
+ BuildScriptOutput::LinkSearch(e) => Some(format!("-L{}", e)),
+ _ => None,
+ })
+ .collect::<Vec<_>>()
+ .join(" ")
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::io::Cursor;
+
+ #[test]
+ fn test_from_read_buffer_to_env_and_flags() {
+ let buff = Cursor::new(
+ "
+cargo:rustc-link-lib=sdfsdf
+cargo:rustc-env=FOO=BAR
+cargo:rustc-link-search=bleh
+cargo:rustc-env=BAR=FOO
+cargo:rustc-flags=-Lblah
+cargo:invalid=ignored
+cargo:rerun-if-changed=ignored
+cargo:rustc-cfg=feature=awesome
+",
+ );
+ let reader = BufReader::new(buff);
+ let result = BuildScriptOutput::from_reader(reader);
+ assert_eq!(result.len(), 6);
+ assert_eq!(result[0], BuildScriptOutput::LinkLib("sdfsdf".to_owned()));
+ assert_eq!(result[1], BuildScriptOutput::Env("FOO=BAR".to_owned()));
+ assert_eq!(result[2], BuildScriptOutput::LinkSearch("bleh".to_owned()));
+ assert_eq!(result[3], BuildScriptOutput::Env("BAR=FOO".to_owned()));
+ assert_eq!(result[4], BuildScriptOutput::Flags("-Lblah".to_owned()));
+ assert_eq!(
+ result[5],
+ BuildScriptOutput::Cfg("feature=awesome".to_owned())
+ );
+
+ assert_eq!(
+ BuildScriptOutput::to_env(&result),
+ "FOO=BAR BAR=FOO".to_owned()
+ );
+ assert_eq!(
+ BuildScriptOutput::to_flags(&result),
+ "-lsdfsdf -Lbleh -Lblah --cfg=feature=awesome".to_owned()
+ );
+ }
+
+}
diff --git a/examples/cargo/BUILD b/examples/cargo/BUILD
new file mode 100644
index 0000000..6949638
--- /dev/null
+++ b/examples/cargo/BUILD
@@ -0,0 +1,28 @@
+load(
+ "@io_bazel_rules_rust//rust:rust.bzl",
+ "rust_binary",
+ "rust_library",
+ "rust_test",
+)
+load(
+ "@io_bazel_rules_rust//cargo:cargo_build_script.bzl",
+ "cargo_build_script",
+)
+
+cargo_build_script(
+ name = "build_script",
+ srcs = ["build_script.rs"],
+ data = ["test.txt"],
+ crate_features = ["bleh"],
+)
+
+rust_library(
+ name = "lib",
+ srcs = ["lib.rs"],
+ deps = [":build_script"],
+)
+
+rust_test(
+ name = "test",
+ crate = ":lib",
+)
diff --git a/examples/cargo/build_script.rs b/examples/cargo/build_script.rs
new file mode 100644
index 0000000..6c325fe
--- /dev/null
+++ b/examples/cargo/build_script.rs
@@ -0,0 +1,30 @@
+// Copyright 2020 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use std::io::prelude::*;
+use std::fs::File;
+use std::env;
+
+fn main() {
+ let bleh = env::var("CARGO_FEATURE_BLEH").unwrap();
+ let out_dir = env::var("OUT_DIR").unwrap();
+ let data = std::fs::read("cargo/test.txt").unwrap();
+ assert!(!bleh.is_empty());
+ println!(r#"cargo:rustc-env=FOO=BAR
+cargo:rustc-env=BAR=FOO
+cargo:rustc-flags=--cfg=blah="bleh"
+cargo:rustc-flags=--cfg=data="{}"
+cargo:rustc-cfg=foobar"#, std::str::from_utf8(&data).unwrap());
+ let mut file = File::create(format!("{}/hello.world.txt", out_dir)).unwrap();
+ file.write_all(b"Hello, world!").unwrap();
+}
\ No newline at end of file
diff --git a/examples/cargo/lib.rs b/examples/cargo/lib.rs
new file mode 100644
index 0000000..f1f1389
--- /dev/null
+++ b/examples/cargo/lib.rs
@@ -0,0 +1,36 @@
+// Copyright 2020 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+mod test {
+ #[test]
+ fn test_env_contents() {
+ assert_eq!(env!("FOO"), "BAR");
+ assert_eq!(env!("BAR"), "FOO");
+ }
+
+ #[test]
+ fn test_cfg_contents() {
+ assert!(cfg!(foobar));
+ }
+
+ #[test]
+ fn test_rustc_contents() {
+ assert!(cfg!(blah = "bleh"));
+ }
+
+ #[test]
+ fn test_access_data() {
+ assert!(cfg!(data = "Yeah!"));
+ }
+}
\ No newline at end of file
diff --git a/examples/cargo/test.txt b/examples/cargo/test.txt
new file mode 100644
index 0000000..2eda9ce
--- /dev/null
+++ b/examples/cargo/test.txt
@@ -0,0 +1 @@
+Yeah!
\ No newline at end of file
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index 1b93e94..2819f0f 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -39,11 +39,19 @@
},
)
+BuildInfo = provider(
+ fields = {
+ "flags": """File: file containing additional flags to pass to rustc""",
+ "out_dir": """File: directory containing the result of a build script""",
+ "rustc_env": """File: file containing additional environment variables to set for rustc.""",
+ },
+)
+
AliasableDep = provider(
fields = {
"name": "str",
"dep": "CrateInfo",
- }
+ },
)
DepInfo = provider(
@@ -110,8 +118,9 @@
transitive_crates = depset()
transitive_dylibs = depset(order = "topological") # dylib link flag ordering matters.
transitive_staticlibs = depset()
+ build_info = None
- aliases = {k.label: v for k,v in aliases.items()}
+ aliases = {k.label: v for k, v in aliases.items()}
for dep in deps:
if CrateInfo in dep:
# This dependency is a rust_library
@@ -134,6 +143,10 @@
staticlibs = [l for l in libs.to_list() if l.basename.endswith(toolchain.staticlib_ext)]
transitive_dylibs = depset(transitive = [transitive_dylibs, depset(dylibs)])
transitive_staticlibs = depset(transitive = [transitive_staticlibs, depset(staticlibs)])
+ elif BuildInfo in dep:
+ if build_info:
+ fail("Several deps are providing build information, only one is allowed in the dependencies", "deps")
+ build_info = dep[BuildInfo]
else:
fail("rust targets can only depend on rust_library, rust_*_library or cc_library targets." + str(dep), "deps")
@@ -142,12 +155,15 @@
transitive = [transitive_staticlibs, transitive_dylibs],
)
- return DepInfo(
- direct_crates = depset(direct_crates),
- transitive_crates = transitive_crates,
- transitive_dylibs = transitive_dylibs,
- transitive_staticlibs = transitive_staticlibs,
- transitive_libs = transitive_libs.to_list(),
+ return (
+ DepInfo(
+ direct_crates = depset(direct_crates),
+ transitive_crates = transitive_crates,
+ transitive_dylibs = transitive_dylibs,
+ transitive_staticlibs = transitive_staticlibs,
+ transitive_libs = transitive_libs.to_list(),
+ ),
+ build_info,
)
def _get_linker_and_args(ctx, rpaths):
@@ -211,7 +227,7 @@
"""
output_dir = crate_info.output.dirname
- dep_info = collect_deps(
+ dep_info, build_info = collect_deps(
crate_info.deps,
crate_info.aliases,
toolchain,
@@ -233,6 +249,7 @@
dep_info.transitive_libs +
[toolchain.rustc] +
toolchain.crosstool_files +
+ ([build_info.rustc_env, build_info.flags] if build_info else []) +
([] if linker_script == None else [linker_script]),
transitive = [
toolchain.rustc_lib.files,
@@ -292,7 +309,7 @@
add_crate_link_flags(args, dep_info)
# We awkwardly construct this command because we cannot reference $PWD from ctx.actions.run(executable=toolchain.rustc)
- out_dir = _create_out_dir_action(ctx)
+ out_dir = _create_out_dir_action(ctx, build_info.out_dir if build_info else None)
if out_dir:
compile_inputs = depset([out_dir], transitive = [compile_inputs])
out_dir_env = "OUT_DIR=$(pwd)/{} ".format(out_dir.path)
@@ -336,10 +353,12 @@
dst = crate_info.output.path
if src != dst:
maybe_rename = " && /bin/mv {src} {dst}".format(src=src, dst=dst)
- command = '{}{}{} "$@" --remap-path-prefix="$(pwd)"=__bazel_redacted_pwd{}'.format(
+ command = '{}{}{}{} "$@" --remap-path-prefix="$(pwd)"=__bazel_redacted_pwd{}{}'.format(
+ ("export $(cat %s);" % build_info.rustc_env.path) if build_info else "",
manifest_dir_env,
out_dir_env,
toolchain.rustc.path,
+ (" $(cat '%s')" % build_info.flags.path) if build_info else "",
maybe_rename,
)
@@ -366,7 +385,10 @@
arguments = [args],
mnemonic = "Rustc",
progress_message = "Compiling Rust {} {}{} ({} files)".format(
- crate_info.type, ctx.label.name, formatted_version, len(crate_info.srcs)
+ crate_info.type,
+ ctx.label.name,
+ formatted_version,
+ len(crate_info.srcs),
),
)
runfiles = ctx.runfiles(
@@ -393,19 +415,25 @@
if crate.edition != "2015":
args.add("--edition={}".format(crate.edition))
-def _create_out_dir_action(ctx):
+def _create_out_dir_action(ctx, build_info_out_dir = None):
tar_file = getattr(ctx.file, "out_dir_tar", None)
if not tar_file:
- return None
-
- out_dir = ctx.actions.declare_directory(ctx.label.name + ".out_dir")
- ctx.actions.run_shell(
- # TODO: Remove system tar usage
- command = "rm -fr {dir} && mkdir {dir} && tar -xzf {tar} -C {dir}".format(tar = tar_file.path, dir = out_dir.path),
- inputs = [tar_file],
- outputs = [out_dir],
- use_default_shell_env = True, # Sets PATH for tar and gzip (tar's dependency)
- )
+ return build_info_out_dir
+ else:
+ out_dir = ctx.actions.declare_directory(ctx.label.name + ".out_dir")
+ ctx.actions.run_shell(
+ # TODO: Remove system tar usage
+ command = ";".join([
+ "rm -fr {dir} && mkdir {dir} && tar -xzf {tar} -C {dir}".format(tar = tar_file.path, dir = out_dir.path),
+ ] + (
+ ["pushd {dir}; cp -fr {in_dir}; popd".format(dir = out_dir.path, in_dir = build_info_out_dir.path)
+ ] if build_info_out_dir else []
+ )),
+ progress_message = "Creating OUT_DIR = %s" % out_dir.path,
+ inputs = [tar_file] + (build_info_out_dir or []),
+ outputs = [out_dir],
+ use_default_shell_env = True, # Sets PATH for tar and gzip (tar's dependency)
+ )
return out_dir
def _compute_rpaths(toolchain, output_dir, dep_info):