Skip to content

Commit

Permalink
Synthesize build scripts that Cargo failed to vendor
Browse files Browse the repository at this point in the history
Summary:
This is a workaround for [rust-lang/cargo#14348](rust-lang/cargo#14348), which is a regression in Rust 1.80's `cargo vendor`.

4 crates in fbsource/third-party/rust are currently impacted:

- `cxx-build`
- `cxxbridge-cmd`
- `cxxbridge-macro`
- `orjson` (https://github.com/ijl/orjson)

The workaround works by writing a build.rs containing just `fn main() {}` for crates where Cargo has injected `build = "build.rs"` into their manifest without vendoring the corresponding build.rs.

We can delete this workaround once the Cargo bug is fixed.

Reviewed By: diliop

Differential Revision: D60855541

fbshipit-source-id: 553c3e45e8f0998fb3091b1f1a82f33b2d7c0a6f
  • Loading branch information
David Tolnay authored and facebook-github-bot committed Aug 6, 2024
1 parent 43c8308 commit bbaf511
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ license = "MIT"
[dependencies]
anyhow = "1.0.75"
cached = "0.39.0"
cargo_toml = "0.17.2"
clap = { version = "4.5.11", features = ["derive", "env", "string", "unicode", "wrap_help"] }
dunce = "1.0.2"
env_logger = "0.10"
Expand Down
67 changes: 64 additions & 3 deletions src/vendor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::io::ErrorKind;
use std::path::Path;

use anyhow::Context;
use cargo_toml::OptionalFile;
use globset::GlobBuilder;
use globset::GlobSetBuilder;
use ignore::gitignore::GitignoreBuilder;
Expand Down Expand Up @@ -70,6 +71,7 @@ pub(crate) fn cargo_vendor(

if let Some(vendor_config) = &config.vendor {
filter_checksum_files(&paths.third_party_dir, vendordir, vendor_config)?;
write_excluded_build_scripts(&paths.third_party_dir, vendordir)?;
}

if audit_sec {
Expand Down Expand Up @@ -158,8 +160,8 @@ fn filter_checksum_files(

for entry in fs::read_dir(third_party_dir.join(vendordir))? {
let entry = entry?;
let path = entry.path(); // full/path/to/vendor/foo-1.2.3
let checksum = path.join(".cargo-checksum.json"); // full/path/to/vendor/foo-1.2.3/.cargo-checksum.json
let manifest_dir = entry.path(); // full/path/to/vendor/foo-1.2.3
let checksum = manifest_dir.join(".cargo-checksum.json"); // full/path/to/vendor/foo-1.2.3/.cargo-checksum.json

log::trace!("Reading checksum {}", checksum.display());

Expand All @@ -181,7 +183,7 @@ fn filter_checksum_files(

let mut changed = false;

let pkgdir = relative_path(third_party_dir, &path); // vendor/foo-1.2.3
let pkgdir = relative_path(third_party_dir, &manifest_dir); // vendor/foo-1.2.3

checksums.files.retain(|k, _| {
log::trace!("{}: checking {}", checksum.display(), k);
Expand All @@ -204,3 +206,62 @@ fn filter_checksum_files(

Ok(())
}

// Work around https://github.com/rust-lang/cargo/issues/14348.
//
// This step can be deleted if that `cargo vendor` bug is fixed in a future
// version of Cargo.
fn write_excluded_build_scripts(third_party_dir: &Path, vendordir: &Path) -> anyhow::Result<()> {
type TomlManifest = cargo_toml::Manifest<serde::de::IgnoredAny>;

let third_party_vendor = third_party_dir.join(vendordir);
if !third_party_vendor.try_exists()? {
// If there are no dependencies from a remote registry (because there
// are no dependencies whatsoever, or all dependencies are local path
// dependencies) then `cargo vendor` won't have created a "vendor"
// directory.
return Ok(());
}

for entry in fs::read_dir(third_party_vendor)? {
let entry = entry?;
let manifest_dir = entry.path(); // full/path/to/vendor/foo-1.2.3
let cargo_toml = manifest_dir.join("Cargo.toml");

log::trace!("Reading manifest {}", cargo_toml.display());

let content = match fs::read_to_string(&cargo_toml) {
Ok(file) => file,
Err(err) => {
log::warn!("Failed to read {}: {}", cargo_toml.display(), err);
continue;
}
};

let manifest: TomlManifest = match toml::from_str(&content) {
Ok(cs) => cs,
Err(err) => {
log::warn!("Failed to deserialize {}: {}", cargo_toml.display(), err);
continue;
}
};

let Some(package) = &manifest.package else {
continue;
};
let Some(OptionalFile::Path(build_script_path)) = &package.build else {
continue;
};

let expected_build_script = manifest_dir.join(build_script_path);
if !expected_build_script.try_exists()? {
log::trace!(
"Synthesizing build script {}",
expected_build_script.display(),
);
fs::write(expected_build_script, "fn main() {}\n")?;
}
}

Ok(())
}

0 comments on commit bbaf511

Please sign in to comment.