Skip to content

Commit 09c1476

Browse files
authored
Rollup merge of rust-lang#122597 - pacak:master, r=bjorn3
Show files produced by `--emit foo` in json artifact notifications Right now it is possible to ask `rustc` to save some intermediate representation into one or more files with `--emit=foo`, but figuring out what exactly was produced is difficult. This pull request adds information about `llvm_ir` and `asm` intermediate files into notifications produced by `--json=artifacts`. Related discussion: https://internals.rust-lang.org/t/easier-access-to-files-generated-by-emit-foo/20477 Motivation - `cargo-show-asm` parses those intermediate files and presents them in a user friendly way, but right now I have to apply some dirty hacks. Hacks make behavior confusing: hintron/computer-enhance#35 This pull request introduces a new behavior: now `rustc` will emit a new artifact notification for every artifact type user asked to `--emit`, for example for `--emit asm` those will include all the `.s` files. Most users won't notice this behavior, to be affected by it all of the following must hold: - user must use `rustc` binary directly (when `cargo` invokes `rustc` - it consumes artifact notifications and doesn't emit anything) - user must specify both `--emit xxx` and `--json artifacts` - user must refuse to handle unknown artifact types - user must disable incremental compilation (or deal with it better than cargo does, or use a workaround like `save-temps`) in order not to hit rust-lang#88829 / rust-lang#89149
2 parents 1d52972 + c8390cd commit 09c1476

File tree

7 files changed

+140
-1
lines changed

7 files changed

+140
-1
lines changed

compiler/rustc_codegen_cranelift/src/driver/aot.rs

+23
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,29 @@ fn produce_final_output_artifacts(
288288
}
289289
}
290290

291+
if sess.opts.json_artifact_notifications {
292+
if codegen_results.modules.len() == 1 {
293+
codegen_results.modules[0].for_each_output(|_path, ty| {
294+
if sess.opts.output_types.contains_key(&ty) {
295+
let descr = ty.shorthand();
296+
// for single cgu file is renamed to drop cgu specific suffix
297+
// so we regenerate it the same way
298+
let path = crate_output.path(ty);
299+
sess.dcx().emit_artifact_notification(path.as_path(), descr);
300+
}
301+
});
302+
} else {
303+
for module in &codegen_results.modules {
304+
module.for_each_output(|path, ty| {
305+
if sess.opts.output_types.contains_key(&ty) {
306+
let descr = ty.shorthand();
307+
sess.dcx().emit_artifact_notification(&path, descr);
308+
}
309+
});
310+
}
311+
}
312+
}
313+
291314
// We leave the following files around by default:
292315
// - #crate#.o
293316
// - #crate#.crate.metadata.o

compiler/rustc_codegen_ssa/src/back/write.rs

+23
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,29 @@ fn produce_final_output_artifacts(
717717
}
718718
}
719719

720+
if sess.opts.json_artifact_notifications {
721+
if compiled_modules.modules.len() == 1 {
722+
compiled_modules.modules[0].for_each_output(|_path, ty| {
723+
if sess.opts.output_types.contains_key(&ty) {
724+
let descr = ty.shorthand();
725+
// for single cgu file is renamed to drop cgu specific suffix
726+
// so we regenerate it the same way
727+
let path = crate_output.path(ty);
728+
sess.dcx().emit_artifact_notification(path.as_path(), descr);
729+
}
730+
});
731+
} else {
732+
for module in &compiled_modules.modules {
733+
module.for_each_output(|path, ty| {
734+
if sess.opts.output_types.contains_key(&ty) {
735+
let descr = ty.shorthand();
736+
sess.dcx().emit_artifact_notification(&path, descr);
737+
}
738+
});
739+
}
740+
}
741+
}
742+
720743
// We leave the following files around by default:
721744
// - #crate#.o
722745
// - #crate#.crate.metadata.o

compiler/rustc_codegen_ssa/src/lib.rs

+18
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,24 @@ pub struct CompiledModule {
106106
pub llvm_ir: Option<PathBuf>, // --emit=llvm-ir, llvm-bc is in bytecode
107107
}
108108

