tool.rs 25.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

M
Mark Simulacrum 已提交
11
use std::fs;
12
use std::env;
13
use std::iter;
14
use std::path::PathBuf;
15
use std::process::{Command, exit};
16
use std::collections::HashSet;
17 18

use Mode;
M
Mark Simulacrum 已提交
19
use Compiler;
20
use builder::{Step, RunConfig, ShouldRun, Builder};
21
use util::{exe, add_lib_path};
22
use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
23 24
use native;
use channel::GitInfo;
25
use cache::Interned;
26
use toolstate::ToolState;
27

28
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
29 30 31
pub struct CleanTools {
    pub compiler: Compiler,
    pub target: Interned<String>,
32
    pub cause: Mode,
33 34
}

35
impl Step for CleanTools {
36 37
    type Output = ();

38 39
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
40 41
    }

42
    fn run(self, builder: &Builder) {
43
        let compiler = self.compiler;
44
        let target = self.target;
45
        let cause = self.cause;
46

47 48 49
        // This is for the original compiler, but if we're forced to use stage 1, then
        // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
        // we copy the libs forward.
C
Collins Abitekaniza 已提交
50
        let tools_dir = builder.stage_out(compiler, Mode::ToolRustc);
51 52 53 54
        let compiler = if builder.force_use_stage1(compiler, target) {
            builder.compiler(1, compiler.host)
        } else {
            compiler
55
        };
56

57
        for &cur_mode in &[Mode::Std, Mode::Test, Mode::Rustc] {
58
            let stamp = match cur_mode {
59 60 61
                Mode::Std => libstd_stamp(builder, compiler, target),
                Mode::Test => libtest_stamp(builder, compiler, target),
                Mode::Rustc => librustc_stamp(builder, compiler, target),
62 63 64
                _ => panic!(),
            };

65
            if builder.clear_if_dirty(&tools_dir, &stamp) {
66 67 68 69 70
                break;
            }

            // If we are a rustc tool, and std changed, we also need to clear ourselves out -- our
            // dependencies depend on std. Therefore, we iterate up until our own mode.
71
            if cause == cur_mode {
72 73 74
                break;
            }
        }
75 76 77
    }
}

78
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
79 80 81 82
struct ToolBuild {
    compiler: Compiler,
    target: Interned<String>,
    tool: &'static str,
83
    path: &'static str,
84
    mode: Mode,
85
    is_ext_tool: bool,
86
    extra_features: Vec<String>,
87 88
}

89
impl Step for ToolBuild {
90
    type Output = Option<PathBuf>;
91

92 93
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
94 95
    }

96 97 98 99
    /// Build a tool in `src/tools`
    ///
    /// This will build the specified tool with the specified `host` compiler in
    /// `stage` into the normal cargo output directory.
