tool.rs 12.7 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
        let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
        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");
        }

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

        let info = GitInfo::new(&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);
        }

        build.run(&mut cargo);
124
        build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    }
}

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 {
142
                            compiler: self.compiler(0, self.build.build),
143
                            target: self.build.build,
144 145 146 147 148 149 150
                        }),
                    )+
                }
            }
        }

        $(
151 152
            #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        pub struct $name {
153
            pub compiler: Compiler,
154
            pub target: Interned<String>,
155 156
        }

157
        impl Step for $name {
158 159
            type Output = PathBuf;

160 161
            fn should_run(run: ShouldRun) -> ShouldRun {
                run.path($path)
162 163
            }

164 165
            fn make_run(run: RunConfig) {
                run.builder.ensure($name {
166
                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
167
                    target: run.target,
168 169 170 171 172
                });
            }

            fn run(self, builder: &Builder) -> PathBuf {
                builder.ensure(ToolBuild {
173
                    compiler: self.compiler,
174 175 176 177 178 179 180 181 182 183 184 185 186
                    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;
187
    UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd;
188 189 190 191
    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 已提交
192
    BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Librustc;
193 194 195 196
    RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
    RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
);

197 198
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RemoteTestServer {
199
    pub compiler: Compiler,
200
    pub target: Interned<String>,
201 202
}

203
impl Step for RemoteTestServer {
204 205
    type Output = PathBuf;

206 207
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/tools/remote-test-server")
208 209
    }

210 211
    fn make_run(run: RunConfig) {
        run.builder.ensure(RemoteTestServer {
212
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
213
            target: run.target,
214 215 216 217 218
        });
    }

    fn run(self, builder: &Builder) -> PathBuf {
        builder.ensure(ToolBuild {
219
            compiler: self.compiler,
220 221 222 223 224 225 226
            target: self.target,
            tool: "remote-test-server",
            mode: Mode::Libstd,
        })
    }
}

M
Mark Simulacrum 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
#[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 {
        let target_compiler = self.target_compiler;
        let build_compiler = if target_compiler.stage == 0 {
            target_compiler
        } else {
            builder.compiler(target_compiler.stage - 1, target_compiler.host)
        };

        let tool_rustdoc = builder.ensure(ToolBuild {
            compiler: build_compiler,
            target: build_compiler.host,
            tool: "rustdoc",
            mode: Mode::Librustc,
        });

        // 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
        }
    }
}

277 278
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Cargo {
279
    pub compiler: Compiler,
280
    pub target: Interned<String>,
281 282
}

283
impl Step for Cargo {
284 285 286 287
    type Output = PathBuf;
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

288
    fn should_run(run: ShouldRun) -> ShouldRun {
289 290
        let builder = run.builder;
        run.path("src/tools/cargo").default_condition(builder.build.config.extended)
291 292
    }

293 294
    fn make_run(run: RunConfig) {
        run.builder.ensure(Cargo {
295
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
296
            target: run.target,
297 298 299 300 301 302 303 304 305
        });
    }

    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.
306
        builder.ensure(compile::Rustc {
307
            compiler: self.compiler,
308
            target: builder.build.build,
309 310
        });
        builder.ensure(ToolBuild {
311
            compiler: self.compiler,
312 313
            target: self.target,
            tool: "cargo",
A
Alex Crichton 已提交
314
            mode: Mode::Librustc,
315 316 317 318
        })
    }
}

319 320
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Rls {
321
    pub compiler: Compiler,
322
    pub target: Interned<String>,
323 324
}

325
impl Step for Rls {
326 327 328 329
    type Output = PathBuf;
    const DEFAULT: bool = true;
    const ONLY_HOSTS: bool = true;

330
    fn should_run(run: ShouldRun) -> ShouldRun {
331 332
        let builder = run.builder;
        run.path("src/tools/rls").default_condition(builder.build.config.extended)
333 334
    }

335 336
    fn make_run(run: RunConfig) {
        run.builder.ensure(Rls {
337
            compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
338
            target: run.target,
339 340 341 342 343 344 345 346 347
        });
    }

    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.
348
        builder.ensure(compile::Rustc {
349
            compiler: self.compiler,
350
            target: builder.build.build,
351 352
        });
        builder.ensure(ToolBuild {
353
            compiler: self.compiler,
354 355 356 357
            target: self.target,
            tool: "rls",
            mode: Mode::Librustc,
        })
358 359
    }
}
M
Mark Simulacrum 已提交
360 361 362 363

impl<'a> Builder<'a> {
    /// Get a `Command` which is ready to run `tool` in `stage` built for
    /// `host`.
M
Mark Simulacrum 已提交
364 365
    pub fn tool_cmd(&self, tool: Tool) -> Command {
        let mut cmd = Command::new(self.tool_exe(tool));
366
        let compiler = self.compiler(0, self.build.build);
M
Mark Simulacrum 已提交
367 368 369 370 371 372 373 374 375
        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) {
376 377 378 379
        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 已提交
380 381 382 383 384 385
        ];

        // 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 已提交
386
            let curpaths = env::var_os("PATH").unwrap_or_default();
M
Mark Simulacrum 已提交
387
            let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
388
            for &(ref k, ref v) in self.cc[&compiler.host].0.env() {
M
Mark Simulacrum 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401
                if k != "PATH" {
                    continue
                }
                for path in env::split_paths(v) {
                    if !curpaths.contains(&path) {
                        paths.push(path);
                    }
                }
            }
        }
        add_lib_path(paths, cmd);
    }
}