tool.rs 13.8 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::path::PathBuf;
14 15 16
use std::process::Command;

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

25
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
26 27 28 29
struct CleanTools {
    compiler: Compiler,
    target: Interned<String>,
    mode: Mode,
30 31
}

32
impl Step for CleanTools {
33 34
    type Output = ();

35 36
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
37 38
    }

39 40 41 42 43 44
    /// 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.
    fn run(self, builder: &Builder) {
        let build = builder.build;
45
        let compiler = self.compiler;
46 47 48 49
        let target = self.target;
        let mode = self.mode;

        let stamp = match mode {
50 51 52
            Mode::Libstd => libstd_stamp(build, compiler, target),
            Mode::Libtest => libtest_stamp(build, compiler, target),
            Mode::Librustc => librustc_stamp(build, compiler, target),
53 54
            _ => panic!(),
        };
55
        let out_dir = build.cargo_out(compiler, Mode::Tool, target);
56 57 58 59
        build.clear_if_dirty(&out_dir, &stamp);
    }
}

60
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
61 62 63 64 65
struct ToolBuild {
    compiler: Compiler,
    target: Interned<String>,
    tool: &'static str,
    mode: Mode,
66 67
}

68
impl Step for ToolBuild {
69
    type Output = PathBuf;
70

71 72
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
73 74
    }

75 76 77 78
    /// 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.
79
    fn run(self, builder: &Builder) -> PathBuf {
80
        let build = builder.build;
81
        let compiler = self.compiler;
82 83 84
        let target = self.target;
        let tool = self.tool;

85
        builder.ensure(CleanTools { compiler, target, mode: self.mode });
86 87 88 89 90 91 92
        match self.mode {
            Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
            Mode::Libtest => builder.ensure(compile::Test { compiler, target }),
            Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }),
            Mode::Tool => panic!("unexpected Mode::Tool for tool build")
        }

93 94
        let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
        println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
95

96 97 98 99 100
        let mut cargo = prepare_tool_cargo(builder, compiler, target, tool);
        build.run(&mut cargo);
        build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
    }
}
101

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
fn prepare_tool_cargo(
    builder: &Builder,
    compiler: Compiler,
    target: Interned<String>,
    tool: &'static str,
) -> Command {
    let build = builder.build;
    let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
    let dir = build.src.join("src/tools").join(tool);
    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");

    if let Some(dir) = build.openssl_install_dir(target) {
        cargo.env("OPENSSL_STATIC", "1");
        cargo.env("OPENSSL_DIR", dir);
        cargo.env("LIBZ_SYS_STATIC", "1");
    }
122

123
    cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
124

125 126 127 128 129 130 131 132 133
    let info = GitInfo::new(&build.config, &dir);
    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);
134
    }
135
    cargo
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
}

macro_rules! tool {
    ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
        #[derive(Copy, Clone)]
        pub enum Tool {
            $(
                $name,
            )+
        }

        impl<'a> Builder<'a> {
            pub fn tool_exe(&self, tool: Tool) -> PathBuf {
                match tool {
                    $(Tool::$name =>
                        self.ensure($name {
152
                            compiler: self.compiler(0, self.build.build),
153
                            target: self.build.build,
154 155 156 157 158 159 160
                        }),
                    )+
                }
            }
        }

        $(
161 162
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
163
            pub compiler: Compiler,
164
            pub target: Interned<String>,
165 166
        }

167
        impl Step for $name {
168 169
            type Output = PathBuf;

170 171
            fn should_run(run: ShouldRun) -> ShouldRun {
                run.path($path)
172 173
            }

174 175
            fn make_run(run: RunConfig) {
                run.builder.ensure($name {
176
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
177
                    target: run.target,
178 179 180 181 182
                });
            }

            fn run(self, builder: &Builder) -> PathBuf {
                builder.ensure(ToolBuild {
183
                    compiler: self.compiler,
184 185 186 187 188 189 190 191 192 193 194 195 196
                    target: self.target,
                    tool: $tool_name,
                    mode: $mode,
                })
            }
        }
        )+
    }
}

tool!(
    Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc;
    ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc;
197
    UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd;
198 199 200 201
    Tidy, "src/tools/tidy", "tidy", Mode::Libstd;
    Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd;
    CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd;
    Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
M
Mark Simulacrum 已提交
202
    BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Librustc;
203 204 205 206
    RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
    RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
);

207 208
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RemoteTestServer {
209
    pub compiler: Compiler,
210
    pub target: Interned<String>,
211 212
}

213
impl Step for RemoteTestServer {
214 215
    type Output = PathBuf;

216 217
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/tools/remote-test-server")
218 219
    }

220 221
    fn make_run(run: RunConfig) {
        run.builder.ensure(RemoteTestServer {
222
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
223
            target: run.target,
224 225 226 227 228
        });
    }

    fn run(self, builder: &Builder) -> PathBuf {
        builder.ensure(ToolBuild {
229
            compiler: self.compiler,
230 231 232 233 234 235 236
            target: self.target,
            tool: "remote-test-server",
            mode: Mode::Libstd,
        })
    }
}