100
    fn run(self, builder: &Builder) -> Option<PathBuf> {
101
        let compiler = self.compiler;
102 103
        let target = self.target;
        let tool = self.tool;
104
        let path = self.path;
105
        let is_ext_tool = self.is_ext_tool;
106

107
        match self.mode {
108 109 110
            Mode::ToolRustc => {
                builder.ensure(compile::Rustc { compiler, target })
            }
A
Alex Crichton 已提交
111 112 113
            Mode::ToolStd => {
                builder.ensure(compile::Std { compiler, target })
            }
114
            Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs
C
Collins Abitekaniza 已提交
115
            _ => panic!("unexpected Mode for tool build")
116 117
        }

118 119 120 121 122 123 124 125 126
        let mut cargo = prepare_tool_cargo(
            builder,
            compiler,
            self.mode,
            target,
            "build",
            path,
            is_ext_tool,
        );
127
        cargo.arg("--features").arg(self.extra_features.join(" "));
128

129 130
        let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
        builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
131
        let mut duplicates = Vec::new();
132
        let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| {
133
            // Only care about big things like the RLS/Cargo for now
134 135 136 137 138 139 140
            match tool {
                | "rls"
                | "cargo"
                | "clippy-driver"
                => {}

                _ => return,
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
            }
            let (id, features, filenames) = match msg {
                compile::CargoMessage::CompilerArtifact {
                    package_id,
                    features,
                    filenames
                } => {
                    (package_id, features, filenames)
                }
                _ => return,
            };
            let features = features.iter().map(|s| s.to_string()).collect::<Vec<_>>();

            for path in filenames {
                let val = (tool, PathBuf::from(&*path), features.clone());
                // we're only interested in deduplicating rlibs for now
                if val.1.extension().and_then(|s| s.to_str()) != Some("rlib") {
                    continue
                }

                // Don't worry about libs that turn out to be host dependencies
                // or build scripts, we only care about target dependencies that
                // are in `deps`.
                if let Some(maybe_target) = val.1
                    .parent()                   // chop off file name
                    .and_then(|p| p.parent())   // chop off `deps`
                    .and_then(|p| p.parent())   // chop off `release`
                    .and_then(|p| p.file_name())
                    .and_then(|p| p.to_str())
                {
                    if maybe_target != &*target {
                        continue
                    }
                }

176
                let mut artifacts = builder.tool_artifacts.borrow_mut();
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
                let prev_artifacts = artifacts
                    .entry(target)
                    .or_insert_with(Default::default);
                if let Some(prev) = prev_artifacts.get(&*id) {
                    if prev.1 != val.1 {
                        duplicates.push((
                            id.to_string(),
                            val,
                            prev.clone(),
                        ));
                    }
                    return
                }
                prev_artifacts.insert(id.to_string(), val);
            }
        });

        if is_expected && duplicates.len() != 0 {
            println!("duplicate artfacts found when compiling a tool, this \
                      typically means that something was recompiled because \
                      a transitive dependency has different features activated \
                      than in a previous build:\n");
199 200
            println!("the following dependencies are duplicated although they \
                      have the same features enabled:");
O
Oliver Schneider 已提交
201
            for (id, cur, prev) in duplicates.drain_filter(|(_, cur, prev)| cur.2 == prev.2) {
202
                println!("  {}", id);
O
Oliver Schneider 已提交
203 204
                // same features
                println!("    `{}` ({:?})\n    `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
205 206
            }
            println!("the following dependencies have different features:");
207 208
            for (id, cur, prev) in duplicates {
                println!("  {}", id);
209 210 211
                let cur_features: HashSet<_> = cur.2.into_iter().collect();
                let prev_features: HashSet<_> = prev.2.into_iter().collect();
                println!("    `{}` additionally enabled features {:?} at {:?}",
O
Oliver Schneider 已提交
212
                         cur.0, &cur_features - &prev_features, cur.1);
213
                println!("    `{}` additionally enabled features {:?} at {:?}",
O
Oliver Schneider 已提交
214
                         prev.0, &prev_features - &cur_features, prev.1);
215 216 217 218 219
            }
            println!("");
            panic!("tools should not compile multiple copies of the same crate");
        }

220
        builder.save_toolstate(tool, if is_expected {
221
            ToolState::TestFail
222
        } else {
223
            ToolState::BuildFail
224 225 226
        });

        if !is_expected {
227
            if !is_ext_tool {
M
Mark Simulacrum 已提交
228
                exit(1);
229 230 231
            } else {
                return None;
            }
232
        } else {
C
Collins Abitekaniza 已提交
233
            let cargo_out = builder.cargo_out(compiler, self.mode, target)
234
                .join(exe(tool, &compiler.host));
235 236
            let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host));
            builder.copy(&cargo_out, &bin);
237 238
            Some(bin)
        }
239 240
    }
}
241

242
pub fn prepare_tool_cargo(
243 244
    builder: &Builder,
    compiler: Compiler,
C
Collins Abitekaniza 已提交
245
    mode: Mode,
246
    target: Interned<String>,
247
    command: &'static str,
248
    path: &'static str,
249
    is_ext_tool: bool,
250
) -> Command {
C
Collins Abitekaniza 已提交
251
    let mut cargo = builder.cargo(compiler, mode, target, command);
252
    let dir = builder.src.join(path);
253 254 255 256 257 258
    cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));

    // We don't want to build tools dynamically as they'll be running across
    // stages and such and it's just easier if they're not dynamically linked.
    cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");

259 260 261 262
    if is_ext_tool {
        cargo.env("RUSTC_EXT_TOOL", "1");
    }