109+
impl CompiledModule {
110+
/// Call `emit` function with every artifact type currently compiled
111+
pub fn for_each_output(&self, mut emit: impl FnMut(&Path, OutputType)) {
112+
if let Some(path) = self.object.as_deref() {
113+
emit(path, OutputType::Object);
114+
}
115+
if let Some(path) = self.bytecode.as_deref() {
116+
emit(path, OutputType::Bitcode);
117+
}
118+
if let Some(path) = self.llvm_ir.as_deref() {
119+
emit(path, OutputType::LlvmAssembly);
120+
}
121+
if let Some(path) = self.assembly.as_deref() {
122+
emit(path, OutputType::Assembly);
123+
}
124+
}
125+
}
126+
109127
pub struct CachedModuleCodegen {
110128
pub name: String,
111129
pub source: WorkProduct,

compiler/rustc_mir_transform/src/dump_mir.rs

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
2828
OutFileName::Real(path) => {
2929
let mut f = io::BufWriter::new(File::create(&path)?);
3030
write_mir_pretty(tcx, None, &mut f)?;
31+
if tcx.sess.opts.json_artifact_notifications {
32+
tcx.dcx().emit_artifact_notification(&path, "mir");
33+
}
3134
}
3235
}
3336
Ok(())

src/doc/rustc/src/json.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ Diagnostics have the following format:
217217
Artifact notifications are emitted when the [`--json=artifacts`
218218
flag][option-json] is used. They indicate that a file artifact has been saved
219219
to disk. More information about emit kinds may be found in the [`--emit`
220-
flag][option-emit] documentation.
220+
flag][option-emit] documentation. Notifications can contain more than one file
221+
for each type, for example when using multiple codegen units.
221222

222223
```javascript
223224
{
@@ -229,6 +230,11 @@ flag][option-emit] documentation.
229230
- "link": The generated crate as specified by the crate-type.
230231
- "dep-info": The `.d` file with dependency information in a Makefile-like syntax.
231232
- "metadata": The Rust `.rmeta` file containing metadata about the crate.
233+
- "asm": The `.s` file with generated assembly
234+
- "llvm-ir": The `.ll` file with generated textual LLVM IR
235+
- "llvm-bc": The `.bc` file with generated LLVM bitcode
236+
- "mir": The `.mir` file with rustc's mid-level intermediate representation.
237+
- "obj": The `.o` file with generated native object code
232238
*/
233239
"emit": "link"
234240
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fn one() -> usize {
2+
1
3+
}
4+
5+
pub mod a {
6+
pub fn two() -> usize {
7+
::one() + ::one()
8+
}
9+
}
10+
11+
pub mod b {
12+
pub fn three() -> usize {
13+
::one() + ::a::two()
14+
}
15+
}
16+
17+
#[inline(never)]
18+
pub fn main() {
19+
a::two();
20+
b::three();
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// rust should produce artifact notifications about files it was asked to --emit.
2+
//
3+
// It should work in incremental mode both on the first pass where files are generated as well
4+
// as on subsequent passes where they are taken from the incremental cache
5+
//
6+
// See <https://internals.rust-lang.org/t/easier-access-to-files-generated-by-emit-foo/20477>
7+
extern crate run_make_support;
8+
9+
use run_make_support::{rustc, tmp_dir};
10+
11+
fn main() {
12+
let inc_dir = tmp_dir();
13+
14+
// With single codegen unit files are renamed to match the source file name
15+
for _ in 0..=1 {
16+
let output = rustc()
17+
.input("lib.rs")
18+
.emit("obj,asm,llvm-ir,llvm-bc,mir")
19+
.codegen_units(1)
20+
.json("artifacts")
21+
.error_format("json")
22+
.incremental(&inc_dir)
23+
.run();
24+
let stderr = String::from_utf8_lossy(&output.stderr);
25+
for file in &["lib.o", "lib.ll", "lib.bc", "lib.s"] {
26+
assert!(stderr.contains(file), "No {:?} in {:?}", file, stderr);
27+
}
28+
}
29+
30+
// with multiple codegen units files keep codegen unit id part.
31+
for _ in 0..=1 {
32+
let output = rustc()
33+
.input("lib.rs")
34+
.emit("obj,asm,llvm-ir,llvm-bc,mir")
35+
.codegen_units(2)
36+
.json("artifacts")
37+
.error_format("json")
38+
.incremental(&inc_dir)
39+
.run();
40+
let stderr = String::from_utf8_lossy(&output.stderr);
41+
for file in &["rcgu.o", "rcgu.ll", "rcgu.bc", "rcgu.s"] {
42+
assert!(stderr.contains(file), "No {:?} in {:?}", file, stderr);
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)