blob: 7c0f09c322f24cffa5bd39a0d515bc873a77a22f [file] [log] [blame]
// Copyright 2015 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.
//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!
use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;
use build_helper::output;
use Build;
pub fn check(build: &mut Build) {
let mut checked = HashSet::new();
let path = env::var_os("PATH").unwrap_or(OsString::new());
let mut need_cmd = |cmd: &OsStr| {
if !checked.insert(cmd.to_owned()) {
return
}
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
if fs::metadata(&path).is_ok() ||
fs::metadata(path.with_extension("exe")).is_ok() {
return
}
}
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
};
// If we've got a git directory we're gona need git to update
// submodules and learn about various other aspects.
if fs::metadata(build.src.join(".git")).is_ok() {
need_cmd("git".as_ref());
}
// We need cmake, but only if we're actually building LLVM
for host in build.config.host.iter() {
if let Some(config) = build.config.target_config.get(host) {
if config.llvm_config.is_some() {
continue
}
}
need_cmd("cmake".as_ref());
if build.config.ninja {
need_cmd("ninja".as_ref())
}
break
}
need_cmd("python".as_ref());
// We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() {
need_cmd(build.cc(target).as_ref());
if let Some(ar) = build.ar(target) {
need_cmd(ar.as_ref());
}
}
for host in build.config.host.iter() {
need_cmd(build.cxx(host).as_ref());
}
// Externally configured LLVM requires FileCheck to exist
let filecheck = build.llvm_filecheck(&build.config.build);
if !filecheck.starts_with(&build.out) && !filecheck.exists() {
panic!("filecheck executable {:?} does not exist", filecheck);
}
for target in build.config.target.iter() {
// Either can't build or don't want to run jemalloc on these targets
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
target.contains("msvc") {
build.config.use_jemalloc = false;
}
// Can't compile for iOS unless we're on OSX
if target.contains("apple-ios") &&
!build.config.build.contains("apple-darwin") {
panic!("the iOS target is only supported on OSX");
}
// Make sure musl-root is valid if specified
if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
match build.config.musl_root {
Some(ref root) => {
if fs::metadata(root.join("lib/libc.a")).is_err() {
panic!("couldn't find libc.a in musl dir: {}",
root.join("lib").display());
}
if fs::metadata(root.join("lib/libunwind.a")).is_err() {
panic!("couldn't find libunwind.a in musl dir: {}",
root.join("lib").display());
}
}
None => {
panic!("when targeting MUSL the build.musl-root option \
must be specified in config.toml")
}
}
}
if target.contains("msvc") {
// There are three builds of cmake on windows: MSVC, MinGW, and
// Cygwin. The Cygwin build does not have generators for Visual
// Studio, so detect that here and error.
let out = output(Command::new("cmake").arg("--help"));
if !out.contains("Visual Studio") {
panic!("
cmake does not support Visual Studio generators.
This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.
If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:
$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
}
}
if target.contains("arm-linux-android") {
need_cmd("adb".as_ref());
}
}
for host in build.flags.host.iter() {
if !build.config.host.contains(host) {
panic!("specified host `{}` is not in the ./configure list", host);
}
}
for target in build.flags.target.iter() {
if !build.config.target.contains(target) {
panic!("specified target `{}` is not in the ./configure list",
target);
}
}
let run = |cmd: &mut Command| {
cmd.output().map(|output| {
String::from_utf8_lossy(&output.stdout)
.lines().next().unwrap()
.to_string()
})
};
build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
if build.lldb_version.is_some() {
build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
}
}