263
    if let Some(dir) = builder.openssl_install_dir(target) {
264 265 266 267
        cargo.env("OPENSSL_STATIC", "1");
        cargo.env("OPENSSL_DIR", dir);
        cargo.env("LIBZ_SYS_STATIC", "1");
    }
268

A
Alex Crichton 已提交
269 270 271 272
    // if tools are using lzma we want to force the build script to build its
    // own copy
    cargo.env("LZMA_API_STATIC", "1");

273 274
    cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
    cargo.env("CFG_VERSION", builder.rust_version());
275

276
    let info = GitInfo::new(&builder.config, &dir);
277 278 279 280 281 282 283 284
    if let Some(sha) = info.sha() {
        cargo.env("CFG_COMMIT_HASH", sha);
    }
    if let Some(sha_short) = info.sha_short() {
        cargo.env("CFG_SHORT_COMMIT_HASH", sha_short);
    }
    if let Some(date) = info.commit_date() {
        cargo.env("CFG_COMMIT_DATE", date);
285
    }
286
    cargo
287 288 289
}

macro_rules! tool {
290
    ($($name:ident, $path:expr, $tool_name:expr, $mode:expr $(,llvm_tools = $llvm:expr)*;)+) => {
291
        #[derive(Copy, PartialEq, Eq, Clone)]
292 293 294 295 296 297
        pub enum Tool {
            $(
                $name,
            )+
        }

C
Collins Abitekaniza 已提交
298 299 300 301 302 303 304
        impl Tool {
            pub fn get_mode(&self) -> Mode {
                let mode = match self {
                    $(Tool::$name => $mode,)+
                };
                mode
            }
305 306 307 308

            /// Whether this tool requires LLVM to run
            pub fn uses_llvm_tools(&self) -> bool {
                match self {
309
                    $(Tool::$name => false $(|| $llvm)*,)+
310 311
                }
            }
C
Collins Abitekaniza 已提交
312 313
        }

314 315
        impl<'a> Builder<'a> {
            pub fn tool_exe(&self, tool: Tool) -> PathBuf {
316
                let stage = self.tool_default_stage(tool);
317 318 319
                match tool {
                    $(Tool::$name =>
                        self.ensure($name {
320 321
                            compiler: self.compiler(stage, self.config.build),
                            target: self.config.build,
322 323 324 325
                        }),
                    )+
                }
            }
326 327

            pub fn tool_default_stage(&self, tool: Tool) -> u32 {
328 329 330 331
                // Compile the error-index in the same stage as rustdoc to avoid
                // recompiling rustdoc twice if we can. Otherwise compile
                // everything else in stage0 as there's no need to rebootstrap
                // everything.
332
                match tool {
333
                    Tool::ErrorIndex if self.top_stage >= 2 => self.top_stage,
334 335 336
                    _ => 0,
                }
            }
337 338 339
        }

        $(
340 341
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
342
            pub compiler: Compiler,
343
            pub target: Interned<String>,
344 345
        }

346
        impl Step for $name {
347 348
            type Output = PathBuf;

349 350
            fn should_run(run: ShouldRun) -> ShouldRun {
                run.path($path)
351 352
            }

353 354
            fn make_run(run: RunConfig) {
                run.builder.ensure($name {
355
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
356
                    target: run.target,
357 358 359 360 361
                });
            }

            fn run(self, builder: &Builder) -> PathBuf {
                builder.ensure(ToolBuild {
362
                    compiler: self.compiler,
363 364 365
                    target: self.target,
                    tool: $tool_name,
                    mode: $mode,
366
                    path: $path,
367
                    is_ext_tool: false,
368
                    extra_features: Vec::new(),
369
                }).expect("expected to build -- essential tool")
370 371 372 373 374 375 376
            }
        }
        )+
    }
}

tool!(
377
    Rustbook, "src/tools/rustbook", "rustbook", Mode::ToolBootstrap;
C
Collins Abitekaniza 已提交
378
    ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::ToolRustc;
379 380 381 382 383 384 385 386 387
    UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::ToolBootstrap;
    Tidy, "src/tools/tidy", "tidy", Mode::ToolBootstrap;
    Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::ToolBootstrap;
    CargoTest, "src/tools/cargotest", "cargotest", Mode::ToolBootstrap;
    Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolBootstrap, llvm_tools = true;
    BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolBootstrap;
    RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolBootstrap;
    RustInstaller, "src/tools/rust-installer", "fabricate", Mode::ToolBootstrap;
    RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::ToolBootstrap;
388 389
);

