11use anyhow:: Context ;
22use flate2:: { Compression , write:: GzEncoder } ;
3- use std:: env:: consts:: EXE_EXTENSION ;
4- use std:: ffi:: OsStr ;
53use std:: {
6- env,
74 fs:: File ,
85 io:: { self , BufWriter } ,
96 path:: { Path , PathBuf } ,
@@ -12,11 +9,11 @@ use time::OffsetDateTime;
129use xshell:: { Cmd , Shell , cmd} ;
1310use zip:: { DateTime , ZipWriter , write:: SimpleFileOptions } ;
1411
15- use crate :: flags:: PgoTrainingCrate ;
1612use crate :: {
1713 date_iso,
18- flags:: { self , Malloc } ,
14+ flags:: { self , Malloc , PgoTrainingCrate } ,
1915 project_root,
16+ util:: detect_target,
2017} ;
2118
2219const VERSION_STABLE : & str = "0.3" ;
@@ -28,7 +25,7 @@ impl flags::Dist {
2825 let stable = sh. var ( "GITHUB_REF" ) . unwrap_or_default ( ) . as_str ( ) == "refs/heads/release" ;
2926
3027 let project_root = project_root ( ) ;
31- let target = Target :: get ( & project_root) ;
28+ let target = Target :: get ( & project_root, sh ) ;
3229 let allocator = self . allocator ( ) ;
3330 let dist = project_root. join ( "dist" ) ;
3431 sh. remove_path ( & dist) ?;
@@ -113,9 +110,9 @@ fn dist_server(
113110 let command = if linux_target && zig { "zigbuild" } else { "build" } ;
114111
115112 let pgo_profile = if let Some ( train_crate) = pgo {
116- Some ( gather_pgo_profile (
113+ Some ( crate :: pgo :: gather_pgo_profile (
117114 sh,
118- build_command ( sh, command, & target_name, features) ,
115+ crate :: pgo :: build_command ( sh, command, & target_name, features) ,
119116 & target_name,
120117 train_crate,
121118 ) ?)
@@ -151,85 +148,6 @@ fn build_command<'a>(
151148 )
152149}
153150
154- /// Decorates `ra_build_cmd` to add PGO instrumentation, and then runs the PGO instrumented
155- /// Rust Analyzer on itself to gather a PGO profile.
156- fn gather_pgo_profile < ' a > (
157- sh : & ' a Shell ,
158- ra_build_cmd : Cmd < ' a > ,
159- target : & str ,
160- train_crate : PgoTrainingCrate ,
161- ) -> anyhow:: Result < PathBuf > {
162- let pgo_dir = std:: path:: absolute ( "rust-analyzer-pgo" ) ?;
163- // Clear out any stale profiles
164- if pgo_dir. is_dir ( ) {
165- std:: fs:: remove_dir_all ( & pgo_dir) ?;
166- }
167- std:: fs:: create_dir_all ( & pgo_dir) ?;
168-
169- // Figure out a path to `llvm-profdata`
170- let target_libdir = cmd ! ( sh, "rustc --print=target-libdir" )
171- . read ( )
172- . context ( "cannot resolve target-libdir from rustc" ) ?;
173- let target_bindir = PathBuf :: from ( target_libdir) . parent ( ) . unwrap ( ) . join ( "bin" ) ;
174- let llvm_profdata = target_bindir. join ( "llvm-profdata" ) . with_extension ( EXE_EXTENSION ) ;
175-
176- // Build RA with PGO instrumentation
177- let cmd_gather =
178- ra_build_cmd. env ( "RUSTFLAGS" , format ! ( "-Cprofile-generate={}" , pgo_dir. to_str( ) . unwrap( ) ) ) ;
179- cmd_gather. run ( ) . context ( "cannot build rust-analyzer with PGO instrumentation" ) ?;
180-
181- let ( train_path, label) = match & train_crate {
182- PgoTrainingCrate :: RustAnalyzer => ( PathBuf :: from ( "." ) , "itself" ) ,
183- PgoTrainingCrate :: GitHub ( repo) => {
184- ( download_crate_for_training ( sh, & pgo_dir, repo) ?, repo. as_str ( ) )
185- }
186- } ;
187-
188- // Run RA either on itself or on a downloaded crate
189- eprintln ! ( "Training RA on {label}..." ) ;
190- cmd ! (
191- sh,
192- "target/{target}/release/rust-analyzer analysis-stats -q --run-all-ide-things {train_path}"
193- )
194- . run ( )
195- . context ( "cannot generate PGO profiles" ) ?;
196-
197- // Merge profiles into a single file
198- let merged_profile = pgo_dir. join ( "merged.profdata" ) ;
199- let profile_files = std:: fs:: read_dir ( pgo_dir) ?. filter_map ( |entry| {
200- let entry = entry. ok ( ) ?;
201- if entry. path ( ) . extension ( ) == Some ( OsStr :: new ( "profraw" ) ) {
202- Some ( entry. path ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) )
203- } else {
204- None
205- }
206- } ) ;
207- cmd ! ( sh, "{llvm_profdata} merge {profile_files...} -o {merged_profile}" ) . run ( ) . context (
208- "cannot merge PGO profiles. Do you have the rustup `llvm-tools` component installed?" ,
209- ) ?;
210-
211- Ok ( merged_profile)
212- }
213-
214- /// Downloads a crate from GitHub, stores it into `pgo_dir` and returns a path to it.
215- fn download_crate_for_training ( sh : & Shell , pgo_dir : & Path , repo : & str ) -> anyhow:: Result < PathBuf > {
216- let mut it = repo. splitn ( 2 , '@' ) ;
217- let repo = it. next ( ) . unwrap ( ) ;
218- let revision = it. next ( ) ;
219-
220- // FIXME: switch to `--revision` here around 2035 or so
221- let revision =
222- if let Some ( revision) = revision { & [ "--branch" , revision] as & [ & str ] } else { & [ ] } ;
223-
224- let normalized_path = repo. replace ( "/" , "-" ) ;
225- let target_path = pgo_dir. join ( normalized_path) ;
226- cmd ! ( sh, "git clone --depth 1 https://github.com/{repo} {revision...} {target_path}" )
227- . run ( )
228- . with_context ( || "cannot download PGO training crate from {repo}" ) ?;
229-
230- Ok ( target_path)
231- }
232-
233151fn gzip ( src_path : & Path , dest_path : & Path ) -> anyhow:: Result < ( ) > {
234152 let mut encoder = GzEncoder :: new ( File :: create ( dest_path) ?, Compression :: best ( ) ) ;
235153 let mut input = io:: BufReader :: new ( File :: open ( src_path) ?) ;
@@ -283,21 +201,8 @@ struct Target {
283201}
284202
285203impl Target {
286- fn get ( project_root : & Path ) -> Self {
287- let name = match env:: var ( "RA_TARGET" ) {
288- Ok ( target) => target,
289- _ => {
290- if cfg ! ( target_os = "linux" ) {
291- "x86_64-unknown-linux-gnu" . to_owned ( )
292- } else if cfg ! ( target_os = "windows" ) {
293- "x86_64-pc-windows-msvc" . to_owned ( )
294- } else if cfg ! ( target_os = "macos" ) {
295- "x86_64-apple-darwin" . to_owned ( )
296- } else {
297- panic ! ( "Unsupported OS, maybe try setting RA_TARGET" )
298- }
299- }
300- } ;
204+ fn get ( project_root : & Path , sh : & Shell ) -> Self {
205+ let name = detect_target ( sh) ;
301206 let ( name, libc_suffix) = match name. split_once ( '.' ) {
302207 Some ( ( l, r) ) => ( l. to_owned ( ) , Some ( r. to_owned ( ) ) ) ,
303208 None => ( name, None ) ,
0 commit comments