about summary refs log tree commit diff
path: root/src/bootstrap/cc.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2016-07-05 21:58:20 -0700
committerAlex Crichton <alex@alexcrichton.com>2016-07-05 21:58:20 -0700
commit48a07bfb958a48da0c909f4607eb0cf9118fc902 (patch)
treebcf2be99d136b0f4a7a66061bc0002025a1e1d9d /src/bootstrap/cc.rs
parentec58d0c9976c18c405a59d26252a1fa7a3e2a742 (diff)
rustbuild: Remove the `build` directory
The organization in rustbuild was a little odd at the moment where the `lib.rs`
was quite small but the binary `main.rs` was much larger. Unfortunately as well
there was a `build/` directory with the implementation of the build system, but
this directory was ignored by GitHub on the file-search prompt which was a
little annoying.

This commit reorganizes rustbuild slightly where all the library files (the
build system) is located directly inside of `src/bootstrap` and all the binaries
now live in `src/bootstrap/bin` (they're small). Hopefully this should allow
GitHub to index and allow navigating all the files while maintaining a
relatively similar layout to the other libraries in `src/`.
Diffstat (limited to 'src/bootstrap/cc.rs')
-rw-r--r--src/bootstrap/cc.rs124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/bootstrap/cc.rs b/src/bootstrap/cc.rs
new file mode 100644
index 00000000000..e2bde4a6586
--- /dev/null
+++ b/src/bootstrap/cc.rs
@@ -0,0 +1,124 @@
+// 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.
+
+//! C-compiler probing and detection.
+//!
+//! This module will fill out the `cc` and `cxx` maps of `Build` by looking for
+//! C and C++ compilers for each target configured. A compiler is found through
+//! a number of vectors (in order of precedence)
+//!
+//! 1. Configuration via `target.$target.cc` in `config.toml`.
+//! 2. Configuration via `target.$target.android-ndk` in `config.toml`, if
+//!    applicable
+//! 3. Special logic to probe on OpenBSD
+//! 4. The `CC_$target` environment variable.
+//! 5. The `CC` environment variable.
+//! 6. "cc"
+//!
+//! Some of this logic is implemented here, but much of it is farmed out to the
+//! `gcc` crate itself, so we end up having the same fallbacks as there.
+//! Similar logic is then used to find a C++ compiler, just some s/cc/c++/ is
+//! used.
+//!
+//! It is intended that after this module has run no C/C++ compiler will
+//! ever be probed for. Instead the compilers found here will be used for
+//! everything.
+
+use std::process::Command;
+
+use build_helper::{cc2ar, output};
+use gcc;
+
+use Build;
+use config::Target;
+
+pub fn find(build: &mut Build) {
+    // For all targets we're going to need a C compiler for building some shims
+    // and such as well as for being a linker for Rust code.
+    for target in build.config.target.iter() {
+        let mut cfg = gcc::Config::new();
+        cfg.cargo_metadata(false).opt_level(0).debug(false)
+           .target(target).host(&build.config.build);
+
+        let config = build.config.target_config.get(target);
+        if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
+            cfg.compiler(cc);
+        } else {
+            set_compiler(&mut cfg, "gcc", target, config);
+        }
+
+        let compiler = cfg.get_compiler();
+        let ar = cc2ar(compiler.path(), target);
+        build.verbose(&format!("CC_{} = {:?}", target, compiler.path()));
+        if let Some(ref ar) = ar {
+            build.verbose(&format!("AR_{} = {:?}", target, ar));
+        }
+        build.cc.insert(target.to_string(), (compiler, ar));
+    }
+
+    // For all host triples we need to find a C++ compiler as well
+    for host in build.config.host.iter() {
+        let mut cfg = gcc::Config::new();
+        cfg.cargo_metadata(false).opt_level(0).debug(false).cpp(true)
+           .target(host).host(&build.config.build);
+        let config = build.config.target_config.get(host);
+        if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
+            cfg.compiler(cxx);
+        } else {
+            set_compiler(&mut cfg, "g++", host, config);
+        }
+        let compiler = cfg.get_compiler();
+        build.verbose(&format!("CXX_{} = {:?}", host, compiler.path()));
+        build.cxx.insert(host.to_string(), compiler);
+    }
+}
+
+fn set_compiler(cfg: &mut gcc::Config,
+                gnu_compiler: &str,
+                target: &str,
+                config: Option<&Target>) {
+    match target {
+        // When compiling for android we may have the NDK configured in the
+        // config.toml in which case we look there. Otherwise the default
+        // compiler already takes into account the triple in question.
+        t if t.contains("android") => {
+            if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
+                let target = target.replace("armv7", "arm");
+                let compiler = format!("{}-{}", target, gnu_compiler);
+                cfg.compiler(ndk.join("bin").join(compiler));
+            }
+        }
+
+        // The default gcc version from OpenBSD may be too old, try using egcc,
+        // which is a gcc version from ports, if this is the case.
+        t if t.contains("openbsd") => {
+            let c = cfg.get_compiler();
+            if !c.path().ends_with(gnu_compiler) {
+                return
+            }
+
+            let output = output(c.to_command().arg("--version"));
+            let i = match output.find(" 4.") {
+                Some(i) => i,
+                None => return,
+            };
+            match output[i + 3..].chars().next().unwrap() {
+                '0' ... '6' => {}
+                _ => return,
+            }
+            let alternative = format!("e{}", gnu_compiler);
+            if Command::new(&alternative).output().is_ok() {
+                cfg.compiler(alternative);
+            }
+        }
+
+        _ => {}
+    }
+}