Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions cargo/private/cargo_build_script_runner/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,25 @@ fn run_buildrs() -> Result<(), String> {

for dep_env_path in input_dep_env_paths.iter() {
if let Ok(contents) = read_to_string(dep_env_path) {
// Handle line continuations: lines ending with '\' continue on the next line
let mut current_line = String::new();
for line in contents.split('\n') {
// split on empty contents will still produce a single empty string in iterable.
if line.is_empty() {
// Skip empty lines when we're not in a continuation
if line.is_empty() && current_line.is_empty() {
continue;
}
match line.split_once('=') {

if let Some(prefix) = line.strip_suffix('\\') {
// Line continues on the next line
current_line.push_str(prefix);
current_line.push('\n');
continue;
}

// Complete line (either standalone or end of continuation)
current_line.push_str(line);

match current_line.split_once('=') {
Some((key, value)) => {
command.env(key, value.replace("${pwd}", &exec_root.to_string_lossy()));
}
Expand All @@ -115,6 +128,7 @@ fn run_buildrs() -> Result<(), String> {
)
}
}
current_line.clear();
}
} else {
return Err("error: Dependency environment file unreadable".to_owned());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
load("//cargo:defs.bzl", "cargo_build_script", "cargo_toml_env_vars")
load("//rust:defs.bzl", "rust_library", "rust_test")

# Test that cargo_toml_env_vars works with build_script_env_files to provide
# CARGO_PKG_* variables to build scripts at runtime. This is the fix for
# crates like rav1e whose build scripts (via the `built` crate) read
# CARGO_PKG_AUTHORS at runtime with std::env::var().

cargo_toml_env_vars(
name = "cargo_toml_env_vars",
src = "Cargo.toml",
)

cargo_build_script(
name = "cargo_build_script",
srcs = ["build.rs"],
build_script_env_files = [":cargo_toml_env_vars"],
edition = "2021",
)

rust_library(
name = "test_lib",
srcs = ["test_lib.rs"],
edition = "2021",
deps = [":cargo_build_script"],
)

rust_test(
name = "consume_build_script",
crate = ":test_lib",
size = "small",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "test_cargo_toml_env"
version = "1.2.3"
authors = ["Test Author <test@example.com>", "Another Author"]
description = """
This is a multiline description
that spans multiple lines.
"""
edition = "2021"
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! Build script that reads CARGO_PKG_* env vars at runtime.
//! This tests that cargo_toml_env_vars + build_script_env_files correctly
//! provides these variables to build scripts, which is needed for crates
//! like rav1e that use the `built` crate.

fn main() {
// Read env vars that should be set from cargo_toml_env_vars via build_script_env_files
let authors = std::env::var("CARGO_PKG_AUTHORS")
.expect("CARGO_PKG_AUTHORS should be set from Cargo.toml");
let version = std::env::var("CARGO_PKG_VERSION")
.expect("CARGO_PKG_VERSION should be set from Cargo.toml");
let name =
std::env::var("CARGO_PKG_NAME").expect("CARGO_PKG_NAME should be set from Cargo.toml");
let description = std::env::var("CARGO_PKG_DESCRIPTION")
.expect("CARGO_PKG_DESCRIPTION should be set from Cargo.toml");

// Pass them to rustc so the test can verify them
println!("cargo:rustc-env=TEST_AUTHORS={}", authors);
println!("cargo:rustc-env=TEST_VERSION={}", version);
println!("cargo:rustc-env=TEST_NAME={}", name);
// Escape newlines for cargo:rustc-env
println!(
"cargo:rustc-env=TEST_DESCRIPTION={}",
description.replace('\n', "\\n")
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! Tests that CARGO_PKG_* env vars from Cargo.toml are available to build.rs
//! at runtime via build_script_env_files.

#[test]
fn check_authors_from_cargo_toml() {
// Authors should be colon-separated as Cargo does
let authors = env!("TEST_AUTHORS");
assert!(
authors.contains("Test Author"),
"Expected 'Test Author' in authors, got: {}",
authors
);
assert!(
authors.contains("Another Author"),
"Expected 'Another Author' in authors, got: {}",
authors
);
}

#[test]
fn check_version_from_cargo_toml() {
assert_eq!("1.2.3", env!("TEST_VERSION"));
}

#[test]
fn check_name_from_cargo_toml() {
assert_eq!("test_cargo_toml_env", env!("TEST_NAME"));
}

#[test]
fn check_description_from_cargo_toml() {
let desc = env!("TEST_DESCRIPTION");
// Description should contain the multiline content (with escaped newlines)
assert!(
desc.contains("multiline description"),
"Expected 'multiline description' in description, got: {}",
desc
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ rust_library(
rust_test(
name = "consume_build_script",
crate = ":test_lib",
size = "small",
)
66 changes: 66 additions & 0 deletions crate_universe/src/rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,12 @@ impl Renderer {
.unwrap_or_default(),
platforms,
),
build_script_env_files: SelectSet::new(
attrs
.map(|attrs| attrs.build_script_env_files.clone())
.unwrap_or_default(),
platforms,
),
rustc_flags: SelectList::new(
// In most cases, warnings in 3rd party crates are not
// interesting as they're out of the control of consumers. The
Expand Down Expand Up @@ -1335,6 +1341,66 @@ mod test {
assert!(build_file_content.contains("name = \"_bs\""));
}

#[test]
fn render_cargo_build_script_with_env_files() {
let mut context = Context::default();
let crate_id = CrateId::new("mock_crate".to_owned(), VERSION_ZERO_ONE_ZERO);

let attrs = BuildScriptAttributes {
build_script_env_files: Select::from_value(BTreeSet::from(["env_file.txt".to_owned()])),
..BuildScriptAttributes::default()
};

context.crates.insert(
crate_id.clone(),
CrateContext {
name: crate_id.name,
version: crate_id.version,
package_url: None,
repository: None,
targets: BTreeSet::from([Rule::BuildScript(TargetAttributes {
crate_name: "build_script_build".to_owned(),
crate_root: Some("build.rs".to_owned()),
..TargetAttributes::default()
})]),
library_target_name: None,
common_attrs: CommonAttributes::default(),
build_script_attrs: Some(attrs),
license: None,
license_ids: BTreeSet::default(),
license_file: None,
additive_build_file_content: None,
disable_pipelining: false,
extra_aliased_targets: BTreeMap::default(),
alias_rule: None,
override_targets: BTreeMap::default(),
},
);

let renderer = Renderer::new(mock_render_config(None), mock_supported_platform_triples());
let output = renderer.render(&context, None).unwrap();

let build_file_content = output
.get(&PathBuf::from("BUILD.mock_crate-0.1.0.bazel"))
.unwrap();

assert!(
build_file_content.contains("cargo_build_script("),
"Expected cargo_build_script in:\n{}",
build_file_content
);
assert!(
build_file_content.contains("build_script_env_files = ["),
"Expected build_script_env_files in:\n{}",
build_file_content
);
assert!(
build_file_content.contains("\"env_file.txt\""),
"Expected env_file.txt in build_script_env_files:\n{}",
build_file_content
);
}

#[test]
fn render_proc_macro() {
let mut context = Context::default();
Expand Down
2 changes: 2 additions & 0 deletions crate_universe/src/utils/starlark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ pub(crate) struct CargoBuildScript {
pub(crate) aliases: SelectDict<Label, String>,
#[serde(skip_serializing_if = "SelectDict::is_empty")]
pub(crate) build_script_env: SelectDict<String, String>,
#[serde(skip_serializing_if = "SelectSet::is_empty")]
pub(crate) build_script_env_files: SelectSet<String>,
#[serde(skip_serializing_if = "Data::is_empty")]
pub(crate) compile_data: Data,
#[serde(skip_serializing_if = "SelectDict::is_empty")]
Expand Down