M
Mark Simulacrum 已提交
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Rustdoc {
    pub target_compiler: Compiler,
}

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 {
            target_compiler: run.builder.compiler(run.builder.top_stage, run.host),
        });
    }

    fn run(self, builder: &Builder) -> PathBuf {
258
        let build = builder.build;
M
Mark Simulacrum 已提交
259
        let target_compiler = self.target_compiler;
260
        let target = target_compiler.host;
M
Mark Simulacrum 已提交
261
        let build_compiler = if target_compiler.stage == 0 {
262
            builder.compiler(0, builder.build.build)
263 264 265 266
        } else if target_compiler.stage >= 2 {
            // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of
            // building rustdoc itself.
            target_compiler
M
Mark Simulacrum 已提交
267
        } else {
268 269 270
            // 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.
271
            builder.compiler(target_compiler.stage - 1, builder.build.build)
M
Mark Simulacrum 已提交
272 273
        };

274 275 276 277 278 279 280 281 282 283
        builder.ensure(CleanTools { compiler: build_compiler, target, mode: Mode::Librustc });
        builder.ensure(compile::Rustc { compiler: build_compiler, target });

        let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
        println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host);

        let mut cargo = prepare_tool_cargo(builder, build_compiler, target, "rustdoc");
        build.run(&mut cargo);
        let tool_rustdoc = build.cargo_out(build_compiler, Mode::Tool, target)
            .join(exe("rustdoc", &target_compiler.host));
M
Mark Simulacrum 已提交
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

        // 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);
            copy(&tool_rustdoc, &bin_rustdoc);
            bin_rustdoc
        } else {
            tool_rustdoc
        }
    }
}

300 301
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Cargo {
302
    pub compiler: Compiler,
303
    pub target: Interned<String>,
304 305
}

306
impl Step for Cargo {
307 308 309 310
    type Output = PathBuf;
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

311
    fn should_run(run: ShouldRun) -> ShouldRun {
312 313
        let builder = run.builder;
        run.path("src/tools/cargo").default_condition(builder.build.config.extended)
314 315
    }

316 317
    fn make_run(run: RunConfig) {
        run.builder.ensure(Cargo {
318
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
319
            target: run.target,
320 321 322 323 324 325 326 327 328
        });
    }

    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.
329
        builder.ensure(compile::Rustc {
330
            compiler: self.compiler,
331
            target: builder.build.build,
332 333
        });
        builder.ensure(ToolBuild {
334
            compiler: self.compiler,
335 336
            target: self.target,
            tool: "cargo",
A
Alex Crichton 已提交
337
            mode: Mode::Librustc,
338 339 340 341
        })
    }
}

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

348
impl Step for Rls {
349 350 351 352
    type Output = PathBuf;
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

353
    fn should_run(run: ShouldRun) -> ShouldRun {
354 355
        let builder = run.builder;
        run.path("src/tools/rls").default_condition(builder.build.config.extended)
356 357
    }

358 359
    fn make_run(run: RunConfig) {
        run.builder.ensure(Rls {
360
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
361
            target: run.target,
362 363 364 365 366 367 368 369 370
        });
    }

    fn run(self, builder: &Builder) -> PathBuf {
        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.
371
        builder.ensure(compile::Rustc {
372
            compiler: self.compiler,
373
            target: builder.build.build,
374 375
        });
        builder.ensure(ToolBuild {
376
            compiler: self.compiler,
377 378 379 380
            target: self.target,
            tool: "rls",
            mode: Mode::Librustc,
        })
381 382
    }
}
M
Mark Simulacrum 已提交
383 384 385 386

impl<'a> Builder<'a> {
    /// Get a `Command` which is ready to run `tool` in `stage` built for
    /// `host`.
M
Mark Simulacrum 已提交
387 388
    pub fn tool_cmd(&self, tool: Tool) -> Command {
        let mut cmd = Command::new(self.tool_exe(tool));
389
        let compiler = self.compiler(0, self.build.build);
M
Mark Simulacrum 已提交
390 391 392 393 394 395 396 397 398
        self.prepare_tool_cmd(compiler, &mut cmd);
        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`.
    fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
399 400 401 402
        let host = &compiler.host;
        let mut paths: Vec<PathBuf> = vec![
            PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)),
            self.cargo_out(compiler, Mode::Tool, *host).join("deps"),
M
Mark Simulacrum 已提交
403 404 405 406 407 408
        ];

        // 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 已提交
409
            let curpaths = env::var_os("PATH").unwrap_or_default();
M
Mark Simulacrum 已提交
410
            let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
411
            for &(ref k, ref v) in self.cc[&compiler.host].0.env() {
M
Mark Simulacrum 已提交
412 413 414 415 416 417 418 419 420 421 422 423 424
                if k != "PATH" {
                    continue
                }
                for path in env::split_paths(v) {
                    if !curpaths.contains(&path) {
                        paths.push(path);
                    }
                }
            }
        }
        add_lib_path(paths, cmd);
    }
}