390 391
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RemoteTestServer {
392
    pub compiler: Compiler,
393
    pub target: Interned<String>,
394 395
}

396
impl Step for RemoteTestServer {
397 398
    type Output = PathBuf;

399 400
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/tools/remote-test-server")
401 402
    }

403 404
    fn make_run(run: RunConfig) {
        run.builder.ensure(RemoteTestServer {
405
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
406
            target: run.target,
407 408 409 410 411
        });
    }

    fn run(self, builder: &Builder) -> PathBuf {
        builder.ensure(ToolBuild {
412
            compiler: self.compiler,
413 414
            target: self.target,
            tool: "remote-test-server",
A
Alex Crichton 已提交
415
            mode: Mode::ToolStd,
416
            path: "src/tools/remote-test-server",
417
            is_ext_tool: false,
418
            extra_features: Vec::new(),
419
        }).expect("expected to build -- essential tool")
420 421 422
    }
}

M
Mark Simulacrum 已提交
423 424
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Rustdoc {
425
    pub host: Interned<String>,
M
Mark Simulacrum 已提交
426 427 428 429 430 431 432 433 434 435 436 437 438
}

impl Step for Rustdoc {
    type Output = PathBuf;
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/tools/rustdoc")
    }

    fn make_run(run: RunConfig) {
        run.builder.ensure(Rustdoc {
439
            host: run.host,
M
Mark Simulacrum 已提交
440 441 442 443
        });
    }

    fn run(self, builder: &Builder) -> PathBuf {
444
        let target_compiler = builder.compiler(builder.top_stage, self.host);
445
        let target = target_compiler.host;
M
Mark Simulacrum 已提交
446
        let build_compiler = if target_compiler.stage == 0 {
447
            builder.compiler(0, builder.config.build)
448 449 450
        } else if target_compiler.stage >= 2 {
            // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of
            // building rustdoc itself.
451
            builder.compiler(target_compiler.stage, builder.config.build)
M
Mark Simulacrum 已提交
452
        } else {
453 454 455
            // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
            // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
            // compilers, which isn't what we want.
456
            builder.compiler(target_compiler.stage - 1, builder.config.build)
M
Mark Simulacrum 已提交
457 458
        };

459
        builder.ensure(compile::Rustc { compiler: build_compiler, target });
460 461
        builder.ensure(compile::Rustc {
            compiler: build_compiler,
462
            target: builder.config.build,
463
        });
464

465 466 467 468 469 470 471 472 473
        let mut cargo = prepare_tool_cargo(
            builder,
            build_compiler,
            Mode::ToolRustc,
            target,
            "build",
            "src/tools/rustdoc",
            false,
        );
474 475 476 477 478

        // Most tools don't get debuginfo, but rustdoc should.
        cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string())
             .env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string());

479 480
        let _folder = builder.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
        builder.info(&format!("Building rustdoc for stage{} ({})",
481
            target_compiler.stage, target_compiler.host));
482
        builder.run(&mut cargo);
483

484 485 486
        // Cargo adds a number of paths to the dylib search path on windows, which results in
        // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
        // rustdoc a different name.
C
Collins Abitekaniza 已提交
487
        let tool_rustdoc = builder.cargo_out(build_compiler, Mode::ToolRustc, target)
488
            .join(exe("rustdoc_tool_binary", &target_compiler.host));
M
Mark Simulacrum 已提交
489 490 491 492 493 494 495 496

        // don't create a stage0-sysroot/bin directory.
        if target_compiler.stage > 0 {
            let sysroot = builder.sysroot(target_compiler);
            let bindir = sysroot.join("bin");
            t!(fs::create_dir_all(&bindir));
            let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host));
            let _ = fs::remove_file(&bin_rustdoc);
497
            builder.copy(&tool_rustdoc, &bin_rustdoc);
M
Mark Simulacrum 已提交
498 499 500 501 502 503 504
            bin_rustdoc
        } else {
            tool_rustdoc
        }
    }
}

