Skip to main content

run_make_support/external_deps/
llvm.rs

1use std::path::{Path, PathBuf};
2
3use crate::command::Command;
4use crate::env::env_var;
5
6/// Construct a new `llvm-readobj` invocation with the `GNU` output style.
7/// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`.
8#[track_caller]
9pub fn llvm_readobj() -> LlvmReadobj {
10    LlvmReadobj::new()
11}
12
13/// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available
14/// at `$LLVM_BIN_DIR/llvm-profdata`.
15#[track_caller]
16pub fn llvm_profdata() -> LlvmProfdata {
17    LlvmProfdata::new()
18}
19
20/// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
21/// at `$LLVM_FILECHECK`.
22#[track_caller]
23pub fn llvm_filecheck() -> LlvmFilecheck {
24    LlvmFilecheck::new()
25}
26
27/// Construct a new `llvm-objdump` invocation. This assumes that `llvm-objdump` is available
28/// at `$LLVM_BIN_DIR/llvm-objdump`.
29pub fn llvm_objdump() -> LlvmObjdump {
30    LlvmObjdump::new()
31}
32
33/// Construct a new `llvm-ar` invocation. This assumes that `llvm-ar` is available
34/// at `$LLVM_BIN_DIR/llvm-ar`.
35pub fn llvm_ar() -> LlvmAr {
36    LlvmAr::new()
37}
38
39/// Construct a new `llvm-nm` invocation. This assumes that `llvm-nm` is available
40/// at `$LLVM_BIN_DIR/llvm-nm`.
41pub fn llvm_nm() -> LlvmNm {
42    LlvmNm::new()
43}
44
45/// Construct a new `llvm-bcanalyzer` invocation. This assumes that `llvm-bcanalyzer` is available
46/// at `$LLVM_BIN_DIR/llvm-bcanalyzer`.
47pub fn llvm_bcanalyzer() -> LlvmBcanalyzer {
48    LlvmBcanalyzer::new()
49}
50
51/// Construct a new `llvm-dwarfdump` invocation. This assumes that `llvm-dwarfdump` is available
52/// at `$LLVM_BIN_DIR/llvm-dwarfdump`.
53pub fn llvm_dwarfdump() -> LlvmDwarfdump {
54    LlvmDwarfdump::new()
55}
56
57/// Construct a new `llvm-pdbutil` invocation. This assumes that `llvm-pdbutil` is available
58/// at `$LLVM_BIN_DIR/llvm-pdbutil`.
59pub fn llvm_pdbutil() -> LlvmPdbutil {
60    LlvmPdbutil::new()
61}
62
63/// Construct a new `llvm-as` invocation. This assumes that `llvm-as` is available
64/// at `$LLVM_BIN_DIR/llvm-as`.
65pub fn llvm_as() -> LlvmAs {
66    LlvmAs::new()
67}
68
69/// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
70/// at `$LLVM_BIN_DIR/llvm-dis`.
71pub fn llvm_dis() -> LlvmDis {
72    LlvmDis::new()
73}
74
75/// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
76/// at `$LLVM_BIN_DIR/llvm-objcopy`.
77pub fn llvm_objcopy() -> LlvmObjcopy {
78    LlvmObjcopy::new()
79}
80
81/// A `llvm-readobj` invocation builder.
82#[derive(Debug)]
83#[must_use]
84pub struct LlvmReadobj {
85    cmd: Command,
86}
87
88/// A `llvm-profdata` invocation builder.
89#[derive(Debug)]
90#[must_use]
91pub struct LlvmProfdata {
92    cmd: Command,
93}
94
95/// A `llvm-filecheck` invocation builder.
96#[derive(Debug)]
97#[must_use]
98pub struct LlvmFilecheck {
99    cmd: Command,
100}
101
102/// A `llvm-objdump` invocation builder.
103#[derive(Debug)]
104#[must_use]
105pub struct LlvmObjdump {
106    cmd: Command,
107}
108
109/// A `llvm-ar` invocation builder.
110#[derive(Debug)]
111#[must_use]
112pub struct LlvmAr {
113    cmd: Command,
114}
115
116/// A `llvm-nm` invocation builder.
117#[derive(Debug)]
118#[must_use]
119pub struct LlvmNm {
120    cmd: Command,
121}
122
123/// A `llvm-bcanalyzer` invocation builder.
124#[derive(Debug)]
125#[must_use]
126pub struct LlvmBcanalyzer {
127    cmd: Command,
128}
129
130/// A `llvm-dwarfdump` invocation builder.
131#[derive(Debug)]
132#[must_use]
133pub struct LlvmDwarfdump {
134    cmd: Command,
135}
136
137/// A `llvm-pdbutil` invocation builder.
138#[derive(Debug)]
139#[must_use]
140pub struct LlvmPdbutil {
141    cmd: Command,
142}
143
144/// A `llvm-as` invocation builder.
145#[derive(Debug)]
146#[must_use]
147pub struct LlvmAs {
148    cmd: Command,
149}
150
151/// A `llvm-dis` invocation builder.
152#[derive(Debug)]
153#[must_use]
154pub struct LlvmDis {
155    cmd: Command,
156}
157
158/// A `llvm-objcopy` invocation builder.
159#[derive(Debug)]
160#[must_use]
161pub struct LlvmObjcopy {
162    cmd: Command,
163}
164
165crate::macros::impl_common_helpers!(LlvmReadobj);
166crate::macros::impl_common_helpers!(LlvmProfdata);
167crate::macros::impl_common_helpers!(LlvmFilecheck);
168crate::macros::impl_common_helpers!(LlvmObjdump);
169crate::macros::impl_common_helpers!(LlvmAr);
170crate::macros::impl_common_helpers!(LlvmNm);
171crate::macros::impl_common_helpers!(LlvmBcanalyzer);
172crate::macros::impl_common_helpers!(LlvmDwarfdump);
173crate::macros::impl_common_helpers!(LlvmPdbutil);
174crate::macros::impl_common_helpers!(LlvmAs);
175crate::macros::impl_common_helpers!(LlvmDis);
176crate::macros::impl_common_helpers!(LlvmObjcopy);
177
178/// Generate the path to the bin directory of LLVM.
179#[must_use]
180pub fn llvm_bin_dir() -> PathBuf {
181    let llvm_bin_dir = env_var("LLVM_BIN_DIR");
182    PathBuf::from(llvm_bin_dir)
183}
184
185impl LlvmReadobj {
186    /// Construct a new `llvm-readobj` invocation with the `GNU` output style.
187    /// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`.
188    #[track_caller]
189    pub fn new() -> Self {
190        let llvm_readobj = llvm_bin_dir().join("llvm-readobj");
191        let cmd = Command::new(llvm_readobj);
192        let mut readobj = Self { cmd };
193        readobj.elf_output_style("GNU");
194        readobj
195    }
196
197    /// Specify the format of the ELF information.
198    ///
199    /// Valid options are `LLVM` (default), `GNU`, and `JSON`.
200    pub fn elf_output_style(&mut self, style: &str) -> &mut Self {
201        self.cmd.arg("--elf-output-style");
202        self.cmd.arg(style);
203        self
204    }
205
206    /// Provide an input file.
207    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
208        self.cmd.arg(path.as_ref());
209        self
210    }
211
212    /// Pass `--file-header` to display file headers.
213    pub fn file_header(&mut self) -> &mut Self {
214        self.cmd.arg("--file-header");
215        self
216    }
217
218    /// Pass `--program-headers` to display program headers.
219    pub fn program_headers(&mut self) -> &mut Self {
220        self.cmd.arg("--program-headers");
221        self
222    }
223
224    /// Pass `--symbols` to display the symbol table, including both local
225    /// and global symbols.
226    pub fn symbols(&mut self) -> &mut Self {
227        self.cmd.arg("--symbols");
228        self
229    }
230
231    /// Pass `--dynamic-table` to display the dynamic symbol table.
232    pub fn dynamic_table(&mut self) -> &mut Self {
233        self.cmd.arg("--dynamic-table");
234        self
235    }
236
237    /// Specify the section to display.
238    pub fn section(&mut self, section: &str) -> &mut Self {
239        self.cmd.arg("--string-dump");
240        self.cmd.arg(section);
241        self
242    }
243}
244
245impl LlvmProfdata {
246    /// Construct a new `llvm-profdata` invocation. This assumes that `llvm-profdata` is available
247    /// at `$LLVM_BIN_DIR/llvm-profdata`.
248    #[track_caller]
249    pub fn new() -> Self {
250        let llvm_profdata = llvm_bin_dir().join("llvm-profdata");
251        let cmd = Command::new(llvm_profdata);
252        Self { cmd }
253    }
254
255    /// Provide an input file.
256    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
257        self.cmd.arg(path.as_ref());
258        self
259    }
260
261    /// Specify the output file path.
262    pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
263        self.cmd.arg("-o");
264        self.cmd.arg(path.as_ref());
265        self
266    }
267
268    /// Take several profile data files generated by PGO instrumentation and merge them
269    /// together into a single indexed profile data file.
270    pub fn merge(&mut self) -> &mut Self {
271        self.cmd.arg("merge");
272        self
273    }
274}
275
276impl LlvmFilecheck {
277    /// Construct a new `llvm-filecheck` invocation. This assumes that `llvm-filecheck` is available
278    /// at `$LLVM_FILECHECK`.
279    #[track_caller]
280    pub fn new() -> Self {
281        let llvm_filecheck = env_var("LLVM_FILECHECK");
282        let cmd = Command::new(llvm_filecheck);
283        Self { cmd }
284    }
285
286    /// Provide a buffer representing standard input containing patterns that will be matched
287    /// against the `.patterns(path)` call.
288    pub fn stdin_buf<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self {
289        self.cmd.stdin_buf(input);
290        self
291    }
292
293    /// Provide the patterns that need to be matched.
294    pub fn patterns<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
295        self.cmd.arg(path.as_ref());
296        self
297    }
298
299    /// `--input-file` option.
300    pub fn input_file<P: AsRef<Path>>(&mut self, input_file: P) -> &mut Self {
301        self.cmd.arg("--input-file");
302        self.cmd.arg(input_file.as_ref());
303        self
304    }
305
306    /// Set a single `--check-prefix`.
307    pub fn check_prefix<S: AsRef<str>>(&mut self, prefix: S) -> &mut Self {
308        self.cmd.arg(format!("--check-prefix={}", prefix.as_ref()));
309        self
310    }
311}
312
313impl LlvmObjdump {
314    /// Construct a new `llvm-objdump` invocation. This assumes that `llvm-objdump` is available
315    /// at `$LLVM_BIN_DIR/llvm-objdump`.
316    pub fn new() -> Self {
317        let llvm_objdump = llvm_bin_dir().join("llvm-objdump");
318        let cmd = Command::new(llvm_objdump);
319        Self { cmd }
320    }
321
322    /// Provide an input file.
323    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
324        self.cmd.arg(path.as_ref());
325        self
326    }
327
328    /// Disassemble all executable sections found in the input files.
329    pub fn disassemble(&mut self) -> &mut Self {
330        self.cmd.arg("-d");
331        self
332    }
333
334    /// Demangle symbols.
335    pub fn demangle(&mut self) -> &mut Self {
336        self.cmd.arg("--demangle");
337        self
338    }
339}
340
341impl LlvmAr {
342    /// Construct a new `llvm-ar` invocation. This assumes that `llvm-ar` is available
343    /// at `$LLVM_BIN_DIR/llvm-ar`.
344    pub fn new() -> Self {
345        let llvm_ar = llvm_bin_dir().join("llvm-ar");
346        let cmd = Command::new(llvm_ar);
347        Self { cmd }
348    }
349
350    /// Automatically pass the commonly used arguments `rcus`, used for combining one or more
351    /// input object files into one output static library file.
352    pub fn obj_to_ar(&mut self) -> &mut Self {
353        self.cmd.arg("rcus");
354        self
355    }
356
357    /// Like `obj_to_ar` except creating a thin archive.
358    pub fn obj_to_thin_ar(&mut self) -> &mut Self {
359        self.cmd.arg("rcus").arg("--thin");
360        self
361    }
362
363    /// Extract archive members back to files.
364    pub fn extract(&mut self) -> &mut Self {
365        self.cmd.arg("x");
366        self
367    }
368
369    /// Print the table of contents.
370    pub fn table_of_contents(&mut self) -> &mut Self {
371        self.cmd.arg("t");
372        self
373    }
374
375    /// Provide an output, then an input file. Bundled in one function, as llvm-ar has
376    /// no "--output"-style flag.
377    pub fn output_input(&mut self, out: impl AsRef<Path>, input: impl AsRef<Path>) -> &mut Self {
378        self.cmd.arg(out.as_ref());
379        self.cmd.arg(input.as_ref());
380        self
381    }
382}
383
384impl LlvmNm {
385    /// Construct a new `llvm-nm` invocation. This assumes that `llvm-nm` is available
386    /// at `$LLVM_BIN_DIR/llvm-nm`.
387    pub fn new() -> Self {
388        let llvm_nm = llvm_bin_dir().join("llvm-nm");
389        let cmd = Command::new(llvm_nm);
390        Self { cmd }
391    }
392
393    /// Provide an input file.
394    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
395        self.cmd.arg(path.as_ref());
396        self
397    }
398}
399
400impl LlvmBcanalyzer {
401    /// Construct a new `llvm-bcanalyzer` invocation. This assumes that `llvm-bcanalyzer` is available
402    /// at `$LLVM_BIN_DIR/llvm-bcanalyzer`.
403    pub fn new() -> Self {
404        let llvm_bcanalyzer = llvm_bin_dir().join("llvm-bcanalyzer");
405        let cmd = Command::new(llvm_bcanalyzer);
406        Self { cmd }
407    }
408
409    /// Provide an input file.
410    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
411        self.cmd.arg(path.as_ref());
412        self
413    }
414}
415
416impl LlvmDwarfdump {
417    /// Construct a new `llvm-dwarfdump` invocation. This assumes that `llvm-dwarfdump` is available
418    /// at `$LLVM_BIN_DIR/llvm-dwarfdump`.
419    pub fn new() -> Self {
420        let llvm_dwarfdump = llvm_bin_dir().join("llvm-dwarfdump");
421        let cmd = Command::new(llvm_dwarfdump);
422        Self { cmd }
423    }
424
425    /// Provide an input file.
426    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
427        self.cmd.arg(path.as_ref());
428        self
429    }
430}
431
432impl LlvmPdbutil {
433    /// Construct a new `llvm-pdbutil` invocation. This assumes that `llvm-pdbutil` is available
434    /// at `$LLVM_BIN_DIR/llvm-pdbutil`.
435    pub fn new() -> Self {
436        let llvm_pdbutil = llvm_bin_dir().join("llvm-pdbutil");
437        let cmd = Command::new(llvm_pdbutil);
438        Self { cmd }
439    }
440
441    /// Provide an input file.
442    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
443        self.cmd.arg(path.as_ref());
444        self
445    }
446}
447
448impl LlvmObjcopy {
449    /// Construct a new `llvm-objcopy` invocation. This assumes that `llvm-objcopy` is available
450    /// at `$LLVM_BIN_DIR/llvm-objcopy`.
451    pub fn new() -> Self {
452        let llvm_objcopy = llvm_bin_dir().join("llvm-objcopy");
453        let cmd = Command::new(llvm_objcopy);
454        Self { cmd }
455    }
456
457    /// Dump the contents of `section` into the file at `path`.
458    #[track_caller]
459    pub fn dump_section<S: AsRef<str>, P: AsRef<Path>>(
460        &mut self,
461        section_name: S,
462        path: P,
463    ) -> &mut Self {
464        self.cmd.arg("--dump-section");
465        self.cmd.arg(format!("{}={}", section_name.as_ref(), path.as_ref().to_str().unwrap()));
466        self
467    }
468}
469
470impl LlvmAs {
471    /// Construct a new `llvm-as` invocation. This assumes that `llvm-as` is available
472    /// at `$LLVM_BIN_DIR/llvm-as`.
473    pub fn new() -> Self {
474        let llvm_as = llvm_bin_dir().join("llvm-as");
475        let cmd = Command::new(llvm_as);
476        Self { cmd }
477    }
478
479    /// Provide an input file.
480    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
481        self.cmd.arg(path.as_ref());
482        self
483    }
484}
485
486impl LlvmDis {
487    /// Construct a new `llvm-dis` invocation. This assumes that `llvm-dis` is available
488    /// at `$LLVM_BIN_DIR/llvm-dis`.
489    pub fn new() -> Self {
490        let llvm_dis = llvm_bin_dir().join("llvm-dis");
491        let cmd = Command::new(llvm_dis);
492        Self { cmd }
493    }
494
495    /// Provide an input file.
496    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
497        self.cmd.arg(path.as_ref());
498        self
499    }
500}