33//! `./x.py test` (aka [`Kind::Test`]) is currently allowed to reach build steps in other modules.
44//! However, this contains ~all test parts we expect people to be able to build and run locally.
55
6+ use std:: collections:: HashSet ;
67use std:: ffi:: { OsStr , OsString } ;
78use std:: path:: { Path , PathBuf } ;
89use std:: { env, fs, iter} ;
910
1011use clap_complete:: shells;
1112
13+ use crate :: core:: build_steps:: compile:: run_cargo;
1214use crate :: core:: build_steps:: doc:: DocumentationFormat ;
1315use crate :: core:: build_steps:: synthetic_targets:: MirOptPanicAbortSyntheticTarget ;
1416use crate :: core:: build_steps:: tool:: { self , SourceType , Tool } ;
@@ -2173,9 +2175,11 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
21732175#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
21742176struct BookTest {
21752177 compiler : Compiler ,
2178+ target : TargetSelection ,
21762179 path : PathBuf ,
21772180 name : & ' static str ,
21782181 is_ext_doc : bool ,
2182+ dependencies : Vec < & ' static str > ,
21792183}
21802184
21812185impl Step for BookTest {
@@ -2228,6 +2232,63 @@ impl BookTest {
22282232 // Books often have feature-gated example text.
22292233 rustbook_cmd. env ( "RUSTC_BOOTSTRAP" , "1" ) ;
22302234 rustbook_cmd. env ( "PATH" , new_path) . arg ( "test" ) . arg ( path) ;
2235+
2236+ // Books may also need to build dependencies. For example, `TheBook` has
2237+ // code samples which use the `trpl` crate. For the `rustdoc` invocation
2238+ // to find them them successfully, they need to be built first and their
2239+ // paths used to generate the
2240+ let libs = if !self . dependencies . is_empty ( ) {
2241+ let mut lib_paths = vec ! [ ] ;
2242+ for dep in self . dependencies {
2243+ let mode = Mode :: ToolRustc ;
2244+ let target = builder. config . build ;
2245+ // CHECKME: is this correct, or should it be using `builder::Cargo::new`?
2246+ let cargo = tool:: prepare_tool_cargo (
2247+ builder,
2248+ self . compiler ,
2249+ mode,
2250+ builder. config . build ,
2251+ Kind :: Build ,
2252+ dep,
2253+ SourceType :: Submodule ,
2254+ & [ ] ,
2255+ ) ;
2256+ // CHECKME: this is used for the "stamp" for this `run_cargo`;
2257+ // is there a better way to do this?!?
2258+ let dep_path = PathBuf :: from ( dep) ;
2259+ let file_name = dep_path. file_name ( ) . unwrap ( ) ;
2260+ let file_name = PathBuf :: from ( file_name) ;
2261+
2262+ let stamp = builder
2263+ . cargo_out ( self . compiler , mode, target)
2264+ . join ( file_name)
2265+ . with_extension ( "stamp" ) ;
2266+
2267+ let output_paths = run_cargo ( builder, cargo, vec ! [ ] , & stamp, vec ! [ ] , false , false ) ;
2268+ let directories = output_paths
2269+ . into_iter ( )
2270+ . filter_map ( |p| p. parent ( ) . map ( ToOwned :: to_owned) )
2271+ . fold ( HashSet :: new ( ) , |mut set, dir| {
2272+ set. insert ( dir) ;
2273+ set
2274+ } ) ;
2275+ lib_paths. extend ( directories) ;
2276+ }
2277+ lib_paths
2278+ } else {
2279+ vec ! [ ]
2280+ } ;
2281+
2282+ if !libs. is_empty ( ) {
2283+ let comma_separated_paths = libs
2284+ . into_iter ( )
2285+ . map ( |path| format ! ( "{}" , path. display( ) ) )
2286+ . collect :: < Vec < String > > ( )
2287+ . join ( "," ) ;
2288+
2289+ rustbook_cmd. args ( vec ! [ String :: from( "--library-path" ) , comma_separated_paths] ) ;
2290+ }
2291+
22312292 builder. add_rust_test_threads ( & mut rustbook_cmd) ;
22322293 let _guard = builder. msg (
22332294 Kind :: Test ,
@@ -2286,12 +2347,14 @@ macro_rules! test_book {
22862347 $name: ident, $path: expr, $book_name: expr,
22872348 default =$default: expr
22882349 $( , submodules = $submodules: expr) ?
2350+ $( , dependencies=$dependencies: expr) ?
22892351 ;
22902352 ) +) => {
22912353 $(
22922354 #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
22932355 pub struct $name {
22942356 compiler: Compiler ,
2357+ target: TargetSelection ,
22952358 }
22962359
22972360 impl Step for $name {
@@ -2306,6 +2369,7 @@ macro_rules! test_book {
23062369 fn make_run( run: RunConfig <' _>) {
23072370 run. builder. ensure( $name {
23082371 compiler: run. builder. compiler( run. builder. top_stage, run. target) ,
2372+ target: run. target,
23092373 } ) ;
23102374 }
23112375
@@ -2315,11 +2379,22 @@ macro_rules! test_book {
23152379 builder. require_submodule( submodule, None ) ;
23162380 }
23172381 ) *
2382+
2383+ let dependencies = vec![ ] ;
2384+ $(
2385+ let mut dependencies = dependencies;
2386+ for dep in $dependencies {
2387+ dependencies. push( dep) ;
2388+ }
2389+ ) ?
2390+
23182391 builder. ensure( BookTest {
23192392 compiler: self . compiler,
2393+ target: self . target,
23202394 path: PathBuf :: from( $path) ,
23212395 name: $book_name,
23222396 is_ext_doc: !$default,
2397+ dependencies,
23232398 } ) ;
23242399 }
23252400 }
@@ -2334,7 +2409,7 @@ test_book!(
23342409 RustcBook , "src/doc/rustc" , "rustc" , default =true ;
23352410 RustByExample , "src/doc/rust-by-example" , "rust-by-example" , default =false , submodules=[ "src/doc/rust-by-example" ] ;
23362411 EmbeddedBook , "src/doc/embedded-book" , "embedded-book" , default =false , submodules=[ "src/doc/embedded-book" ] ;
2337- TheBook , "src/doc/book" , "book" , default =false , submodules=[ "src/doc/book" ] ;
2412+ TheBook , "src/doc/book" , "book" , default =false , submodules=[ "src/doc/book" ] , dependencies= [ "src/doc/book/packages/trpl" ] ;
23382413 UnstableBook , "src/doc/unstable-book" , "unstable-book" , default =true ;
23392414 EditionGuide , "src/doc/edition-guide" , "edition-guide" , default =false , submodules=[ "src/doc/edition-guide" ] ;
23402415) ;
0 commit comments