505 506
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Cargo {
507
    pub compiler: Compiler,
508
    pub target: Interned<String>,
509 510
}

511
impl Step for Cargo {
512 513 514 515
    type Output = PathBuf;
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

516
    fn should_run(run: ShouldRun) -> ShouldRun {
517
        let builder = run.builder;
518
        run.path("src/tools/cargo").default_condition(builder.config.extended)
519 520
    }

521 522
    fn make_run(run: RunConfig) {
        run.builder.ensure(Cargo {
523
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
524
            target: run.target,
525 526 527 528 529 530 531 532 533
        });
    }

    fn run(self, builder: &Builder) -> PathBuf {
        builder.ensure(native::Openssl {
            target: self.target,
        });
        // Cargo depends on procedural macros, which requires a full host
        // compiler to be available, so we need to depend on that.
534
        builder.ensure(compile::Rustc {
535
            compiler: self.compiler,
536
            target: builder.config.build,
537 538
        });
        builder.ensure(ToolBuild {
539
            compiler: self.compiler,
540 541
            target: self.target,
            tool: "cargo",
C
Collins Abitekaniza 已提交
542
            mode: Mode::ToolRustc,
543
            path: "src/tools/cargo",
544
            is_ext_tool: false,
545
            extra_features: Vec::new(),
546
        }).expect("expected to build -- essential tool")
547 548 549
    }
}

550 551 552 553 554 555 556 557
macro_rules! tool_extended {
    (($sel:ident, $builder:ident),
       $($name:ident,
       $toolstate:ident,
       $path:expr,
       $tool_name:expr,
       $extra_deps:block;)+) => {
        $(
558
            #[derive(Debug, Clone, Hash, PartialEq, Eq)]
559 560 561
        pub struct $name {
            pub compiler: Compiler,
            pub target: Interned<String>,
562
            pub extra_features: Vec<String>,
563
        }
O
Oliver Schneider 已提交
564

565 566 567 568
        impl Step for $name {
            type Output = Option<PathBuf>;
            const DEFAULT: bool = true;
            const ONLY_HOSTS: bool = true;
O
Oliver Schneider 已提交
569

570 571
            fn should_run(run: ShouldRun) -> ShouldRun {
                let builder = run.builder;
572
                run.path($path).default_condition(builder.config.extended)
573
            }
O
Oliver Schneider 已提交
574

575 576
            fn make_run(run: RunConfig) {
                run.builder.ensure($name {
577
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
578
                    target: run.target,
579
                    extra_features: Vec::new(),
580 581 582
                });
            }

583 584
            #[allow(unused_mut)]
            fn run(mut $sel, $builder: &Builder) -> Option<PathBuf> {
585 586 587 588 589
                $extra_deps
                $builder.ensure(ToolBuild {
                    compiler: $sel.compiler,
                    target: $sel.target,
                    tool: $tool_name,
C
Collins Abitekaniza 已提交
590
                    mode: Mode::ToolRustc,
591
                    path: $path,
592
                    extra_features: $sel.extra_features,
593
                    is_ext_tool: true,
594 595 596 597
                })
            }
        }
        )+
O
Oliver Schneider 已提交
598
    }
599
}
O
Oliver Schneider 已提交
600

601
tool_extended!((self, builder),
602
    Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {};
O
Oliver Schneider 已提交
603 604 605 606 607 608 609 610
    CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", {
        // Clippy depends on procedural macros (serde), which requires a full host
        // compiler to be available, so we need to depend on that.
        builder.ensure(compile::Rustc {
            compiler: self.compiler,
            target: builder.config.build,
        });
    };
611
    Clippy, clippy, "src/tools/clippy", "clippy-driver", {
O
Oliver Schneider 已提交
612 613 614 615
        // Clippy depends on procedural macros (serde), which requires a full host
        // compiler to be available, so we need to depend on that.
        builder.ensure(compile::Rustc {
            compiler: self.compiler,
616
            target: builder.config.build,
O
Oliver Schneider 已提交
617
        });
618 619 620
    };
    Miri, miri, "src/tools/miri", "miri", {};
    Rls, rls, "src/tools/rls", "rls", {
621 622 623 624 625
        let clippy = builder.ensure(Clippy {
            compiler: self.compiler,
            target: self.target,
            extra_features: Vec::new(),
        });
626
        if clippy.is_some() {
627 628
            self.extra_features.push("clippy".to_owned());
        }
629 630 631 632 633
        builder.ensure(native::Openssl {
            target: self.target,
        });
        // RLS depends on procedural macros, which requires a full host
        // compiler to be available, so we need to depend on that.
634
        builder.ensure(compile::Rustc {
635
            compiler: self.compiler,
636
            target: builder.config.build,
637
        });
638 639 640
    };
    Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {};
);
641

