Skip to content

Commit bbaf511

Browse files
David Tolnayfacebook-github-bot
David Tolnay
authored andcommitted
Synthesize build scripts that Cargo failed to vendor
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
1 parent 43c8308 commit bbaf511

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ license = "MIT"
1111
[dependencies]
1212
anyhow = "1.0.75"
1313
cached = "0.39.0"
14+
cargo_toml = "0.17.2"
1415
clap = { version = "4.5.11", features = ["derive", "env", "string", "unicode", "wrap_help"] }
1516
dunce = "1.0.2"
1617
env_logger = "0.10"

src/vendor.rs

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::io::ErrorKind;
1010
use std::path::Path;
1111

1212
use anyhow::Context;
13+
use cargo_toml::OptionalFile;
1314
use globset::GlobBuilder;
1415
use globset::GlobSetBuilder;
1516
use ignore::gitignore::GitignoreBuilder;
@@ -70,6 +71,7 @@ pub(crate) fn cargo_vendor(
7071

7172
if let Some(vendor_config) = &config.vendor {
7273
filter_checksum_files(&paths.third_party_dir, vendordir, vendor_config)?;
74+
write_excluded_build_scripts(&paths.third_party_dir, vendordir)?;
7375
}
7476

7577
if audit_sec {
@@ -158,8 +160,8 @@ fn filter_checksum_files(
158160

159161
for entry in fs::read_dir(third_party_dir.join(vendordir))? {
160162
let entry = entry?;
161-
let path = entry.path(); // full/path/to/vendor/foo-1.2.3
162-
let checksum = path.join(".cargo-checksum.json"); // full/path/to/vendor/foo-1.2.3/.cargo-checksum.json
163+
let manifest_dir = entry.path(); // full/path/to/vendor/foo-1.2.3
164+
let checksum = manifest_dir.join(".cargo-checksum.json"); // full/path/to/vendor/foo-1.2.3/.cargo-checksum.json
163165

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

@@ -181,7 +183,7 @@ fn filter_checksum_files(
181183

182184
let mut changed = false;
183185

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

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

205207
Ok(())
206208
}
209+
210+
// Work around https://github.com/rust-lang/cargo/issues/14348.
211+
//
212+
// This step can be deleted if that `cargo vendor` bug is fixed in a future
213+
// version of Cargo.
214+
fn write_excluded_build_scripts(third_party_dir: &Path, vendordir: &Path) -> anyhow::Result<()> {
215+
type TomlManifest = cargo_toml::Manifest<serde::de::IgnoredAny>;
216+
217+
let third_party_vendor = third_party_dir.join(vendordir);
218+
if !third_party_vendor.try_exists()? {
219+
// If there are no dependencies from a remote registry (because there
220+
// are no dependencies whatsoever, or all dependencies are local path
221+
// dependencies) then `cargo vendor` won't have created a "vendor"
222+
// directory.
223+
return Ok(());
224+
}
225+
226+
for entry in fs::read_dir(third_party_vendor)? {
227+
let entry = entry?;
228+
let manifest_dir = entry.path(); // full/path/to/vendor/foo-1.2.3
229+
let cargo_toml = manifest_dir.join("Cargo.toml");
230+
231+
log::trace!("Reading manifest {}", cargo_toml.display());
232+
233+
let content = match fs::read_to_string(&cargo_toml) {
234+
Ok(file) => file,
235+
Err(err) => {
236+
log::warn!("Failed to read {}: {}", cargo_toml.display(), err);
237+
continue;
238+
}
239+
};
240+
241+
let manifest: TomlManifest = match toml::from_str(&content) {
242+
Ok(cs) => cs,
243+
Err(err) => {
244+
log::warn!("Failed to deserialize {}: {}", cargo_toml.display(), err);
245+
continue;
246+
}
247+
};
248+
249+
let Some(package) = &manifest.package else {
250+
continue;
251+
};
252+
let Some(OptionalFile::Path(build_script_path)) = &package.build else {
253+
continue;
254+
};
255+
256+
let expected_build_script = manifest_dir.join(build_script_path);
257+
if !expected_build_script.try_exists()? {
258+
log::trace!(
259+
"Synthesizing build script {}",
260+
expected_build_script.display(),
261+
);
262+
fs::write(expected_build_script, "fn main() {}\n")?;
263+
}
264+
}
265+
266+
Ok(())
267+
}

0 commit comments

Comments
 (0)