Skip to content

Commit dc27718

Browse files
committed
fix LTO archive linking
1 parent 55442bb commit dc27718

9 files changed

Lines changed: 114 additions & 25 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ on:
99

1010
jobs:
1111
typst:
12-
name: Typst documents (Ubuntu)
12+
name: Typst documents (${{ matrix.profile }}, Ubuntu)
1313
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
profile: [debug, release]
1418
timeout-minutes: 45
1519
permissions:
1620
contents: read
@@ -71,13 +75,13 @@ jobs:
7175
run: python build.py ci
7276

7377
- name: Compile and render Typst documents
74-
run: python tests/typst/run.py
78+
run: python tests/typst/run.py ${{ matrix.profile == 'release' && '--release' || '' }}
7579

7680
- name: Upload Typst output and diagnostics
7781
if: always()
7882
uses: actions/upload-artifact@v4
7983
with:
80-
name: typst-documents
84+
name: typst-documents-${{ matrix.profile }}
8185
path: target/typst/reports/
8286
if-no-files-found: warn
8387

‎src/archive.rs‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//! Keep JVM payloads when rustc filters native objects out of LTO dependencies.
2+
use rustc_codegen_ssa::back::archive::{
3+
AddArchiveKind, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, ArchiveEntryKind,
4+
ArchiveSymbols, DEFAULT_OBJECT_READER, ImportLibraryItem,
5+
};
6+
use rustc_session::Session;
7+
use std::{io, path::Path};
8+
9+
pub(super) struct RlibArchiveBuilder;
10+
11+
impl ArchiveBuilderBuilder for RlibArchiveBuilder {
12+
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
13+
Box::new(JvmArchiveBuilder(ArArchiveBuilder::new(
14+
sess,
15+
&DEFAULT_OBJECT_READER,
16+
)))
17+
}
18+
19+
fn create_dll_import_lib(
20+
&self,
21+
_sess: &Session,
22+
_lib_name: &str,
23+
_dll_imports: Vec<ImportLibraryItem>,
24+
_tmpdir: &Path,
25+
) {
26+
unimplemented!("creating dll imports is not supported");
27+
}
28+
}
29+
30+
struct JvmArchiveBuilder<'a>(ArArchiveBuilder<'a>);
31+
32+
impl ArchiveBuilder for JvmArchiveBuilder<'_> {
33+
fn add_file(&mut self, path: &Path, kind: ArchiveEntryKind) {
34+
self.0.add_file(path, kind);
35+
}
36+
37+
fn add_archive(&mut self, path: &Path, kind: AddArchiveKind<'_>) -> io::Result<()> {
38+
match kind {
39+
AddArchiveKind::Rlib(cache, skip) => {
40+
// Native LTO has already consumed upstream Rust objects. JVM
41+
// bundles are instead merged by java-linker and must reach it,
42+
// even when the Cargo profile requests thin or fat LTO.
43+
let skip = |name: &str, kind| {
44+
let jvm_payload = name.ends_with(".jvmbundle") || name.ends_with(".jvmsymbols");
45+
!jvm_payload && skip(name, kind)
46+
};
47+
self.0.add_archive(path, AddArchiveKind::Rlib(cache, &skip))
48+
}
49+
AddArchiveKind::Other => self.0.add_archive(path, kind),
50+
}
51+
}
52+
53+
fn build(self: Box<Self>, output: &Path, symbols: Option<ArchiveSymbols>) -> bool {
54+
Box::new(self.0).build(output, symbols)
55+
}
56+
}