M
Mark Simulacrum 已提交
642 643 644
impl<'a> Builder<'a> {
    /// Get a `Command` which is ready to run `tool` in `stage` built for
    /// `host`.
M
Mark Simulacrum 已提交
645 646
    pub fn tool_cmd(&self, tool: Tool) -> Command {
        let mut cmd = Command::new(self.tool_exe(tool));
647
        let compiler = self.compiler(self.tool_default_stage(tool), self.config.build);
648
        self.prepare_tool_cmd(compiler, tool, &mut cmd);
M
Mark Simulacrum 已提交
649 650 651 652 653 654 655
        cmd
    }

    /// Prepares the `cmd` provided to be able to run the `compiler` provided.
    ///
    /// Notably this munges the dynamic library lookup path to point to the
    /// right location to run `compiler`.
656
    fn prepare_tool_cmd(&self, compiler: Compiler, tool: Tool, cmd: &mut Command) {
657
        let host = &compiler.host;
658
        let mut lib_paths: Vec<PathBuf> = vec![
659
            if compiler.stage == 0 && tool != Tool::ErrorIndex {
660 661 662 663
                self.build.rustc_snapshot_libdir()
            } else {
                PathBuf::from(&self.sysroot_libdir(compiler, compiler.host))
            },
664
            self.cargo_out(compiler, tool.get_mode(), *host).join("deps"),
M
Mark Simulacrum 已提交
665 666 667 668 669 670
        ];

        // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
        // mode) and that C compiler may need some extra PATH modification. Do
        // so here.
        if compiler.host.contains("msvc") {
M
Mark Simulacrum 已提交
671
            let curpaths = env::var_os("PATH").unwrap_or_default();
M
Mark Simulacrum 已提交
672
            let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
673
            for &(ref k, ref v) in self.cc[&compiler.host].env() {
M
Mark Simulacrum 已提交
674 675 676 677 678
                if k != "PATH" {
                    continue
                }
                for path in env::split_paths(v) {
                    if !curpaths.contains(&path) {
679
                        lib_paths.push(path);
M
Mark Simulacrum 已提交
680 681 682 683
                    }
                }
            }
        }
684 685 686

        // Add the llvm/bin directory to PATH since it contains lots of
        // useful, platform-independent tools
687 688 689 690 691 692 693 694 695 696 697 698 699
        if tool.uses_llvm_tools() {
            if let Some(llvm_bin_path) = self.llvm_bin_path() {
                if host.contains("windows") {
                    // On Windows, PATH and the dynamic library path are the same,
                    // so we just add the LLVM bin path to lib_path
                    lib_paths.push(llvm_bin_path);
                } else {
                    let old_path = env::var_os("PATH").unwrap_or_default();
                    let new_path = env::join_paths(iter::once(llvm_bin_path)
                            .chain(env::split_paths(&old_path)))
                        .expect("Could not add LLVM bin path to PATH");
                    cmd.env("PATH", new_path);
                }
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
            }
        }

        add_lib_path(lib_paths, cmd);
    }

    fn llvm_bin_path(&self) -> Option<PathBuf> {
        if self.config.llvm_enabled && !self.config.dry_run {
            let llvm_config = self.ensure(native::Llvm {
                target: self.config.build,
                emscripten: false,
            });

            // Add the llvm/bin directory to PATH since it contains lots of
            // useful, platform-independent tools
            let llvm_bin_path = llvm_config.parent()
                .expect("Expected llvm-config to be contained in directory");
            assert!(llvm_bin_path.is_dir());
            Some(llvm_bin_path.to_path_buf())
        } else {
            None
        }
M
Mark Simulacrum 已提交
722 723
    }
}