11//! Tool used by CI to inspect compiler-builtins archives and help ensure we won't run into any
22//! linking errors.
33
4+ use std:: collections:: { BTreeMap , BTreeSet } ;
5+ use std:: fs;
6+ use std:: io:: { BufRead , BufReader } ;
7+ use std:: path:: { Path , PathBuf } ;
8+ use std:: process:: { Command , Stdio } ;
9+
410use object:: read:: archive:: { ArchiveFile , ArchiveMember } ;
511use object:: { Object , ObjectSymbol , Symbol , SymbolKind , SymbolScope , SymbolSection } ;
6- use std:: collections:: { BTreeMap , BTreeSet } ;
7- use std:: { fs, path:: Path } ;
12+ use serde_json:: Value ;
813
914const USAGE : & str = "Usage:
1015
11- symbol-check check-duplicates ARCHIVE ...
12- symbol-check check-core-syms ARCHIVE ...
16+ symbol-check build-and-check CARGO_ARGS ...
1317
14- Note that multiple archives may be specified but they are checked independently
15- rather than as a group." ;
18+ Cargo will get invoked with `CARGO_ARGS` and all output
19+ `compiler_builtins*.rlib` files will be checked.
20+ " ;
1621
1722fn main ( ) {
1823 // Create a `&str` vec so we can match on it.
1924 let args = std:: env:: args ( ) . collect :: < Vec < _ > > ( ) ;
2025 let args_ref = args. iter ( ) . map ( String :: as_str) . collect :: < Vec < _ > > ( ) ;
2126
2227 match & args_ref[ 1 ..] {
23- [ "check-duplicates" , rest @ ..] if !rest. is_empty ( ) => {
24- rest. iter ( ) . for_each ( verify_no_duplicates) ;
25- }
26- [ "check-core-syms" , rest @ ..] if !rest. is_empty ( ) => {
27- rest. iter ( ) . for_each ( verify_core_symbols) ;
28+ [ "build-and-check" , rest @ ..] if !rest. is_empty ( ) => {
29+ let paths = exec_cargo_with_args ( & rest) ;
30+ for path in paths {
31+ println ! ( "Checking {}" , path. display( ) ) ;
32+ verify_no_duplicates ( & path) ;
33+ verify_core_symbols ( & path) ;
34+ }
2835 }
2936 _ => {
3037 println ! ( "{USAGE}" ) ;
@@ -33,6 +40,54 @@ fn main() {
3340 }
3441}
3542
43+ fn exec_cargo_with_args ( args : & [ & str ] ) -> Vec < PathBuf > {
44+ let mut cmd = Command :: new ( "cargo" )
45+ . arg ( "build" )
46+ . arg ( "--message-format=json" )
47+ . args ( args)
48+ . stdout ( Stdio :: piped ( ) )
49+ . spawn ( )
50+ . expect ( "failed to launch Cargo" ) ;
51+
52+ let stdout = cmd. stdout . take ( ) . unwrap ( ) ;
53+ let reader = BufReader :: new ( stdout) ;
54+
55+ let mut x = Vec :: new ( ) ;
56+
57+ for m in reader. lines ( ) {
58+ let m = m. expect ( "failed to read line" ) ;
59+ println ! ( "{m}" ) ;
60+
61+ let j: Value = serde_json:: from_str ( & m) . expect ( "failed to deserialize" ) ;
62+ if j[ "reason" ] != "compiler-artifact" {
63+ continue ;
64+ }
65+
66+ for fname in j[ "filenames" ] . as_array ( ) . expect ( "filenames not an array" ) {
67+ let path = fname. as_str ( ) . expect ( "file name not a string" ) ;
68+ let p = PathBuf :: from ( path) ;
69+
70+ if let Some ( ex) = p. extension ( )
71+ && ex == "rlib"
72+ && p. file_name ( )
73+ . unwrap ( )
74+ . to_str ( )
75+ . unwrap ( )
76+ . contains ( "compiler_builtins" )
77+ {
78+ x. push ( p) ;
79+ }
80+ }
81+ }
82+
83+ cmd. wait ( ) . expect ( "failed to wait on Cargo" ) ;
84+
85+ assert ! ( !x. is_empty( ) , "no compiler_builtins rlibs found" ) ;
86+ println ! ( "Collected the following rlibs to check: {x:#?}" ) ;
87+
88+ x
89+ }
90+
3691#[ expect( unused) ] // only for printing
3792#[ derive( Clone , Debug ) ]
3893struct SymInfo {
@@ -69,8 +124,6 @@ impl SymInfo {
69124
70125/// Ensure that the same global symbol isn't defined in multiple object files within an archive.
71126fn verify_no_duplicates ( path : impl AsRef < Path > ) {
72- println ! ( "Checking `{}` for duplicates" , path. as_ref( ) . display( ) ) ;
73-
74127 let mut syms = BTreeMap :: < String , SymInfo > :: new ( ) ;
75128 let mut dups = Vec :: new ( ) ;
76129
@@ -103,16 +156,11 @@ fn verify_no_duplicates(path: impl AsRef<Path>) {
103156 panic ! ( "found duplicate symbols: {dups:#?}" ) ;
104157 }
105158
106- println ! ( "success: no duplicate symbols found" ) ;
159+ println ! ( " success: no duplicate symbols found" ) ;
107160}
108161
109162/// Ensure that there are no references to symbols from `core` that aren't also (somehow) defined.
110163fn verify_core_symbols ( path : impl AsRef < Path > ) {
111- println ! (
112- "Checking `{}` for references to core" ,
113- path. as_ref( ) . display( )
114- ) ;
115-
116164 let mut defined = BTreeSet :: new ( ) ;
117165 let mut undefined = Vec :: new ( ) ;
118166
@@ -138,7 +186,7 @@ fn verify_core_symbols(path: impl AsRef<Path>) {
138186 panic ! ( "found undefined symbols from core: {undefined:#?}" ) ;
139187 }
140188
141- println ! ( "success: no undefined references to core found" ) ;
189+ println ! ( " success: no undefined references to core found" ) ;
142190}
143191
144192/// For a given archive path, do something with each symbol.
0 commit comments