‎src/lib.rs‎

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ macro_rules! log {
5959

6060
use crate::lower1::context::Definitions;
6161
use oomir::Type;
62-
use rustc_codegen_ssa::back::archive::{ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder};
6362
use rustc_codegen_ssa::{
6463
CompiledModule, CompiledModules, CrateInfo, ModuleKind, traits::CodegenBackend,
6564
};
@@ -125,6 +124,8 @@ fn combine_class_bundles(path: &Path, bundles: &[(String, PathBuf)]) -> std::io:
125124

126125
mod allocator_shims;
127126
use allocator_shims::emit_allocator_shims;
127+
mod archive;
128+
use archive::RlibArchiveBuilder;
128129

129130
fn lower_mono_function<'tcx>(
130131
tcx: TyCtxt<'tcx>,
@@ -667,22 +668,3 @@ use std::alloc::Layout;
667668
pub fn custom_alloc_error_hook(layout: Layout) {
668669
panic!("Memory allocation failed: {} bytes", layout.size());
669670
}
670-
671-
struct RlibArchiveBuilder;
672-
impl ArchiveBuilderBuilder for RlibArchiveBuilder {
673-
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
674-
Box::new(ArArchiveBuilder::new(
675-
sess,
676-
&rustc_codegen_ssa::back::archive::DEFAULT_OBJECT_READER,
677-
))
678-
}
679-
fn create_dll_import_lib(
680-
&self,
681-
_sess: &Session,
682-
_lib_name: &str,
683-
_dll_imports: std::vec::Vec<rustc_codegen_ssa::back::archive::ImportLibraryItem>,
684-
_tmpdir: &Path,
685-
) {
686-
unimplemented!("creating dll imports is not supported");
687-
}
688-
}

‎tests/multicrate/lto/Cargo.lock‎

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

‎tests/multicrate/lto/Cargo.toml‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "lto"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
lto_provider = { path = "provider" }
8+
9+
# Exercise both modes: dependency class bundles must survive either LTO flag.
10+
[profile.dev]
11+
lto = "thin"
12+
13+
[profile.release]
14+
lto = "fat"
15+
codegen-units = 1
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[package]
2+
name = "lto_provider"
3+
version = "0.1.0"
4+
edition = "2024"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#[inline(never)]
2+
pub fn answer() -> u32 {
3+
std::hint::black_box(42)
4+
}

‎tests/multicrate/lto/src/main.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
// Neither the dependency body nor std::env is defined in this crate.
3+
assert_eq!(lto_provider::answer(), 42);
4+
assert!(!std::env::args().next().unwrap().is_empty());
5+
}

‎tests/typst/run.py‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def main() -> int:
8383
parser.add_argument("--target-dir", type=Path, default=ROOT / "target/typst/build")
8484
parser.add_argument("--reports", type=Path, default=ROOT / "target/typst/reports")
8585
parser.add_argument("--timeout", type=float, default=180)
86+
parser.add_argument("--release", action="store_true", help="Build with Cargo's release profile")
8687
parser.add_argument("--case", action="append", choices=CASES, dest="cases")
8788
args = parser.parse_args()
8889
if args.timeout <= 0:
@@ -97,7 +98,8 @@ def main() -> int:
9798
parser.error(f"missing Typst reporter checkout: {source}")
9899
# Cargo does not track changes to the backend library or bundled runtime.
99100
# Rebuild JVM artifacts each time, retaining compiled host build tools.
100-
jvm_target = target / TARGET_SPEC.stem
101+
profile = "release" if args.release else "debug"
102+
jvm_target = target / TARGET_SPEC.stem / profile
101103
if jvm_target.exists():
102104
shutil.rmtree(jvm_target)
103105
reports.mkdir(parents=True, exist_ok=True)
@@ -120,13 +122,16 @@ def main() -> int:
120122
"-Zjson-target-spec", "-Zbuild-std=std,panic_unwind",
121123
"-Zbuild-std-features=panic-unwind", "--target-dir", str(target), "-j2",
122124
]
125+
if args.release:
126+
command.append("--release")
123127
revision = subprocess.check_output(
124128
["git", "rev-parse", "HEAD"], cwd=source, text=True
125129
).strip()
126130
report = {
127131
"passed": False,
128132
"source_revision": revision,
129133
"toolchain": toolchain,
134+
"profile": profile,
130135
"build_command": command,
131136
}
132137
original = entry.read_bytes()
@@ -147,7 +152,7 @@ def main() -> int:
147152
print((reports / "build.stderr.log").read_text(), file=sys.stderr)
148153
return 1
149154

150-
jar = target / "jvm-unknown-jvm/debug/typst-shared.jar"
155+
jar = jvm_target / "typst-shared.jar"
151156
report["documents"] = {
152157
case: run_document(jar, case, reports, args.timeout)
153158
for case in args.cases or CASES

0 commit comments

Comments
 (0)