Skip to content
Merged
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
9 changes: 8 additions & 1 deletion .github/workflows/release-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,12 @@ jobs:
# needs the prebuilt `libperry_ext_*.a` sitting next to
# libperry_runtime.a so `perry compile` can link them without a
# workspace checkout (see optimized_libs.rs::resolve_prebuilt_ext_libs).
# #7358: keep the compiler and both shipped wrapper archives in each
# Cargo invocation. Building an ext staticlib alone gives its bundled
# runtime/shared dependencies a different feature union from stdlib;
# the link deduper then cannot remove the whole second copy, and the
# HTTP accept loop reads a different async reactor from the one the JS
# event loop drives.
# Best-effort per crate: a wrapper that can't build on this host must
# not fail the whole release — the packaging glob below ships
# whatever was produced.
Expand All @@ -437,7 +443,8 @@ jobs:
[ -d "$d" ] || continue
name=$(basename "$d")
echo "::group::build $name"
cargo build --profile dist --target ${{ matrix.target }} -p "$name" \
cargo build --profile dist --target ${{ matrix.target }} \
-p perry -p perry-runtime-static -p perry-stdlib-static -p "$name" \
|| echo " (skipped $name — failed to build on this host)"
echo "::endgroup::"
done
Expand Down
8 changes: 8 additions & 0 deletions changelog.d/7952-ext-feature-union.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
### Fixed

- **Native extension archives in release packages now share the shipped
runtime and stdlib feature set (#7358).** Building each `perry-ext-*` crate
alone could leave a partial second runtime in standalone binaries, attaching
HTTP work to an async reactor the JavaScript event loop did not drive. Release
packaging now selects the compiler, both static wrapper crates, and each
extension in one Cargo invocation.
44 changes: 44 additions & 0 deletions crates/perry/src/commands/compile/well_known.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,50 @@ mod tests {
);
}

/// #7358 — the manifest features above are necessary but not sufficient:
/// Cargo resolves features over the package set selected by one command.
/// A release build of an ext staticlib alone can therefore bundle a
/// runtime/shared-dependency set that differs from the separately-built
/// stdlib archive. The link deduper cannot drop that whole second copy,
/// leaving HTTP attached to an async reactor the JS event loop never
/// drives. Keep the shipping workflow's package set paired with the
/// compiler and both static wrapper crates.
#[test]
fn release_ext_builds_share_the_shipped_runtime_feature_set() {
let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let workspace_root = manifest_dir
.parent()
.and_then(|p| p.parent())
.expect("workspace root reachable from CARGO_MANIFEST_DIR");
let workflow =
std::fs::read_to_string(workspace_root.join(".github/workflows/release-packages.yml"))
.expect("read release-packages workflow");
let step = workflow
.split("- name: Build native ext libraries (Unix)")
.nth(1)
.and_then(|tail| tail.split("- name: Build UI library (macOS)").next())
.expect("native ext release step remains present");
let command: String = step
.lines()
.skip_while(|line| !line.trim_start().starts_with("cargo build "))
.take_while(|line| !line.contains("|| echo"))
.collect::<Vec<_>>()
.join(" ");
let tokens: Vec<&str> = command.split_whitespace().collect();

for package in ["perry", "perry-runtime-static", "perry-stdlib-static"] {
assert!(
tokens.windows(2).any(|pair| pair == ["-p", package]),
"#7358: release ext build must select `{package}` in the same Cargo \
invocation so its bundled runtime matches the shipped archives; got:\n{command}"
);
}
assert!(
tokens.windows(2).any(|pair| pair == ["-p", "\"$name\""]),
"native ext release command stopped selecting the loop's crate: {command}"
);
}

#[test]
fn upstream_pin_parses() {
let raw = r#"
Expand Down
Loading