Squashed 'third_party/rules_rust/' content from commit bf59038ca
git-subtree-dir: third_party/rules_rust
git-subtree-split: bf59038cac11798cbaef9f3bf965bad8182b97fa
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I5a20e403203d670df467ea97dde9a4ac40339a8d
diff --git a/cargo/cargo_build_script_runner/BUILD.bazel b/cargo/cargo_build_script_runner/BUILD.bazel
new file mode 100644
index 0000000..11edd45
--- /dev/null
+++ b/cargo/cargo_build_script_runner/BUILD.bazel
@@ -0,0 +1,24 @@
+load("//rust:defs.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"],
+)
+
+rust_test(
+ name = "bin_test",
+ crate = ":cargo_build_script_runner",
+ deps = [":cargo_build_script_runner"],
+)
diff --git a/cargo/cargo_build_script_runner/bin.rs b/cargo/cargo_build_script_runner/bin.rs
new file mode 100644
index 0000000..58f0363
--- /dev/null
+++ b/cargo/cargo_build_script_runner/bin.rs
@@ -0,0 +1,345 @@
+// 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, CompileAndLinkFlags};
+use std::collections::BTreeMap;
+use std::env;
+use std::fs::{create_dir_all, read_to_string, write};
+use std::path::Path;
+use std::process::Command;
+
+fn run_buildrs() -> Result<(), String> {
+ // We use exec_root.join rather than std::fs::canonicalize, to avoid resolving symlinks, as
+ // some execution strategies and remote execution environments may use symlinks in ways which
+ // canonicalizing them may break them, e.g. by having input files be symlinks into a /cas
+ // directory - resolving these may cause tools which inspect $0, or try to resolve files
+ // relative to themselves, to fail.
+ let exec_root = env::current_dir().expect("Failed to get current directory");
+ let manifest_dir_env = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR was not set");
+ let rustc_env = env::var("RUSTC").expect("RUSTC was not set");
+ let manifest_dir = exec_root.join(&manifest_dir_env);
+ let rustc = exec_root.join(&rustc_env);
+ let Options {
+ progname,
+ crate_links,
+ out_dir,
+ env_file,
+ compile_flags_file,
+ link_flags_file,
+ link_search_paths_file,
+ output_dep_env_path,
+ stdout_path,
+ stderr_path,
+ input_dep_env_paths,
+ } = parse_args()?;
+
+ let out_dir_abs = exec_root.join(&out_dir);
+ // For some reason Google's RBE does not create the output directory, force create it.
+ create_dir_all(&out_dir_abs)
+ .unwrap_or_else(|_| panic!("Failed to make output directory: {:?}", out_dir_abs));
+
+ let target_env_vars =
+ get_target_env_vars(&rustc_env).expect("Error getting target env vars from rustc");
+
+ let mut command = Command::new(exec_root.join(&progname));
+ command
+ .current_dir(&manifest_dir)
+ .envs(target_env_vars)
+ .env("OUT_DIR", out_dir_abs)
+ .env("CARGO_MANIFEST_DIR", manifest_dir)
+ .env("RUSTC", rustc)
+ .env("RUST_BACKTRACE", "full");
+
+ for dep_env_path in input_dep_env_paths.iter() {
+ if let Ok(contents) = read_to_string(dep_env_path) {
+ for line in contents.split('\n') {
+ // split on empty contents will still produce a single empty string in iterable.
+ if line.is_empty() {
+ continue;
+ }
+ let mut key_val = line.splitn(2, '=');
+ match (key_val.next(), key_val.next()) {
+ (Some(key), Some(value)) => {
+ command.env(key, value.replace("${pwd}", &exec_root.to_string_lossy()));
+ }
+ _ => {
+ return Err(
+ "error: Wrong environment file format, should not happen".to_owned()
+ )
+ }
+ }
+ }
+ } else {
+ return Err("error: Dependency environment file unreadable".to_owned());
+ }
+ }
+
+ 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);
+ }
+ }
+
+ if let Some(ar_path) = env::var_os("AR") {
+ // The default OSX toolchain uses libtool as ar_executable not ar.
+ // This doesn't work when used as $AR, so simply don't set it - tools will probably fall back to
+ // /usr/bin/ar which is probably good enough.
+ if Path::new(&ar_path).file_name() == Some("libtool".as_ref()) {
+ command.env_remove("AR");
+ } else {
+ command.env("AR", exec_root.join(ar_path));
+ }
+ }
+
+ 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");
+ if value.contains("${pwd}") {
+ env::set_var(key, value.replace("${pwd}", exec_root_str));
+ }
+ }
+
+ // Bazel does not support byte strings so in order to correctly represent `CARGO_ENCODED_RUSTFLAGS`
+ // the escaped `\x1f` sequences need to be unescaped
+ if let Ok(encoded_rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
+ command.env(
+ "CARGO_ENCODED_RUSTFLAGS",
+ encoded_rustflags.replace("\\x1f", "\x1f"),
+ );
+ }
+
+ let (buildrs_outputs, process_output) = BuildScriptOutput::outputs_from_command(&mut command)
+ .map_err(|process_output| {
+ format!(
+ "Build script process failed{}\n--stdout:\n{}\n--stderr:\n{}",
+ if let Some(exit_code) = process_output.status.code() {
+ format!(" with exit code {}", exit_code)
+ } else {
+ String::new()
+ },
+ String::from_utf8(process_output.stdout)
+ .expect("Failed to parse stdout of child process"),
+ String::from_utf8(process_output.stderr)
+ .expect("Failed to parse stdout of child process"),
+ )
+ })?;
+
+ write(
+ &env_file,
+ BuildScriptOutput::outputs_to_env(&buildrs_outputs, &exec_root.to_string_lossy())
+ .as_bytes(),
+ )
+ .unwrap_or_else(|_| panic!("Unable to write file {:?}", env_file));
+ write(
+ &output_dep_env_path,
+ BuildScriptOutput::outputs_to_dep_env(
+ &buildrs_outputs,
+ &crate_links,
+ &exec_root.to_string_lossy(),
+ )
+ .as_bytes(),
+ )
+ .unwrap_or_else(|_| panic!("Unable to write file {:?}", output_dep_env_path));
+ write(&stdout_path, process_output.stdout)
+ .unwrap_or_else(|_| panic!("Unable to write file {:?}", stdout_path));
+ write(&stderr_path, process_output.stderr)
+ .unwrap_or_else(|_| panic!("Unable to write file {:?}", stderr_path));
+
+ let CompileAndLinkFlags {
+ compile_flags,
+ link_flags,
+ link_search_paths,
+ } = BuildScriptOutput::outputs_to_flags(&buildrs_outputs, &exec_root.to_string_lossy());
+
+ write(&compile_flags_file, compile_flags.as_bytes())
+ .unwrap_or_else(|_| panic!("Unable to write file {:?}", compile_flags_file));
+ write(&link_flags_file, link_flags.as_bytes())
+ .unwrap_or_else(|_| panic!("Unable to write file {:?}", link_flags_file));
+ write(&link_search_paths_file, link_search_paths.as_bytes())
+ .unwrap_or_else(|_| panic!("Unable to write file {:?}", link_search_paths_file));
+ Ok(())
+}
+
+/// A representation of expected command line arguments.
+struct Options {
+ progname: String,
+ crate_links: String,
+ out_dir: String,
+ env_file: String,
+ compile_flags_file: String,
+ link_flags_file: String,
+ link_search_paths_file: String,
+ output_dep_env_path: String,
+ stdout_path: String,
+ stderr_path: String,
+ input_dep_env_paths: Vec<String>,
+}
+
+/// Parses positional comamnd line arguments into a well defined struct
+fn parse_args() -> Result<Options, String> {
+ let mut args = env::args().skip(1);
+
+ // TODO: we should consider an alternative to positional arguments.
+ match (args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next()) {
+ (
+ Some(progname),
+ Some(crate_links),
+ Some(out_dir),
+ Some(env_file),
+ Some(compile_flags_file),
+ Some(link_flags_file),
+ Some(link_search_paths_file),
+ Some(output_dep_env_path),
+ Some(stdout_path),
+ Some(stderr_path),
+ ) => {
+ Ok(Options{
+ progname,
+ crate_links,
+ out_dir,
+ env_file,
+ compile_flags_file,
+ link_flags_file,
+ link_search_paths_file,
+ output_dep_env_path,
+ stdout_path,
+ stderr_path,
+ input_dep_env_paths: args.collect(),
+ })
+ }
+ _ => {
+ Err(format!("Usage: $0 progname crate_links out_dir env_file compile_flags_file link_flags_file link_search_paths_file output_dep_env_path stdout_path stderr_path input_dep_env_paths[arg1...argn]\nArguments passed: {:?}", args.collect::<Vec<String>>()))
+ }
+ }
+}
+
+fn get_target_env_vars<P: AsRef<Path>>(rustc: &P) -> Result<BTreeMap<String, String>, String> {
+ // As done by Cargo when constructing a cargo::core::compiler::build_context::target_info::TargetInfo.
+ let output = Command::new(rustc.as_ref())
+ .arg("--print=cfg")
+ .arg(format!(
+ "--target={}",
+ env::var("TARGET").expect("missing TARGET")
+ ))
+ .output()
+ .map_err(|err| format!("Error running rustc to get target information: {}", err))?;
+ if !output.status.success() {
+ return Err(format!(
+ "Error running rustc to get target information: {:?}",
+ output
+ ));
+ }
+ let stdout = std::str::from_utf8(&output.stdout)
+ .map_err(|err| format!("Non-UTF8 stdout from rustc: {:?}", err))?;
+
+ Ok(parse_rustc_cfg_output(stdout))
+}
+
+fn parse_rustc_cfg_output(stdout: &str) -> BTreeMap<String, String> {
+ let mut values = BTreeMap::new();
+
+ for line in stdout.lines() {
+ if line.starts_with("target_") && line.contains('=') {
+ let mut parts = line.splitn(2, '=');
+ // UNWRAP: Verified that line contains = and split into exactly 2 parts.
+ let key = parts.next().unwrap();
+ let value = parts.next().unwrap();
+ if value.starts_with('"') && value.ends_with('"') && value.len() >= 2 {
+ values
+ .entry(key)
+ .or_insert_with(Vec::new)
+ .push(value[1..(value.len() - 1)].to_owned());
+ }
+ } else if ["windows", "unix"].contains(&line) {
+ // the 'windows' or 'unix' line received from rustc will be turned
+ // into eg. CARGO_CFG_WINDOWS='' below
+ values.insert(line, vec![]);
+ }
+ }
+
+ values
+ .into_iter()
+ .map(|(key, value)| (format!("CARGO_CFG_{}", key.to_uppercase()), value.join(",")))
+ .collect()
+}
+
+fn main() {
+ std::process::exit(match run_buildrs() {
+ Ok(_) => 0,
+ Err(err) => {
+ // Neatly print errors
+ eprintln!("{}", err);
+ 1
+ }
+ });
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn rustc_cfg_parsing() {
+ let macos_output = r#"\
+debug_assertions
+target_arch="x86_64"
+target_endian="little"
+target_env=""
+target_family="unix"
+target_feature="fxsr"
+target_feature="sse"
+target_feature="sse2"
+target_feature="sse3"
+target_feature="ssse3"
+target_os="macos"
+target_pointer_width="64"
+target_vendor="apple"
+unix
+"#;
+ let tree = parse_rustc_cfg_output(macos_output);
+ assert_eq!(tree["CARGO_CFG_UNIX"], "");
+ assert_eq!(tree["CARGO_CFG_TARGET_FAMILY"], "unix");
+
+ let windows_output = r#"\
+debug_assertions
+target_arch="x86_64"
+target_endian="little"
+target_env="msvc"
+target_family="windows"
+target_feature="fxsr"
+target_feature="sse"
+target_feature="sse2"
+target_os="windows"
+target_pointer_width="64"
+target_vendor="pc"
+windows
+"#;
+ let tree = parse_rustc_cfg_output(windows_output);
+ assert_eq!(tree["CARGO_CFG_WINDOWS"], "");
+ assert_eq!(tree["CARGO_CFG_TARGET_FAMILY"], "windows");
+ }
+}
diff --git a/cargo/cargo_build_script_runner/lib.rs b/cargo/cargo_build_script_runner/lib.rs
new file mode 100644
index 0000000..b1aa793
--- /dev/null
+++ b/cargo/cargo_build_script_runner/lib.rs
@@ -0,0 +1,291 @@
+// 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, Output};
+
+#[derive(Debug, PartialEq, Eq)]
+pub struct CompileAndLinkFlags {
+ pub compile_flags: String,
+ pub link_flags: String,
+ pub link_search_paths: String,
+}
+
+/// 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-link-arg
+ LinkArg(String),
+ /// cargo:rustc-env
+ Env(String),
+ /// cargo:VAR=VALUE
+ DepEnv(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 {
+ // Not a cargo directive.
+ return None;
+ }
+ let param = split[1].trim().to_owned();
+ let key_split = split[0].splitn(2, ':').collect::<Vec<_>>();
+ if key_split.len() <= 1 || key_split[0] != "cargo" {
+ // Not a cargo directive.
+ return None;
+ }
+
+ match key_split[1] {
+ "rustc-link-lib" => Some(BuildScriptOutput::LinkLib(param)),
+ "rustc-link-search" => Some(BuildScriptOutput::LinkSearch(param)),
+ "rustc-cfg" => Some(BuildScriptOutput::Cfg(param)),
+ "rustc-flags" => Some(BuildScriptOutput::Flags(param)),
+ "rustc-link-arg" => Some(BuildScriptOutput::LinkArg(param)),
+ "rustc-env" => Some(BuildScriptOutput::Env(param)),
+ "rerun-if-changed" | "rerun-if-env-changed" =>
+ // Ignored because Bazel will re-run if those change all the time.
+ {
+ None
+ }
+ "warning" => {
+ eprint!("Build Script Warning: {}", split[1]);
+ None
+ }
+ "rustc-cdylib-link-arg" | "rustc-link-arg-bin" | "rustc-link-arg-bins" => {
+ // cargo:rustc-cdylib-link-arg=FLAG — Passes custom flags to a linker for cdylib crates.
+ // cargo:rustc-link-arg-bin=BIN=FLAG – Passes custom flags to a linker for the binary BIN.
+ // cargo:rustc-link-arg-bins=FLAG – Passes custom flags to a linker for binaries.
+ eprint!(
+ "Warning: build script returned unsupported directive `{}`",
+ split[0]
+ );
+ None
+ }
+ _ => {
+ // cargo:KEY=VALUE — Metadata, used by links scripts.
+ Some(BuildScriptOutput::DepEnv(format!(
+ "{}={}",
+ key_split[1].to_uppercase(),
+ param
+ )))
+ }
+ }
+ }
+
+ /// Converts a [BufReader] into a vector of [BuildScriptOutput] enums.
+ fn outputs_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 outputs_from_command(
+ cmd: &mut Command,
+ ) -> Result<(Vec<BuildScriptOutput>, Output), Output> {
+ let child_output = cmd.output().expect("Unable to start binary");
+ if child_output.status.success() {
+ let reader = BufReader::new(child_output.stdout.as_slice());
+ let output = Self::outputs_from_reader(reader);
+ Ok((output, child_output))
+ } else {
+ Err(child_output)
+ }
+ }
+
+ /// Convert a vector of [BuildScriptOutput] into a list of environment variables.
+ pub fn outputs_to_env(outputs: &[BuildScriptOutput], exec_root: &str) -> String {
+ outputs
+ .iter()
+ .filter_map(|x| {
+ if let BuildScriptOutput::Env(env) = x {
+ Some(Self::escape_for_serializing(Self::redact_exec_root(
+ env, exec_root,
+ )))
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>()
+ .join("\n")
+ }
+
+ /// Convert a vector of [BuildScriptOutput] into a list of dependencies environment variables.
+ pub fn outputs_to_dep_env(
+ outputs: &[BuildScriptOutput],
+ crate_links: &str,
+ exec_root: &str,
+ ) -> String {
+ let prefix = format!("DEP_{}_", crate_links.replace('-', "_").to_uppercase());
+ outputs
+ .iter()
+ .filter_map(|x| {
+ if let BuildScriptOutput::DepEnv(env) = x {
+ Some(format!(
+ "{}{}",
+ prefix,
+ Self::escape_for_serializing(Self::redact_exec_root(env, exec_root))
+ ))
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>()
+ .join("\n")
+ }
+
+ /// Convert a vector of [BuildScriptOutput] into a flagfile.
+ pub fn outputs_to_flags(outputs: &[BuildScriptOutput], exec_root: &str) -> CompileAndLinkFlags {
+ let mut compile_flags = Vec::new();
+ let mut link_flags = Vec::new();
+ let mut link_search_paths = Vec::new();
+
+ for flag in outputs {
+ match flag {
+ BuildScriptOutput::Cfg(e) => compile_flags.push(format!("--cfg={}", e)),
+ BuildScriptOutput::Flags(e) => compile_flags.push(e.to_owned()),
+ BuildScriptOutput::LinkArg(e) => compile_flags.push(format!("-Clink-arg={}", e)),
+ BuildScriptOutput::LinkLib(e) => link_flags.push(format!("-l{}", e)),
+ BuildScriptOutput::LinkSearch(e) => link_search_paths.push(format!("-L{}", e)),
+ _ => {}
+ }
+ }
+
+ CompileAndLinkFlags {
+ compile_flags: compile_flags.join("\n"),
+ link_flags: Self::redact_exec_root(&link_flags.join("\n"), exec_root),
+ link_search_paths: Self::redact_exec_root(&link_search_paths.join("\n"), exec_root),
+ }
+ }
+
+ fn redact_exec_root(value: &str, exec_root: &str) -> String {
+ value.replace(exec_root, "${pwd}")
+ }
+
+ // The process-wrapper treats trailing backslashes as escapes for following newlines.
+ // If the env var ends with a backslash (and accordingly doesn't have a following newline),
+ // escape it so that it doesn't get turned into a newline by the process-wrapper.
+ //
+ // Note that this code doesn't handle newlines in strings - that's because Cargo treats build
+ // script output as single-line-oriented, so stops processing at the end of a line regardless.
+ fn escape_for_serializing(mut value: String) -> String {
+ if value.ends_with('\\') {
+ value.push('\\');
+ }
+ value
+ }
+}
+
+#[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=/some/absolute/path/bleh
+cargo:rustc-env=BAR=FOO
+cargo:rustc-flags=-Lblah
+cargo:rerun-if-changed=ignored
+cargo:rustc-cfg=feature=awesome
+cargo:version=123
+cargo:version_number=1010107f
+cargo:include_path=/some/absolute/path/include
+cargo:rustc-env=SOME_PATH=/some/absolute/path/beep
+cargo:rustc-link-arg=-weak_framework
+cargo:rustc-link-arg=Metal
+",
+ );
+ let reader = BufReader::new(buff);
+ let result = BuildScriptOutput::outputs_from_reader(reader);
+ assert_eq!(result.len(), 12);
+ 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("/some/absolute/path/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!(
+ result[6],
+ BuildScriptOutput::DepEnv("VERSION=123".to_owned())
+ );
+ assert_eq!(
+ result[7],
+ BuildScriptOutput::DepEnv("VERSION_NUMBER=1010107f".to_owned())
+ );
+ assert_eq!(
+ result[9],
+ BuildScriptOutput::Env("SOME_PATH=/some/absolute/path/beep".to_owned())
+ );
+ assert_eq!(
+ result[10],
+ BuildScriptOutput::LinkArg("-weak_framework".to_owned())
+ );
+ assert_eq!(result[11], BuildScriptOutput::LinkArg("Metal".to_owned()));
+
+ assert_eq!(
+ BuildScriptOutput::outputs_to_dep_env(&result, "ssh2", "/some/absolute/path"),
+ "DEP_SSH2_VERSION=123\nDEP_SSH2_VERSION_NUMBER=1010107f\nDEP_SSH2_INCLUDE_PATH=${pwd}/include".to_owned()
+ );
+ assert_eq!(
+ BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path"),
+ "FOO=BAR\nBAR=FOO\nSOME_PATH=${pwd}/beep".to_owned()
+ );
+ assert_eq!(
+ BuildScriptOutput::outputs_to_flags(&result, "/some/absolute/path"),
+ CompileAndLinkFlags {
+ // -Lblah was output as a rustc-flags, so even though it probably _should_ be a link
+ // flag, we don't treat it like one.
+ compile_flags:
+ "-Lblah\n--cfg=feature=awesome\n-Clink-arg=-weak_framework\n-Clink-arg=Metal"
+ .to_owned(),
+ link_flags: "-lsdfsdf".to_owned(),
+ link_search_paths: "-L${pwd}/bleh".to_owned(),
+ }
+ );
+ }
+}