diff options
| author | bors <bors@rust-lang.org> | 2016-02-12 00:19:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-02-12 00:19:13 +0000 |
| commit | 78a5d5b54e0ff91bda8518df7ed9673cc657a4e6 (patch) | |
| tree | 2dc5ef96a9649578b8bf41b417a22b1f61fea215 /src | |
| parent | 98ec51a4ddc5519f809d667e7dbbf636d59ab653 (diff) | |
| parent | 55dd595c081f76c90f212811ccb55fdf0861784b (diff) | |
| download | rust-78a5d5b54e0ff91bda8518df7ed9673cc657a4e6.tar.gz rust-78a5d5b54e0ff91bda8518df7ed9673cc657a4e6.zip | |
Auto merge of #31123 - alexcrichton:who-doesnt-want-two-build-systems, r=brson
This series of commits adds the initial implementation of a new build system for the compiler and standard library based on Cargo. The high-level architecture now looks like: 1. The `./configure` script is run with `--enable-rustbuild` and other standard configuration options. 2. A `Makefile` is generate which proxies commands to the new build system. 3. The new build system has a Python script entry point which manages downloading both a Rust and Cargo nightly. This initial script also manages building the build system itself (which is written in Rust). 4. The build system, written in rust and called `bootstrap`, architects how to call `cargo` and manages building all native libraries and such. One might reasonably ask "why rewrite the build system?", which is a good question! The Rust project has used Makefiles for as long as I can remember at least, and while ugly and difficult to use are undeniably robust as they contain years worth of tweaking and tuning for working on as many platforms in as many situation as possible. The rationale behind this PR, however is: * The makefiles are impenetrable to all but a few people on this planet. This means that contributions to the build system are almost nonexistent, and furthermore if a build system change is needed it's incredibly difficult to figure out how to do so. This hindrance prevents us from doing some "perhaps fancier" things we may wish to do in make. * Our build system, while portable, is unfortunately not infinitely portable everywhere. For example the recently-introduced MSVC target is quite unlikely to have `make` installed by default (e.g. it requires building inside of an MSYS2 shell currently). Conversely, the portability of make comes at a cost of crazy and weird hacks to work around all sorts of versions of software everywhere, especially when it comes to the configure script and makefiles. By rewriting this logic in one of the most robust platforms there is, Rust, we get to assuage all of these worries for free! * There's a standard tool to build Rust crates, Cargo, but the standard library and compiler don't use it. This means that they cannot benefit easily from the crates.io ecosystem, nor can the ecosystem benefit from a standard way to build this repository itself. Moving to Cargo should help assuage both of these needs. This has the added benefit of making the compiler more approachable for newbies as working on the compiler will just happen to be working on a large Cargo project, all the same standard tools and tricks will apply. * There's a huge amount of portability information in the main distribution, for example around cross compiling, compiling on new OSes, etc. Pushing this logic into standard crates (like `gcc`) enables the community to immediately benefit from new build logic. Despite these benefits, it's going to be a long road to actually replace our current build system. This PR is just the beginning and doesn't implement the full suite of functionality as the current one, but there are many more to follow! The current implementation strategy hopes to look like: 1. Land a second build system in-tree that can be itereated on an and contributed to. This will not be used just yet in terms of gating new commits to the repo. 2. Over time, bring the second build system to feature parity with the old build system, start setting up CI for both build systems. 3. At some point in the future, switch the default to the new build system, but keep the old one around. 4. At some further point in the future, delete the entire old build system. --- Alright, so with all that out of the way, here's some more info on this PR itself. The inital build system here is contained in the `src/bootstrap` directory and just adds the necessary minimum bits to bootstrap the compiler itself. There is currently no support for building documentation, running tests, or installing, but the implemented support is: * Compiling LLVM with `cmake` instead of `./configure` + `make`. The LLVM project is removing their autotools build system, so we'd have to make this transition eventually anyway. * Compiling compiler-rt with `cmake` as well (for the same rationale as above). * Adding `Cargo.toml` to map out the dependency graph to all crates, and also adding `build.rs` files where appropriate. For example `alloc_jemalloc` has a script to build jemalloc, `flate` has a script to build `miniz.c`, `std` will build `libbacktrace`, etc. * Orchestrating all the calls to `cargo` to build the standard distribution, following the normal bootstrapping process. This also tracks dependencies between steps to ensure cross-compilation targets happen as well. * Configuration is intended to eventually be done through a `config.toml` file, so support is implemented for this. The most likely vector of configuration for now, however, is likely through `config.mk` (what `./configure` emits), so the build system currently parses this information. There's still quite a few steps left to do, and I'll open up some follow-up issues (as well as a tracking issue) for this migration, but hopefully this is a great start to get going! This PR is currently tested on all the Windows/Linux/OSX triples for x86\_64 and x86, but more portability is always welcome! --- Future functionality left to implement * [ ] Re-verify that multi-host builds work * [ ] Verify android build works * [ ] Verify iOS build work (mostly compiler-rt) * [ ] Verify sha256 and ideally gpg of downloaded nightly compiler and nightly rustc * [ ] Implement testing -- this is a huge bullet point with lots of sub-bullets * [ ] Build and generate documentation (plus the various tools we have in-tree) * [ ] Move various src/etc scripts into Rust -- not sure how this interacts with `make` build system * [ ] Implement `make install` - like testing this is also quite massive * [x] Deduplicate version information with makefiles
Diffstat (limited to 'src')
90 files changed, 4579 insertions, 88 deletions
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock new file mode 100644 index 00000000000..f9593eb1609 --- /dev/null +++ b/src/bootstrap/Cargo.lock @@ -0,0 +1,109 @@ +[root] +name = "bootstrap" +version = "0.0.0" +dependencies = [ + "build_helper 0.1.0", + "cmake 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "advapi32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "build_helper" +version = "0.1.0" + +[[package]] +name = "cmake" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "filetime" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gcc" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getopts" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "kernel32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num_cpus" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "toml" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml new file mode 100644 index 00000000000..8321f93c90f --- /dev/null +++ b/src/bootstrap/Cargo.toml @@ -0,0 +1,29 @@ +[package] +authors = ["The Rust Project Developers"] +name = "bootstrap" +version = "0.0.0" + +[lib] +name = "bootstrap" +path = "lib.rs" + +[[bin]] +name = "bootstrap" +path = "main.rs" + +[[bin]] +name = "rustc" +path = "rustc.rs" + +[dependencies] +build_helper = { path = "../build_helper" } +cmake = "0.1.10" +filetime = "0.1" +num_cpus = "0.2" +toml = "0.1" +getopts = "0.2" +rustc-serialize = "0.3" +winapi = "0.2" +kernel32-sys = "0.2" +gcc = "0.3.17" +libc = "0.2" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md new file mode 100644 index 00000000000..9e97ec4da07 --- /dev/null +++ b/src/bootstrap/README.md @@ -0,0 +1,110 @@ +# Bootstrapping Rust + +This is an in-progress README which is targeted at helping to explain how Rust +is bootstrapped and in general some of the technical details of the build +system. + +> **Note**: This build system is currently under active development and is not +> intended to be the primarily used one just yet. The makefiles are currently +> the ones that are still "guaranteed to work" as much as possible at least. + +## Using the new build system + +When configuring Rust via `./configure`, pass the following to enable building +via this build system: + +``` +./configure --enable-rustbuild +``` + +## ... + +## Directory Layout + +This build system houses all output under the `target` directory, which looks +like this: + +``` +# Root folder of all output. Everything is scoped underneath here +build/ + + # Location where the stage0 compiler downloads are all cached. This directory + # only contains the tarballs themselves as they're extracted elsewhere. + cache/ + 2015-12-19/ + 2016-01-15/ + 2016-01-21/ + ... + + # Output directory for building this build system itself. The stage0 + # cargo/rustc are used to build the build system into this location. + bootstrap/ + debug/ + release/ + + # Each remaining directory is scoped by the "host" triple of compilation at + # hand. + x86_64-unknown-linux-gnu/ + + # The build artifacts for the `compiler-rt` library for the target this + # folder is under. The exact layout here will likely depend on the platform, + # and this is also built with CMake so the build system is also likely + # different. + compiler-rt/build/ + + # Output folder for LLVM if it is compiled for this target + llvm/ + + # build folder (e.g. the platform-specific build system). Like with + # compiler-rt this is compiled with CMake + build/ + + # Installation of LLVM. Note that we run the equivalent of 'make install' + # for LLVM to setup these folders. + bin/ + lib/ + include/ + share/ + ... + + # Location where the stage0 Cargo and Rust compiler are unpacked. This + # directory is purely an extracted and overlaid tarball of these two (done + # by the bootstrapy python script). In theory the build system does not + # modify anything under this directory afterwards. + stage0/ + + # These to build directories are the cargo output directories for builds of + # the standard library and compiler, respectively. Internally these may also + # have other target directories, which represent artifacts being compiled + # from the host to the specified target. + # + # Essentially, each of these directories is filled in by one `cargo` + # invocation. The build system instruments calling Cargo in the right order + # with the right variables to ensure these are filled in correctly. + stageN-std/ + stageN-rustc/ + + # This is a special case of the above directories, **not** filled in via + # Cargo but rather the build system itself. The stage0 compiler already has + # a set of target libraries for its own host triple (in its own sysroot) + # inside of stage0/. When we run the stage0 compiler to bootstrap more + # things, however, we don't want to use any of these libraries (as those are + # the ones that we're building). So essentially, when the stage1 compiler is + # being compiled (e.g. after libstd has been built), *this* is used as the + # sysroot for the stage0 compiler being run. + # + # Basically this directory is just a temporary artifact use to configure the + # stage0 compiler to ensure that the libstd we just built is used to + # compile the stage1 compiler. + stage0-rustc/lib/ + + # These output directories are intended to be standalone working + # implementations of the compiler (corresponding to each stage). The build + # system will link (using hard links) output from stageN-{std,rustc} into + # each of these directories. + # + # In theory there is no extra build output in these directories. + stage1/ + stage2/ + stage3/ +``` diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py new file mode 100644 index 00000000000..744c30aa08f --- /dev/null +++ b/src/bootstrap/bootstrap.py @@ -0,0 +1,316 @@ +# Copyright 2015-2016 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. + +import argparse +import contextlib +import os +import shutil +import subprocess +import sys +import tarfile + +def get(url, path, verbose=False): + print("downloading " + url) + # see http://serverfault.com/questions/301128/how-to-download + if sys.platform == 'win32': + run(["PowerShell.exe", "/nologo", "-Command", + "(New-Object System.Net.WebClient).DownloadFile('" + url + + "', '" + path + "')"], verbose=verbose) + else: + run(["curl", "-o", path, url], verbose=verbose) + +def unpack(tarball, dst, verbose=False, match=None): + print("extracting " + tarball) + fname = os.path.basename(tarball).replace(".tar.gz", "") + with contextlib.closing(tarfile.open(tarball)) as tar: + for p in tar.getnames(): + if "/" not in p: + continue + name = p.replace(fname + "/", "", 1) + if match is not None and not name.startswith(match): + continue + name = name[len(match) + 1:] + + fp = os.path.join(dst, name) + if verbose: + print(" extracting " + p) + tar.extract(p, dst) + tp = os.path.join(dst, p) + if os.path.isdir(tp) and os.path.exists(fp): + continue + shutil.move(tp, fp) + shutil.rmtree(os.path.join(dst, fname)) + +def run(args, verbose=False): + if verbose: + print("running: " + ' '.join(args)) + sys.stdout.flush() + # Use Popen here instead of call() as it apparently allows powershell on + # Windows to not lock up waiting for input presumably. + ret = subprocess.Popen(args) + code = ret.wait() + if code != 0: + if not verbose: + print("failed to run: " + ' '.join(args)) + raise RuntimeError("failed to run command") + +class RustBuild: + def download_rust_nightly(self): + cache_dst = os.path.join(self.build_dir, "cache") + rustc_cache = os.path.join(cache_dst, self.snap_rustc_date()) + cargo_cache = os.path.join(cache_dst, self.snap_cargo_date()) + if not os.path.exists(rustc_cache): + os.makedirs(rustc_cache) + if not os.path.exists(cargo_cache): + os.makedirs(cargo_cache) + + if self.rustc().startswith(self.bin_root()) and \ + (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): + filename = "rust-std-nightly-" + self.build + ".tar.gz" + url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date() + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get(url + "/" + filename, tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), + match="rust-std-" + self.build, + verbose=self.verbose) + + filename = "rustc-nightly-" + self.build + ".tar.gz" + url = "https://static.rust-lang.org/dist/" + self.snap_rustc_date() + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get(url + "/" + filename, tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), match="rustc", verbose=self.verbose) + with open(self.rustc_stamp(), 'w') as f: + f.write(self.snap_rustc_date()) + + if self.cargo().startswith(self.bin_root()) and \ + (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): + filename = "cargo-nightly-" + self.build + ".tar.gz" + url = "https://static.rust-lang.org/cargo-dist/" + self.snap_cargo_date() + tarball = os.path.join(cargo_cache, filename) + if not os.path.exists(tarball): + get(url + "/" + filename, tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose) + with open(self.cargo_stamp(), 'w') as f: + f.write(self.snap_cargo_date()) + + def snap_cargo_date(self): + return self._cargo_date + + def snap_rustc_date(self): + return self._rustc_date + + def rustc_stamp(self): + return os.path.join(self.bin_root(), '.rustc-stamp') + + def cargo_stamp(self): + return os.path.join(self.bin_root(), '.cargo-stamp') + + def rustc_out_of_date(self): + if not os.path.exists(self.rustc_stamp()): + return True + with open(self.rustc_stamp(), 'r') as f: + return self.snap_rustc_date() != f.read() + + def cargo_out_of_date(self): + if not os.path.exists(self.cargo_stamp()): + return True + with open(self.cargo_stamp(), 'r') as f: + return self.snap_cargo_date() != f.read() + + def bin_root(self): + return os.path.join(self.build_dir, self.build, "stage0") + + def get_toml(self, key): + for line in self.config_toml.splitlines(): + if line.startswith(key + ' ='): + return self.get_string(line) + return None + + def get_mk(self, key): + for line in iter(self.config_mk.splitlines()): + if line.startswith(key): + return line[line.find(':=') + 2:].strip() + return None + + def cargo(self): + config = self.get_toml('cargo') + if config: + return config + return os.path.join(self.bin_root(), "bin/cargo" + self.exe_suffix()) + + def rustc(self): + config = self.get_toml('rustc') + if config: + return config + config = self.get_mk('CFG_LOCAL_RUST') + if config: + return config + '/bin/rustc' + self.exe_suffix() + return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix()) + + def get_string(self, line): + start = line.find('"') + end = start + 1 + line[start+1:].find('"') + return line[start+1:end] + + def exe_suffix(self): + if sys.platform == 'win32': + return '.exe' + else: + return '' + + def parse_nightly_dates(self): + nightlies = os.path.join(self.rust_root, "src/nightlies.txt") + with open(nightlies, 'r') as nightlies: + rustc, cargo = nightlies.read().split("\n")[:2] + assert rustc.startswith("rustc: ") + assert cargo.startswith("cargo: ") + self._rustc_date = rustc[len("rustc: "):] + self._cargo_date = cargo[len("cargo: "):] + + def build_bootstrap(self): + env = os.environ.copy() + env["CARGO_TARGET_DIR"] = os.path.join(self.build_dir, "bootstrap") + env["RUSTC"] = self.rustc() + env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + env["PATH"] = os.path.join(self.bin_root(), "bin") + \ + os.pathsep + env["PATH"] + self.run([self.cargo(), "build", "--manifest-path", + os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")], + env) + + def run(self, args, env): + proc = subprocess.Popen(args, env = env) + ret = proc.wait() + if ret != 0: + sys.exit(ret) + + def build_triple(self): + config = self.get_toml('build') + if config: + return config + config = self.get_mk('CFG_BUILD') + if config: + return config + try: + ostype = subprocess.check_output(['uname', '-s']).strip() + cputype = subprocess.check_output(['uname', '-m']).strip() + except FileNotFoundError: + if sys.platform == 'win32': + return 'x86_64-pc-windows-msvc' + else: + raise + + # Darwin's `uname -s` lies and always returns i386. We have to use + # sysctl instead. + if ostype == 'Darwin' and cputype == 'i686': + sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64']) + if sysctl.contains(': 1'): + cputype = 'x86_64' + + # The goal here is to come up with the same triple as LLVM would, + # at least for the subset of platforms we're willing to target. + if ostype == 'Linux': + ostype = 'unknown-linux-gnu' + elif ostype == 'FreeBSD': + ostype = 'unknown-freebsd' + elif ostype == 'DragonFly': + ostype = 'unknown-dragonfly' + elif ostype == 'Bitrig': + ostype = 'unknown-bitrig' + elif ostype == 'OpenBSD': + ostype = 'unknown-openbsd' + elif ostype == 'NetBSD': + ostype = 'unknown-netbsd' + elif ostype == 'Darwin': + ostype = 'apple-darwin' + elif ostype.startswith('MINGW'): + # msys' `uname` does not print gcc configuration, but prints msys + # configuration. so we cannot believe `uname -m`: + # msys1 is always i686 and msys2 is always x86_64. + # instead, msys defines $MSYSTEM which is MINGW32 on i686 and + # MINGW64 on x86_64. + ostype = 'pc-windows-gnu' + cputype = 'i686' + if os.environ.get('MSYSTEM') == 'MINGW64': + cputype = 'x86_64' + elif ostype.startswith('MSYS'): + ostype = 'pc-windows-gnu' + elif ostype.startswith('CYGWIN_NT'): + cputype = 'i686' + if ostype.endswith('WOW64'): + cputype = 'x86_64' + ostype = 'pc-windows-gnu' + else: + raise ValueError("unknown OS type: " + ostype) + + if cputype in {'i386', 'i486', 'i686', 'i786', 'x86'}: + cputype = 'i686' + elif cputype in {'xscale', 'arm'}: + cputype = 'arm' + elif cputype == 'armv7l': + cputype = 'arm' + ostype += 'eabihf' + elif cputype == 'aarch64': + cputype = 'aarch64' + elif cputype in {'powerpc', 'ppc', 'ppc64'}: + cputype = 'powerpc' + elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: + cputype = 'x86_64' + else: + raise ValueError("unknown cpu type: " + cputype) + + return cputype + '-' + ostype + +parser = argparse.ArgumentParser(description='Build rust') +parser.add_argument('--config') +parser.add_argument('-v', '--verbose', action='store_true') + +args = [a for a in sys.argv if a != '-h'] +args, _ = parser.parse_known_args(args) + +# Configure initial bootstrap +rb = RustBuild() +rb.config_toml = '' +rb.config_mk = '' +rb.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) +rb.build_dir = os.path.join(os.getcwd(), "build") +rb.verbose = args.verbose + +try: + with open(args.config or 'config.toml') as config: + rb.config_toml = config.read() +except: + pass +try: + rb.config_mk = open('config.mk').read() +except: + pass + +# Fetch/build the bootstrap +rb.build = rb.build_triple() +rb.parse_nightly_dates() +rb.download_rust_nightly() +sys.stdout.flush() +rb.build_bootstrap() +sys.stdout.flush() + +# Run the bootstrap +args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")] +args.extend(sys.argv[1:]) +args.append('--src') +args.append(rb.rust_root) +args.append('--build') +args.append(rb.build) +env = os.environ.copy() +env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) +rb.run(args, env) diff --git a/src/bootstrap/build/cc.rs b/src/bootstrap/build/cc.rs new file mode 100644 index 00000000000..9f962e9d9e6 --- /dev/null +++ b/src/bootstrap/build/cc.rs @@ -0,0 +1,98 @@ +// 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. + +use std::process::Command; + +use build_helper::{cc2ar, output}; +use gcc; + +use build::Build; +use build::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())); + 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 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); + } + } + + _ => {} + } +} diff --git a/src/bootstrap/build/channel.rs b/src/bootstrap/build/channel.rs new file mode 100644 index 00000000000..628b1d76432 --- /dev/null +++ b/src/bootstrap/build/channel.rs @@ -0,0 +1,82 @@ +// 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. + +use std::fs::{self, File}; +use std::io::prelude::*; +use std::path::Path; +use std::process::Command; + +use build_helper::output; + +use build::Build; +use build::util::mtime; + +pub fn collect(build: &mut Build) { + let mut main_mk = String::new(); + t!(t!(File::open(build.src.join("mk/main.mk"))).read_to_string(&mut main_mk)); + let mut release_num = ""; + let mut prerelease_version = ""; + for line in main_mk.lines() { + if line.starts_with("CFG_RELEASE_NUM") { + release_num = line.split('=').skip(1).next().unwrap().trim(); + } + if line.starts_with("CFG_PRERELEASE_VERSION") { + prerelease_version = line.split('=').skip(1).next().unwrap().trim(); + } + } + + // FIXME: this is duplicating makefile logic + match &build.config.channel[..] { + "stable" => { + build.release = release_num.to_string(); + build.unstable_features = false; + } + "beta" => { + build.release = format!("{}-beta{}", release_num, + prerelease_version); + build.unstable_features = false; + } + "nightly" => { + build.release = format!("{}-nightly", release_num); + build.unstable_features = true; + } + _ => { + build.release = format!("{}-dev", release_num); + build.unstable_features = true; + } + } + build.version = build.release.clone(); + + if fs::metadata(build.src.join(".git")).is_ok() { + let ver_date = output(Command::new("git").current_dir(&build.src) + .arg("log").arg("-1") + .arg("--date=short") + .arg("--pretty=format:%cd")); + let ver_hash = output(Command::new("git").current_dir(&build.src) + .arg("rev-parse").arg("HEAD")); + let short_ver_hash = output(Command::new("git") + .current_dir(&build.src) + .arg("rev-parse") + .arg("--short=9") + .arg("HEAD")); + let ver_date = ver_date.trim().to_string(); + let ver_hash = ver_hash.trim().to_string(); + let short_ver_hash = short_ver_hash.trim().to_string(); + build.version.push_str(&format!(" ({} {})", short_ver_hash, + ver_date)); + build.ver_date = Some(ver_date.to_string()); + build.ver_hash = Some(ver_hash); + build.short_ver_hash = Some(short_ver_hash); + } + + build.bootstrap_key = mtime(Path::new("config.toml")).seconds() + .to_string(); +} + diff --git a/src/bootstrap/build/compile.rs b/src/bootstrap/build/compile.rs new file mode 100644 index 00000000000..c22648b4710 --- /dev/null +++ b/src/bootstrap/build/compile.rs @@ -0,0 +1,249 @@ +// 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. + +use std::collections::HashMap; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use build_helper::output; + +use build::util::{exe, staticlib, libdir, mtime, is_dylib}; +use build::{Build, Compiler}; + +/// Build the standard library. +/// +/// This will build the standard library for a particular stage of the build +/// using the `compiler` targeting the `target` architecture. The artifacts +/// created will also be linked into the sysroot directory. +pub fn std<'a>(build: &'a Build, stage: u32, target: &str, + compiler: &Compiler<'a>) { + let host = compiler.host; + println!("Building stage{} std artifacts ({} -> {})", stage, + host, target); + + // Move compiler-rt into place as it'll be required by the compiler when + // building the standard library to link the dylib of libstd + let libdir = build.sysroot_libdir(stage, &host, target); + let _ = fs::remove_dir_all(&libdir); + t!(fs::create_dir_all(&libdir)); + t!(fs::hard_link(&build.compiler_rt_built.borrow()[target], + libdir.join(staticlib("compiler-rt", target)))); + + build_startup_objects(build, target, &libdir); + + let out_dir = build.cargo_out(stage, &host, true, target); + build.clear_if_dirty(&out_dir, &build.compiler_path(compiler)); + let mut cargo = build.cargo(stage, compiler, true, target, "build"); + cargo.arg("--features").arg(build.std_features()) + .arg("--manifest-path") + .arg(build.src.join("src/rustc/std_shim/Cargo.toml")); + + if let Some(target) = build.config.target_config.get(target) { + if let Some(ref jemalloc) = target.jemalloc { + cargo.env("JEMALLOC_OVERRIDE", jemalloc); + } + } + if let Some(ref p) = build.config.musl_root { + if target.contains("musl") { + cargo.env("MUSL_ROOT", p); + } + } + + build.run(&mut cargo); + add_to_sysroot(&out_dir, &libdir); +} + +/// Build and prepare startup objects like rsbegin.o and rsend.o +/// +/// These are primarily used on Windows right now for linking executables/dlls. +/// They don't require any library support as they're just plain old object +/// files, so we just use the nightly snapshot compiler to always build them (as +/// no other compilers are guaranteed to be available). +fn build_startup_objects(build: &Build, target: &str, into: &Path) { + if !target.contains("pc-windows-gnu") { + return + } + let compiler = Compiler::new(0, &build.config.build); + let compiler = build.compiler_path(&compiler); + + for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) { + let file = t!(file); + build.run(Command::new(&compiler) + .arg("--emit=obj") + .arg("--out-dir").arg(into) + .arg(file.path())); + } + + for obj in ["crt2.o", "dllcrt2.o"].iter() { + t!(fs::copy(compiler_file(build.cc(target), obj), into.join(obj))); + } +} + +/// Build the compiler. +/// +/// This will build the compiler for a particular stage of the build using +/// the `compiler` targeting the `target` architecture. The artifacts +/// created will also be linked into the sysroot directory. +pub fn rustc<'a>(build: &'a Build, stage: u32, target: &str, + compiler: &Compiler<'a>) { + let host = compiler.host; + println!("Building stage{} compiler artifacts ({} -> {})", stage, + host, target); + + let out_dir = build.cargo_out(stage, &host, false, target); + let rustc = out_dir.join(exe("rustc", target)); + build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target)); + + let mut cargo = build.cargo(stage, compiler, false, target, "build"); + cargo.arg("--features").arg(build.rustc_features(stage)) + .arg("--manifest-path") + .arg(build.src.join("src/rustc/Cargo.toml")); + + // In stage0 we may not need to build as many executables + if stage == 0 { + cargo.arg("--bin").arg("rustc"); + } + + // Set some configuration variables picked up by build scripts and + // the compiler alike + cargo.env("CFG_RELEASE", &build.release) + .env("CFG_RELEASE_CHANNEL", &build.config.channel) + .env("CFG_VERSION", &build.version) + .env("CFG_BOOTSTRAP_KEY", &build.bootstrap_key) + .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(String::new())) + .env("RUSTC_BOOTSTRAP_KEY", &build.bootstrap_key) + .env("CFG_LIBDIR_RELATIVE", "lib"); + + if let Some(ref ver_date) = build.ver_date { + cargo.env("CFG_VER_DATE", ver_date); + } + if let Some(ref ver_hash) = build.ver_hash { + cargo.env("CFG_VER_HASH", ver_hash); + } + if !build.unstable_features { + cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); + } + if let Some(config) = build.config.target_config.get(target) { + if let Some(ref s) = config.llvm_config { + cargo.env("LLVM_CONFIG", s); + } + } + if build.config.llvm_static_stdcpp { + cargo.env("LLVM_STATIC_STDCPP", + compiler_file(build.cxx(target), "libstdc++.a")); + } + if let Some(ref s) = build.config.rustc_default_linker { + cargo.env("CFG_DEFAULT_LINKER", s); + } + if let Some(ref s) = build.config.rustc_default_ar { + cargo.env("CFG_DEFAULT_AR", s); + } + build.run(&mut cargo); + + let sysroot_libdir = build.sysroot_libdir(stage, host, target); + add_to_sysroot(&out_dir, &sysroot_libdir); + + if host == target { + assemble_compiler(build, stage, target, &rustc); + } +} + +/// Cargo's output path for the standard library in a given stage, compiled +/// by a particular compiler for the specified target. +fn libstd_shim(build: &Build, stage: u32, host: &str, target: &str) -> PathBuf { + build.cargo_out(stage, host, true, target).join("libstd_shim.rlib") +} + +fn compiler_file(compiler: &Path, file: &str) -> String { + output(Command::new(compiler) + .arg(format!("-print-file-name={}", file))).trim().to_string() +} + +/// Prepare a new compiler from the artifacts in `stage` +/// +/// This will link the compiler built by `host` during the stage +/// specified to the sysroot location for `host` to be the official +/// `stage + 1` compiler for that host. This means that the `rustc` binary +/// itself will be linked into place along with all supporting dynamic +/// libraries. +fn assemble_compiler(build: &Build, stage: u32, host: &str, rustc: &Path) { + // Clear out old files + let sysroot = build.sysroot(stage + 1, host); + let _ = fs::remove_dir_all(&sysroot); + t!(fs::create_dir_all(&sysroot)); + + // Link in all dylibs to the libdir + let sysroot_libdir = sysroot.join(libdir(host)); + t!(fs::create_dir_all(&sysroot_libdir)); + let src_libdir = build.sysroot_libdir(stage, host, host); + for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) { + let filename = f.file_name().into_string().unwrap(); + if is_dylib(&filename) { + t!(fs::hard_link(&f.path(), sysroot_libdir.join(&filename))); + } + } + + // Link the compiler binary itself into place + let bindir = sysroot.join("bin"); + t!(fs::create_dir_all(&bindir)); + let compiler = build.compiler_path(&Compiler::new(stage + 1, host)); + let _ = fs::remove_file(&compiler); + t!(fs::hard_link(rustc, compiler)); + + // See if rustdoc exists to link it into place + let exe = exe("rustdoc", host); + let rustdoc_src = rustc.parent().unwrap().join(&exe); + let rustdoc_dst = bindir.join(exe); + if fs::metadata(&rustdoc_src).is_ok() { + let _ = fs::remove_file(&rustdoc_dst); + t!(fs::hard_link(&rustdoc_src, &rustdoc_dst)); + } +} + +/// Link some files into a rustc sysroot. +/// +/// For a particular stage this will link all of the contents of `out_dir` +/// into the sysroot of the `host` compiler, assuming the artifacts are +/// compiled for the specified `target`. +fn add_to_sysroot(out_dir: &Path, sysroot_dst: &Path) { + // Collect the set of all files in the dependencies directory, keyed + // off the name of the library. We assume everything is of the form + // `foo-<hash>.{rlib,so,...}`, and there could be multiple different + // `<hash>` values for the same name (of old builds). + let mut map = HashMap::new(); + for file in t!(fs::read_dir(out_dir.join("deps"))).map(|f| t!(f)) { + let filename = file.file_name().into_string().unwrap(); + + // We're only interested in linking rlibs + dylibs, other things like + // unit tests don't get linked in + if !filename.ends_with(".rlib") && + !filename.ends_with(".lib") && + !is_dylib(&filename) { + continue + } + let file = file.path(); + let dash = filename.find("-").unwrap(); + let key = (filename[..dash].to_string(), + file.extension().unwrap().to_owned()); + map.entry(key).or_insert(Vec::new()) + .push(file.clone()); + } + + // For all hash values found, pick the most recent one to move into the + // sysroot, that should be the one we just built. + for (_, paths) in map { + let (_, path) = paths.iter().map(|path| { + (mtime(&path).seconds(), path) + }).max().unwrap(); + t!(fs::hard_link(&path, + sysroot_dst.join(path.file_name().unwrap()))); + } +} diff --git a/src/bootstrap/build/config.rs b/src/bootstrap/build/config.rs new file mode 100644 index 00000000000..1e67c4a9a3e --- /dev/null +++ b/src/bootstrap/build/config.rs @@ -0,0 +1,361 @@ +// 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. + +use std::collections::HashMap; +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; +use std::process; + +use num_cpus; +use rustc_serialize::Decodable; +use toml::{Parser, Decoder, Value}; + +/// Global configuration for the entire build and/or bootstrap. +/// +/// This structure is derived from a combination of both `config.toml` and +/// `config.mk`. As of the time of this writing it's unlikely that `config.toml` +/// is used all that much, so this is primarily filled out by `config.mk` which +/// is generated from `./configure`. +/// +/// Note that this structure is not decoded directly into, but rather it is +/// filled out from the decoded forms of the structs below. +#[derive(Default)] +pub struct Config { + pub ccache: bool, + pub verbose: bool, + pub submodules: bool, + pub compiler_docs: bool, + pub docs: bool, + pub target_config: HashMap<String, Target>, + + // llvm codegen options + pub llvm_assertions: bool, + pub llvm_optimize: bool, + pub llvm_version_check: bool, + pub llvm_static_stdcpp: bool, + + // rust codegen options + pub rust_optimize: bool, + pub rust_codegen_units: u32, + pub rust_debug_assertions: bool, + pub rust_debuginfo: bool, + pub rust_rpath: bool, + pub rustc_default_linker: Option<String>, + pub rustc_default_ar: Option<String>, + + pub build: String, + pub host: Vec<String>, + pub target: Vec<String>, + pub rustc: Option<String>, + pub cargo: Option<String>, + + // libstd features + pub debug_jemalloc: bool, + pub use_jemalloc: bool, + + // misc + pub channel: String, + pub musl_root: Option<PathBuf>, + pub prefix: Option<String>, +} + +/// Per-target configuration stored in the global configuration structure. +#[derive(Default)] +pub struct Target { + pub llvm_config: Option<PathBuf>, + pub jemalloc: Option<PathBuf>, + pub cc: Option<PathBuf>, + pub cxx: Option<PathBuf>, + pub ndk: Option<PathBuf>, +} + +/// Structure of the `config.toml` file that configuration is read from. +/// +/// This structure uses `Decodable` to automatically decode a TOML configuration +/// file into this format, and then this is traversed and written into the above +/// `Config` structure. +#[derive(RustcDecodable, Default)] +struct TomlConfig { + build: Option<Build>, + llvm: Option<Llvm>, + rust: Option<Rust>, + target: Option<HashMap<String, TomlTarget>>, +} + +/// TOML representation of various global build decisions. +#[derive(RustcDecodable, Default, Clone)] +struct Build { + build: Option<String>, + host: Vec<String>, + target: Vec<String>, + cargo: Option<String>, + rustc: Option<String>, + compiler_docs: Option<bool>, + docs: Option<bool>, +} + +/// TOML representation of how the LLVM build is configured. +#[derive(RustcDecodable, Default)] +struct Llvm { + ccache: Option<bool>, + assertions: Option<bool>, + optimize: Option<bool>, + version_check: Option<bool>, + static_libstdcpp: Option<bool>, +} + +/// TOML representation of how the Rust build is configured. +#[derive(RustcDecodable, Default)] +struct Rust { + optimize: Option<bool>, + codegen_units: Option<u32>, + debug_assertions: Option<bool>, + debuginfo: Option<bool>, + debug_jemalloc: Option<bool>, + use_jemalloc: Option<bool>, + default_linker: Option<String>, + default_ar: Option<String>, + channel: Option<String>, + musl_root: Option<String>, + rpath: Option<bool>, +} + +/// TOML representation of how each build target is configured. +#[derive(RustcDecodable, Default)] +struct TomlTarget { + llvm_config: Option<String>, + jemalloc: Option<String>, + cc: Option<String>, + cxx: Option<String>, + android_ndk: Option<String>, +} + +impl Config { + pub fn parse(build: &str, file: Option<PathBuf>) -> Config { + let mut config = Config::default(); + config.llvm_optimize = true; + config.use_jemalloc = true; + config.rust_optimize = true; + config.submodules = true; + config.docs = true; + config.rust_rpath = true; + config.rust_codegen_units = 1; + config.build = build.to_string(); + config.channel = "dev".to_string(); + + let toml = file.map(|file| { + let mut f = t!(File::open(&file)); + let mut toml = String::new(); + t!(f.read_to_string(&mut toml)); + let mut p = Parser::new(&toml); + let table = match p.parse() { + Some(table) => table, + None => { + println!("failed to parse TOML configuration:"); + for err in p.errors.iter() { + let (loline, locol) = p.to_linecol(err.lo); + let (hiline, hicol) = p.to_linecol(err.hi); + println!("{}:{}-{}:{}: {}", loline, locol, hiline, + hicol, err.desc); + } + process::exit(2); + } + }; + let mut d = Decoder::new(Value::Table(table)); + match Decodable::decode(&mut d) { + Ok(cfg) => cfg, + Err(e) => { + println!("failed to decode TOML: {}", e); + process::exit(2); + } + } + }).unwrap_or_else(|| TomlConfig::default()); + + let build = toml.build.clone().unwrap_or(Build::default()); + set(&mut config.build, build.build.clone()); + config.host.push(config.build.clone()); + for host in build.host.iter() { + if !config.host.contains(host) { + config.host.push(host.clone()); + } + } + for target in config.host.iter().chain(&build.target) { + if !config.target.contains(target) { + config.target.push(target.clone()); + } + } + config.rustc = build.rustc; + config.cargo = build.cargo; + set(&mut config.compiler_docs, build.compiler_docs); + set(&mut config.docs, build.docs); + + if let Some(ref llvm) = toml.llvm { + set(&mut config.ccache, llvm.ccache); + set(&mut config.llvm_assertions, llvm.assertions); + set(&mut config.llvm_optimize, llvm.optimize); + set(&mut config.llvm_optimize, llvm.optimize); + set(&mut config.llvm_version_check, llvm.version_check); + set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); + } + if let Some(ref rust) = toml.rust { + set(&mut config.rust_debug_assertions, rust.debug_assertions); + set(&mut config.rust_debuginfo, rust.debuginfo); + set(&mut config.rust_optimize, rust.optimize); + set(&mut config.rust_rpath, rust.rpath); + set(&mut config.debug_jemalloc, rust.debug_jemalloc); + set(&mut config.use_jemalloc, rust.use_jemalloc); + set(&mut config.channel, rust.channel.clone()); + config.rustc_default_linker = rust.default_linker.clone(); + config.rustc_default_ar = rust.default_ar.clone(); + config.musl_root = rust.musl_root.clone().map(PathBuf::from); + + match rust.codegen_units { + Some(0) => config.rust_codegen_units = num_cpus::get() as u32, + Some(n) => config.rust_codegen_units = n, + None => {} + } + } + + if let Some(ref t) = toml.target { + for (triple, cfg) in t { + let mut target = Target::default(); + + if let Some(ref s) = cfg.llvm_config { + target.llvm_config = Some(env::current_dir().unwrap().join(s)); + } + if let Some(ref s) = cfg.jemalloc { + target.jemalloc = Some(env::current_dir().unwrap().join(s)); + } + if let Some(ref s) = cfg.android_ndk { + target.ndk = Some(env::current_dir().unwrap().join(s)); + } + target.cxx = cfg.cxx.clone().map(PathBuf::from); + target.cc = cfg.cc.clone().map(PathBuf::from); + + config.target_config.insert(triple.clone(), target); + } + } + + return config + } + + pub fn update_with_config_mk(&mut self) { + let mut config = String::new(); + File::open("config.mk").unwrap().read_to_string(&mut config).unwrap(); + for line in config.lines() { + let mut parts = line.splitn(2, ":=").map(|s| s.trim()); + let key = parts.next().unwrap(); + let value = match parts.next() { + Some(n) if n.starts_with('\"') => &n[1..n.len() - 1], + Some(n) => n, + None => continue + }; + + macro_rules! check { + ($(($name:expr, $val:expr),)*) => { + if value == "1" { + $( + if key == concat!("CFG_ENABLE_", $name) { + $val = true; + continue + } + if key == concat!("CFG_DISABLE_", $name) { + $val = false; + continue + } + )* + } + } + } + + check! { + ("CCACHE", self.ccache), + ("MANAGE_SUBMODULES", self.submodules), + ("COMPILER_DOCS", self.compiler_docs), + ("DOCS", self.docs), + ("LLVM_ASSERTIONS", self.llvm_assertions), + ("OPTIMIZE_LLVM", self.llvm_optimize), + ("LLVM_VERSION_CHECK", self.llvm_version_check), + ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), + ("OPTIMIZE", self.rust_optimize), + ("DEBUG_ASSERTIONS", self.rust_debug_assertions), + ("DEBUGINFO", self.rust_debuginfo), + ("JEMALLOC", self.use_jemalloc), + ("DEBUG_JEMALLOC", self.debug_jemalloc), + ("RPATH", self.rust_rpath), + } + + match key { + "CFG_BUILD" => self.build = value.to_string(), + "CFG_HOST" => { + self.host = value.split(" ").map(|s| s.to_string()) + .collect(); + } + "CFG_TARGET" => { + self.target = value.split(" ").map(|s| s.to_string()) + .collect(); + } + "CFG_MUSL_ROOT" if value.len() > 0 => { + self.musl_root = Some(PathBuf::from(value)); + } + "CFG_DEFAULT_AR" if value.len() > 0 => { + self.rustc_default_ar = Some(value.to_string()); + } + "CFG_DEFAULT_LINKER" if value.len() > 0 => { + self.rustc_default_linker = Some(value.to_string()); + } + "CFG_RELEASE_CHANNEL" => { + self.channel = value.to_string(); + } + "CFG_PREFIX" => { + self.prefix = Some(value.to_string()); + } + "CFG_LLVM_ROOT" if value.len() > 0 => { + let target = self.target_config.entry(self.build.clone()) + .or_insert(Target::default()); + let root = PathBuf::from(value); + target.llvm_config = Some(root.join("bin/llvm-config")); + } + "CFG_JEMALLOC_ROOT" if value.len() > 0 => { + let target = self.target_config.entry(self.build.clone()) + .or_insert(Target::default()); + target.jemalloc = Some(PathBuf::from(value)); + } + "CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => { + let target = "arm-linux-androideabi".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.ndk = Some(PathBuf::from(value)); + } + "CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => { + let target = "i686-linux-androideabi".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.ndk = Some(PathBuf::from(value)); + } + "CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => { + let target = "aarch64-linux-androideabi".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.ndk = Some(PathBuf::from(value)); + } + _ => {} + } + } + } +} + +fn set<T>(field: &mut T, val: Option<T>) { + if let Some(v) = val { + *field = v; + } +} diff --git a/src/bootstrap/build/flags.rs b/src/bootstrap/build/flags.rs new file mode 100644 index 00000000000..cd538bb0a90 --- /dev/null +++ b/src/bootstrap/build/flags.rs @@ -0,0 +1,99 @@ +// 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. + +use std::fs; +use std::path::PathBuf; +use std::process; +use std::slice; + +use getopts::Options; + +pub struct Flags { + pub verbose: bool, + pub stage: Option<u32>, + pub build: String, + pub host: Filter, + pub target: Filter, + pub step: Vec<String>, + pub config: Option<PathBuf>, + pub src: Option<PathBuf>, + pub jobs: Option<u32>, + pub args: Vec<String>, +} + +pub struct Filter { + values: Vec<String>, +} + +impl Flags { + pub fn parse(args: &[String]) -> Flags { + let mut opts = Options::new(); + opts.optflag("v", "verbose", "use verbose output"); + opts.optopt("", "config", "TOML configuration file for build", "FILE"); + opts.optmulti("", "host", "host targets to build", "HOST"); + opts.reqopt("", "build", "build target of the stage0 compiler", "BUILD"); + opts.optmulti("", "target", "targets to build", "TARGET"); + opts.optmulti("s", "step", "build step to execute", "STEP"); + opts.optopt("", "stage", "stage to build", "N"); + opts.optopt("", "src", "path to repo root", "DIR"); + opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); + opts.optflag("h", "help", "print this help message"); + + let usage = |n| -> ! { + let brief = format!("Usage: rust.py [options]"); + print!("{}", opts.usage(&brief)); + process::exit(n); + }; + + let m = opts.parse(args).unwrap_or_else(|e| { + println!("failed to parse options: {}", e); + usage(1); + }); + if m.opt_present("h") { + usage(0); + } + + if m.free.len() > 0 { + println!("free arguments are not currently accepted"); + usage(1); + } + + let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { + if fs::metadata("config.toml").is_ok() { + Some(PathBuf::from("config.toml")) + } else { + None + } + }); + + Flags { + verbose: m.opt_present("v"), + stage: m.opt_str("stage").map(|j| j.parse().unwrap()), + build: m.opt_str("build").unwrap(), + host: Filter { values: m.opt_strs("host") }, + target: Filter { values: m.opt_strs("target") }, + step: m.opt_strs("step"), + config: cfg_file, + src: m.opt_str("src").map(PathBuf::from), + jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), + args: m.free.clone(), + } + } +} + +impl Filter { + pub fn contains(&self, name: &str) -> bool { + self.values.len() == 0 || self.values.iter().any(|s| s == name) + } + + pub fn iter(&self) -> slice::Iter<String> { + self.values.iter() + } +} diff --git a/src/bootstrap/build/job.rs b/src/bootstrap/build/job.rs new file mode 100644 index 00000000000..49e027ffda5 --- /dev/null +++ b/src/bootstrap/build/job.rs @@ -0,0 +1,100 @@ +// 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. + +//! Job management on Windows for bootstrapping +//! +//! Most of the time when you're running a build system (e.g. make) you expect +//! Ctrl-C or abnormal termination to actually terminate the entire tree of +//! process in play, not just the one at the top. This currently works "by +//! default" on Unix platforms because Ctrl-C actually sends a signal to the +//! *process group* rather than the parent process, so everything will get torn +//! down. On Windows, however, this does not happen and Ctrl-C just kills the +//! parent process. +//! +//! To achieve the same semantics on Windows we use Job Objects to ensure that +//! all processes die at the same time. Job objects have a mode of operation +//! where when all handles to the object are closed it causes all child +//! processes associated with the object to be terminated immediately. +//! Conveniently whenever a process in the job object spawns a new process the +//! child will be associated with the job object as well. This means if we add +//! ourselves to the job object we create then everything will get torn down! +//! +//! Unfortunately most of the time the build system is actually called from a +//! python wrapper (which manages things like building the build system) so this +//! all doesn't quite cut it so far. To go the last mile we duplicate the job +//! object handle into our parent process (a python process probably) and then +//! close our own handle. This means that the only handle to the job object +//! resides in the parent python process, so when python dies the whole build +//! system dies (as one would probably expect!). +//! +//! Note that this module has a #[cfg(windows)] above it as none of this logic +//! is required on Unix. + +extern crate kernel32; +extern crate winapi; + +use std::env; +use std::io; +use std::mem; + +use self::winapi::*; +use self::kernel32::*; + +pub unsafe fn setup() { + // Create a new job object for us to use + let job = CreateJobObjectW(0 as *mut _, 0 as *const _); + assert!(job != 0 as *mut _, "{}", io::Error::last_os_error()); + + // Indicate that when all handles to the job object are gone that all + // process in the object should be killed. Note that this includes our + // entire process tree by default because we've added ourselves and and our + // children will reside in the job by default. + let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>(); + info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + let r = SetInformationJobObject(job, + JobObjectExtendedLimitInformation, + &mut info as *mut _ as LPVOID, + mem::size_of_val(&info) as DWORD); + assert!(r != 0, "{}", io::Error::last_os_error()); + + // Assign our process to this job object + let r = AssignProcessToJobObject(job, GetCurrentProcess()); + assert!(r != 0, "{}", io::Error::last_os_error()); + + // If we've got a parent process (e.g. the python script that called us) + // then move ownership of this job object up to them. That way if the python + // script is killed (e.g. via ctrl-c) then we'll all be torn down. + // + // If we don't have a parent (e.g. this was run directly) then we + // intentionally leak the job object handle. When our process exits + // (normally or abnormally) it will close the handle implicitly, causing all + // processes in the job to be cleaned up. + let pid = match env::var("BOOTSTRAP_PARENT_ID") { + Ok(s) => s, + Err(..) => return, + }; + + let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap()); + assert!(parent != 0 as *mut _, "{}", io::Error::last_os_error()); + let mut parent_handle = 0 as *mut _; + let r = DuplicateHandle(GetCurrentProcess(), job, + parent, &mut parent_handle, + 0, FALSE, DUPLICATE_SAME_ACCESS); + + // If this failed, well at least we tried! An example of DuplicateHandle + // failing in the past has been when the wrong python2 package spawed this + // build system (e.g. the `python2` package in MSYS instead of + // `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure + // mode" here is that we only clean everything up when the build system + // dies, not when the python parent does, so not too bad. + if r != 0 { + CloseHandle(job); + } +} diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs new file mode 100644 index 00000000000..6f962aae923 --- /dev/null +++ b/src/bootstrap/build/mod.rs @@ -0,0 +1,452 @@ +// 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. + +use std::cell::RefCell; +use std::collections::HashMap; +use std::env; +use std::fs::{self, File}; +use std::path::{PathBuf, Path}; +use std::process::Command; + +use build_helper::{run_silent, output}; +use gcc; +use num_cpus; + +use build::util::{exe, mtime, libdir, add_lib_path}; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +mod cc; +mod channel; +mod compile; +mod config; +mod flags; +mod native; +mod sanity; +mod step; +mod util; + +pub use build::config::Config; +pub use build::flags::Flags; + +#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] +pub struct Compiler<'a> { + stage: u32, + host: &'a str, +} + +pub struct Build { + // User-specified configuration via config.toml + config: Config, + + // User-specified configuration via CLI flags + flags: Flags, + + // Derived properties from the above two configurations + cargo: PathBuf, + rustc: PathBuf, + src: PathBuf, + out: PathBuf, + release: String, + unstable_features: bool, + ver_hash: Option<String>, + short_ver_hash: Option<String>, + ver_date: Option<String>, + version: String, + bootstrap_key: String, + + // Runtime state filled in later on + cc: HashMap<String, (gcc::Tool, PathBuf)>, + cxx: HashMap<String, gcc::Tool>, + compiler_rt_built: RefCell<HashMap<String, PathBuf>>, +} + +impl Build { + pub fn new(flags: Flags, config: Config) -> Build { + let cwd = t!(env::current_dir()); + let src = flags.src.clone().unwrap_or(cwd.clone()); + let out = cwd.join("build"); + + let stage0_root = out.join(&config.build).join("stage0/bin"); + let rustc = match config.rustc { + Some(ref s) => PathBuf::from(s), + None => stage0_root.join(exe("rustc", &config.build)), + }; + let cargo = match config.cargo { + Some(ref s) => PathBuf::from(s), + None => stage0_root.join(exe("cargo", &config.build)), + }; + + Build { + flags: flags, + config: config, + cargo: cargo, + rustc: rustc, + src: src, + out: out, + + release: String::new(), + unstable_features: false, + ver_hash: None, + short_ver_hash: None, + ver_date: None, + version: String::new(), + bootstrap_key: String::new(), + cc: HashMap::new(), + cxx: HashMap::new(), + compiler_rt_built: RefCell::new(HashMap::new()), + } + } + + pub fn build(&mut self) { + use build::step::Source::*; + + // see comments in job.rs for what's going on here + #[cfg(windows)] + fn setup_job() { + mod job; + unsafe { job::setup() } + } + #[cfg(not(windows))] fn setup_job() {} + setup_job(); + + cc::find(self); + sanity::check(self); + channel::collect(self); + self.update_submodules(); + + for target in step::all(self) { + match target.src { + Llvm { _dummy } => { + native::llvm(self, target.target); + } + CompilerRt { _dummy } => { + native::compiler_rt(self, target.target); + } + Libstd { stage, compiler } => { + compile::std(self, stage, target.target, &compiler); + } + Librustc { stage, compiler } => { + compile::rustc(self, stage, target.target, &compiler); + } + Rustc { stage } => { + println!("ok, rustc stage{} in {}", stage, target.target); + } + } + } + } + + fn update_submodules(&self) { + if !self.config.submodules { + return + } + if fs::metadata(self.src.join(".git")).is_err() { + return + } + let out = output(Command::new("git").arg("submodule").arg("status")); + if !out.lines().any(|l| l.starts_with("+") || l.starts_with("-")) { + return + } + + self.run(Command::new("git").arg("submodule").arg("sync")); + self.run(Command::new("git").arg("submodule").arg("init")); + self.run(Command::new("git").arg("submodule").arg("update")); + self.run(Command::new("git").arg("submodule").arg("update") + .arg("--recursive")); + self.run(Command::new("git").arg("submodule").arg("status") + .arg("--recursive")); + self.run(Command::new("git").arg("submodule").arg("foreach") + .arg("--recursive") + .arg("git").arg("clean").arg("-fdx")); + self.run(Command::new("git").arg("submodule").arg("foreach") + .arg("--recursive") + .arg("git").arg("checkout").arg(".")); + } + + /// Clear out `dir` if our build has been flagged as dirty, and also set + /// ourselves as dirty if `file` changes when `f` is executed. + fn clear_if_dirty(&self, dir: &Path, input: &Path) { + let stamp = dir.join(".stamp"); + if mtime(&stamp) < mtime(input) { + self.verbose(&format!("Dirty - {}", dir.display())); + let _ = fs::remove_dir_all(dir); + } + t!(fs::create_dir_all(dir)); + t!(File::create(stamp)); + } + + /// Prepares an invocation of `cargo` to be run. + /// + /// This will create a `Command` that represents a pending execution of + /// Cargo for the specified stage, whether or not the standard library is + /// being built, and using the specified compiler targeting `target`. + // FIXME: aren't stage/compiler duplicated? + fn cargo(&self, stage: u32, compiler: &Compiler, is_std: bool, + target: &str, cmd: &str) -> Command { + let mut cargo = Command::new(&self.cargo); + let host = compiler.host; + let out_dir = self.stage_out(stage, host, is_std); + cargo.env("CARGO_TARGET_DIR", out_dir) + .arg(cmd) + .arg("--target").arg(target) + .arg("-j").arg(self.jobs().to_string()); + + // Customize the compiler we're running. Specify the compiler to cargo + // as our shim and then pass it some various options used to configure + // how the actual compiler itself is called. + cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc")) + .env("RUSTC_REAL", self.compiler_path(compiler)) + .env("RUSTC_STAGE", self.stage_arg(stage, compiler).to_string()) + .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) + .env("RUSTC_CODEGEN_UNITS", + self.config.rust_codegen_units.to_string()) + .env("RUSTC_DEBUG_ASSERTIONS", + self.config.rust_debug_assertions.to_string()) + .env("RUSTC_SNAPSHOT", &self.rustc) + .env("RUSTC_SYSROOT", self.sysroot(stage, host)) + .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()) + .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")) + .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) + .env("RUSTDOC", self.tool(compiler, "rustdoc")); + + // Specify some variuos options for build scripts used throughout the + // build. + // + // FIXME: the guard against msvc shouldn't need to be here + if !target.contains("msvc") { + cargo.env(format!("CC_{}", target), self.cc(target)) + .env(format!("AR_{}", target), self.ar(target)) + .env(format!("CFLAGS_{}", target), self.cflags(target)); + } + + // Environment variables *required* needed throughout the build + // + // FIXME: should update code to not require this env vars + cargo.env("CFG_COMPILER_HOST_TRIPLE", target); + + if self.config.verbose || self.flags.verbose { + cargo.arg("-v"); + } + if self.config.rust_optimize { + cargo.arg("--release"); + } + self.add_rustc_lib_path(compiler, &mut cargo); + return cargo + } + + /// Get a path to the compiler specified. + fn compiler_path(&self, compiler: &Compiler) -> PathBuf { + if compiler.is_snapshot(self) { + self.rustc.clone() + } else { + self.sysroot(compiler.stage, compiler.host).join("bin") + .join(exe("rustc", compiler.host)) + } + } + + /// Get the specified tool next to the specified compiler + fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf { + if compiler.is_snapshot(self) { + assert!(tool == "rustdoc", "no tools other than rustdoc in stage0"); + let mut rustdoc = self.rustc.clone(); + rustdoc.pop(); + rustdoc.push(exe("rustdoc", &self.config.build)); + return rustdoc + } + let (stage, host) = (compiler.stage, compiler.host); + self.cargo_out(stage - 1, host, false, host).join(exe(tool, host)) + } + + /// Get a `Command` which is ready to run `tool` in `stage` built for + /// `host`. + #[allow(dead_code)] // this will be used soon + fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command { + let mut cmd = Command::new(self.tool(&compiler, tool)); + let host = compiler.host; + let stage = compiler.stage; + let paths = vec![ + self.cargo_out(stage - 1, host, true, host).join("deps"), + self.cargo_out(stage - 1, host, false, host).join("deps"), + ]; + add_lib_path(paths, &mut cmd); + return cmd + } + + fn stage_arg(&self, stage: u32, compiler: &Compiler) -> u32 { + if stage == 0 && compiler.host != self.config.build {1} else {stage} + } + + /// Get the space-separated set of activated features for the standard + /// library. + fn std_features(&self) -> String { + let mut features = String::new(); + if self.config.debug_jemalloc { + features.push_str(" debug-jemalloc"); + } + if self.config.use_jemalloc { + features.push_str(" jemalloc"); + } + return features + } + + /// Get the space-separated set of activated features for the compiler. + fn rustc_features(&self, stage: u32) -> String { + let mut features = String::new(); + if self.config.use_jemalloc { + features.push_str(" jemalloc"); + } + if stage > 0 { + features.push_str(" rustdoc"); + features.push_str(" rustbook"); + } + return features + } + + /// Component directory that Cargo will produce output into (e.g. + /// release/debug) + fn cargo_dir(&self) -> &'static str { + if self.config.rust_optimize {"release"} else {"debug"} + } + + fn sysroot(&self, stage: u32, host: &str) -> PathBuf { + if stage == 0 { + self.stage_out(stage, host, false) + } else { + self.out.join(host).join(format!("stage{}", stage)) + } + } + + fn sysroot_libdir(&self, stage: u32, host: &str, target: &str) -> PathBuf { + self.sysroot(stage, host).join("lib").join("rustlib") + .join(target).join("lib") + } + + /// Returns the root directory for all output generated in a particular + /// stage when running with a particular host compiler. + /// + /// The `is_std` flag indicates whether the root directory is for the + /// bootstrap of the standard library or for the compiler. + fn stage_out(&self, stage: u32, host: &str, is_std: bool) -> PathBuf { + self.out.join(host) + .join(format!("stage{}{}", stage, if is_std {"-std"} else {"-rustc"})) + } + + /// Returns the root output directory for all Cargo output in a given stage, + /// running a particular comipler, wehther or not we're building the + /// standard library, and targeting the specified architecture. + fn cargo_out(&self, stage: u32, host: &str, is_std: bool, + target: &str) -> PathBuf { + self.stage_out(stage, host, is_std).join(target).join(self.cargo_dir()) + } + + /// Root output directory for LLVM compiled for `target` + fn llvm_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("llvm") + } + + /// Root output directory for compiler-rt compiled for `target` + fn compiler_rt_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("compiler-rt") + } + + fn add_rustc_lib_path(&self, compiler: &Compiler, cmd: &mut Command) { + // Windows doesn't need dylib path munging because the dlls for the + // compiler live next to the compiler and the system will find them + // automatically. + if cfg!(windows) { return } + + add_lib_path(vec![self.rustc_libdir(compiler)], cmd); + } + + fn rustc_libdir(&self, compiler: &Compiler) -> PathBuf { + if compiler.is_snapshot(self) { + self.rustc_snapshot_libdir() + } else { + self.sysroot(compiler.stage, compiler.host) + .join(libdir(compiler.host)) + } + } + + fn rustc_snapshot_libdir(&self) -> PathBuf { + self.rustc.parent().unwrap().parent().unwrap() + .join(libdir(&self.config.build)) + } + + fn run(&self, cmd: &mut Command) { + self.verbose(&format!("running: {:?}", cmd)); + run_silent(cmd) + } + + fn verbose(&self, msg: &str) { + if self.flags.verbose || self.config.verbose { + println!("{}", msg); + } + } + + fn jobs(&self) -> u32 { + self.flags.jobs.unwrap_or(num_cpus::get() as u32) + } + + fn cc(&self, target: &str) -> &Path { + self.cc[target].0.path() + } + + fn cflags(&self, target: &str) -> String { + self.cc[target].0.args().iter() + .map(|s| s.to_string_lossy()) + .collect::<Vec<_>>() + .join(" ") + } + + fn ar(&self, target: &str) -> &Path { + &self.cc[target].1 + } + + fn cxx(&self, target: &str) -> &Path { + self.cxx[target].path() + } + + fn rustc_flags(&self, target: &str) -> Vec<String> { + let mut base = match target { + "arm-unknown-linux-gnueabihf" => { + vec!["-Ctarget-feature=+v6,+vfp2".to_string()] + } + "mips-unknown-linux-gnu" => { + vec!["-Ctarget-cpu=mips32r2".to_string(), + "-Ctarget-feature=+mips32r2".to_string(), + "-Csoft-float".to_string()] + } + "mipsel-unknown-linux-gnu" => { + vec!["-Ctarget-cpu=mips32".to_string(), + "-Ctarget-feature=+mips32".to_string()] + } + _ => Vec::new(), + }; + if target != self.config.build && !target.contains("msvc") { + base.push(format!("-Clinker={}", self.cc(target).display())); + } + return base + } +} + +impl<'a> Compiler<'a> { + fn new(stage: u32, host: &'a str) -> Compiler<'a> { + Compiler { stage: stage, host: host } + } + + fn is_snapshot(&self, build: &Build) -> bool { + self.stage == 0 && self.host == build.config.build + } +} diff --git a/src/bootstrap/build/native.rs b/src/bootstrap/build/native.rs new file mode 100644 index 00000000000..6ad5f404123 --- /dev/null +++ b/src/bootstrap/build/native.rs @@ -0,0 +1,157 @@ +// 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. + +use std::path::Path; +use std::process::Command; +use std::fs; + +use build_helper::output; +use cmake; + +use build::Build; +use build::util::{exe, staticlib}; + +pub fn llvm(build: &Build, target: &str) { + // If we're using a custom LLVM bail out here, but we can only use a + // custom LLVM for the build triple. + if let Some(config) = build.config.target_config.get(target) { + if let Some(ref s) = config.llvm_config { + return check_llvm_version(build, s); + } + } + + // If the cleaning trigger is newer than our built artifacts (or if the + // artifacts are missing) then we keep going, otherwise we bail out. + let dst = build.llvm_out(target); + let stamp = build.src.join("src/rustllvm/llvm-auto-clean-trigger"); + let llvm_config = dst.join("bin").join(exe("llvm-config", target)); + build.clear_if_dirty(&dst, &stamp); + if fs::metadata(llvm_config).is_ok() { + return + } + + let _ = fs::remove_dir_all(&dst.join("build")); + t!(fs::create_dir_all(&dst.join("build"))); + let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; + + // http://llvm.org/docs/CMake.html + let mut cfg = cmake::Config::new(build.src.join("src/llvm")); + cfg.target(target) + .host(&build.config.build) + .out_dir(&dst) + .profile(if build.config.llvm_optimize {"Release"} else {"Debug"}) + .define("LLVM_ENABLE_ASSERTIONS", assertions) + .define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC") + .define("LLVM_INCLUDE_EXAMPLES", "OFF") + .define("LLVM_INCLUDE_TESTS", "OFF") + .define("LLVM_INCLUDE_DOCS", "OFF") + .define("LLVM_ENABLE_ZLIB", "OFF") + .define("WITH_POLLY", "OFF") + .define("LLVM_ENABLE_TERMINFO", "OFF") + .define("LLVM_ENABLE_LIBEDIT", "OFF") + .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()); + + if target.starts_with("i686") { + cfg.define("LLVM_BUILD_32_BITS", "ON"); + } + + // http://llvm.org/docs/HowToCrossCompileLLVM.html + if target != build.config.build { + // FIXME: if the llvm root for the build triple is overridden then we + // should use llvm-tblgen from there, also should verify that it + // actually exists most of the time in normal installs of LLVM. + let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen"); + cfg.define("CMAKE_CROSSCOMPILING", "True") + .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) + .define("LLVM_TABLEGEN", &host) + .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + } + + // MSVC handles compiler business itself + if !target.contains("msvc") { + if build.config.ccache { + cfg.define("CMAKE_C_COMPILER", "ccache") + .define("CMAKE_C_COMPILER_ARG1", build.cc(target)) + .define("CMAKE_CXX_COMPILER", "ccache") + .define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target)); + } else { + cfg.define("CMAKE_C_COMPILER", build.cc(target)) + .define("CMAKE_CXX_COMPILER", build.cxx(target)); + } + cfg.build_arg("-j").build_arg(build.jobs().to_string()); + } + + // FIXME: we don't actually need to build all LLVM tools and all LLVM + // libraries here, e.g. we just want a few components and a few + // tools. Figure out how to filter them down and only build the right + // tools and libs on all platforms. + cfg.build(); +} + +fn check_llvm_version(build: &Build, llvm_config: &Path) { + if !build.config.llvm_version_check { + return + } + + let mut cmd = Command::new(llvm_config); + let version = output(cmd.arg("--version")); + if version.starts_with("3.5") || version.starts_with("3.6") || + version.starts_with("3.7") { + return + } + panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version) +} + +pub fn compiler_rt(build: &Build, target: &str) { + let dst = build.compiler_rt_out(target); + let arch = target.split('-').next().unwrap(); + let mode = if build.config.rust_optimize {"Release"} else {"Debug"}; + let (dir, build_target, libname) = if target.contains("linux") { + let os = if target.contains("android") {"-android"} else {""}; + let target = format!("clang_rt.builtins-{}{}", arch, os); + ("linux".to_string(), target.clone(), target) + } else if target.contains("darwin") { + let target = format!("clang_rt.builtins_{}_osx", arch); + ("builtins".to_string(), target.clone(), target) + } else if target.contains("windows-gnu") { + let target = format!("clang_rt.builtins-{}", arch); + ("windows".to_string(), target.clone(), target) + } else if target.contains("windows-msvc") { + (format!("windows/{}", mode), + "lib/builtins/builtins".to_string(), + format!("clang_rt.builtins-{}", arch.replace("i686", "i386"))) + } else { + panic!("can't get os from target: {}", target) + }; + let output = dst.join("build/lib").join(dir) + .join(staticlib(&libname, target)); + build.compiler_rt_built.borrow_mut().insert(target.to_string(), + output.clone()); + if fs::metadata(&output).is_ok() { + return + } + let _ = fs::remove_dir_all(&dst); + t!(fs::create_dir_all(&dst)); + let build_llvm_config = build.llvm_out(&build.config.build) + .join("bin") + .join(exe("llvm-config", &build.config.build)); + let mut cfg = cmake::Config::new(build.src.join("src/compiler-rt")); + cfg.target(target) + .host(&build.config.build) + .out_dir(&dst) + .profile(mode) + .define("LLVM_CONFIG_PATH", build_llvm_config) + .define("COMPILER_RT_DEFAULT_TARGET_TRIPLE", target) + .define("COMPILER_RT_BUILD_SANITIZERS", "OFF") + .define("COMPILER_RT_BUILD_EMUTLS", "OFF") + .define("CMAKE_C_COMPILER", build.cc(target)) + .build_target(&build_target); + cfg.build(); +} diff --git a/src/bootstrap/build/sanity.rs b/src/bootstrap/build/sanity.rs new file mode 100644 index 00000000000..40f4c707609 --- /dev/null +++ b/src/bootstrap/build/sanity.rs @@ -0,0 +1,122 @@ +// 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. + +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::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()); + 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()); + need_cmd(build.ar(target).as_ref()); + } + for host in build.config.host.iter() { + need_cmd(build.cxx(host).as_ref()); + } + + 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") { + 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 +"); + } + } + } +} diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs new file mode 100644 index 00000000000..2fbf1a6ad1d --- /dev/null +++ b/src/bootstrap/build/step.rs @@ -0,0 +1,177 @@ +// Copyright 2016 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. + +use std::collections::HashSet; + +use build::{Build, Compiler}; + +#[derive(Hash, Eq, PartialEq, Clone, Debug)] +pub struct Step<'a> { + pub src: Source<'a>, + pub target: &'a str, +} + +macro_rules! targets { + ($m:ident) => { + $m! { + (rustc, Rustc { stage: u32 }), + (libstd, Libstd { stage: u32, compiler: Compiler<'a> }), + (librustc, Librustc { stage: u32, compiler: Compiler<'a> }), + (llvm, Llvm { _dummy: () }), + (compiler_rt, CompilerRt { _dummy: () }), + } + } +} + +macro_rules! item { ($a:item) => ($a) } + +macro_rules! define_source { + ($(($short:ident, $name:ident { $($args:tt)* }),)*) => { + item! { + #[derive(Hash, Eq, PartialEq, Clone, Debug)] + pub enum Source<'a> { + $($name { $($args)* }),* + } + } + } +} + +targets!(define_source); + +pub fn all(build: &Build) -> Vec<Step> { + let mut ret = Vec::new(); + let mut all = HashSet::new(); + for target in top_level(build) { + fill(build, &target, &mut ret, &mut all); + } + return ret; + + fn fill<'a>(build: &'a Build, + target: &Step<'a>, + ret: &mut Vec<Step<'a>>, + set: &mut HashSet<Step<'a>>) { + if set.insert(target.clone()) { + for dep in target.deps(build) { + fill(build, &dep, ret, set); + } + ret.push(target.clone()); + } + } +} + +fn top_level(build: &Build) -> Vec<Step> { + let mut targets = Vec::new(); + let stage = build.flags.stage.unwrap_or(2); + + let host = Step { + src: Source::Llvm { _dummy: () }, + target: build.flags.host.iter().next() + .unwrap_or(&build.config.build), + }; + let target = Step { + src: Source::Llvm { _dummy: () }, + target: build.flags.target.iter().next().map(|x| &x[..]) + .unwrap_or(host.target) + }; + + add_steps(build, stage, &host, &target, &mut targets); + + if targets.len() == 0 { + let t = Step { + src: Source::Llvm { _dummy: () }, + target: &build.config.build, + }; + for host in build.config.host.iter() { + if !build.flags.host.contains(host) { + continue + } + let host = t.target(host); + targets.push(host.librustc(stage, host.compiler(stage))); + for target in build.config.target.iter() { + if !build.flags.target.contains(target) { + continue + } + targets.push(host.target(target) + .libstd(stage, host.compiler(stage))); + } + } + } + + return targets + +} + +fn add_steps<'a>(build: &'a Build, + stage: u32, + host: &Step<'a>, + target: &Step<'a>, + targets: &mut Vec<Step<'a>>) { + for step in build.flags.step.iter() { + let compiler = host.compiler(stage); + match &step[..] { + "libstd" => targets.push(target.libstd(stage, compiler)), + "librustc" => targets.push(target.libstd(stage, compiler)), + "rustc" => targets.push(host.rustc(stage)), + "llvm" => targets.push(target.llvm(())), + "compiler-rt" => targets.push(target.compiler_rt(())), + _ => panic!("unknown build target: `{}`", step), + } + } +} + +macro_rules! constructors { + ($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => {$( + fn $short(&self, $($arg: $t),*) -> Step<'a> { + Step { + src: Source::$name { $($arg: $arg),* }, + target: self.target, + } + } + )*} +} + +impl<'a> Step<'a> { + fn compiler(&self, stage: u32) -> Compiler<'a> { + Compiler::new(stage, self.target) + } + + fn target(&self, target: &'a str) -> Step<'a> { + Step { target: target, src: self.src.clone() } + } + + targets!(constructors); + + pub fn deps(&self, build: &'a Build) -> Vec<Step<'a>> { + match self.src { + Source::Rustc { stage: 0 } => { + if self.target == build.config.build { + Vec::new() + } else { + let compiler = Compiler::new(0, &build.config.build); + vec![self.librustc(0, compiler)] + } + } + Source::Rustc { stage } => { + vec![self.librustc(stage - 1, self.compiler(stage - 1))] + } + Source::Librustc { stage, compiler } => { + vec![self.libstd(stage, compiler), self.llvm(())] + } + Source::Libstd { stage: _, compiler } => { + vec![self.compiler_rt(()), + self.rustc(compiler.stage).target(compiler.host)] + } + Source::CompilerRt { _dummy } => { + vec![self.llvm(()).target(&build.config.build)] + } + Source::Llvm { _dummy } => Vec::new(), + } + } +} diff --git a/src/bootstrap/build/util.rs b/src/bootstrap/build/util.rs new file mode 100644 index 00000000000..6c700671f11 --- /dev/null +++ b/src/bootstrap/build/util.rs @@ -0,0 +1,97 @@ +// 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. + +use std::env; +use std::path::{Path, PathBuf}; +use std::fs; +use std::process::Command; + +use bootstrap::{dylib_path, dylib_path_var}; +use filetime::FileTime; + +pub fn staticlib(name: &str, target: &str) -> String { + if target.contains("windows-msvc") { + format!("{}.lib", name) + } else { + format!("lib{}.a", name) + } +} + +pub fn mtime(path: &Path) -> FileTime { + fs::metadata(path).map(|f| { + FileTime::from_last_modification_time(&f) + }).unwrap_or(FileTime::zero()) +} + +#[allow(dead_code)] // this will be used soon +pub fn cp_r(src: &Path, dst: &Path) { + for f in t!(fs::read_dir(src)) { + let f = t!(f); + let path = f.path(); + let name = path.file_name().unwrap(); + let dst = dst.join(name); + if t!(f.file_type()).is_dir() { + let _ = fs::remove_dir_all(&dst); + t!(fs::create_dir(&dst)); + cp_r(&path, &dst); + } else { + let _ = fs::remove_file(&dst); + t!(fs::hard_link(&path, dst)); + } + } +} + +/// Given an executable called `name`, return the filename for the +/// executable for a particular target. +pub fn exe(name: &str, target: &str) -> String { + if target.contains("windows") { + format!("{}.exe", name) + } else { + name.to_string() + } +} + +pub fn is_dylib(name: &str) -> bool { + name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll") +} + +pub fn libdir(target: &str) -> &'static str { + if target.contains("windows") {"bin"} else {"lib"} +} + +pub fn add_lib_path(path: Vec<PathBuf>, cmd: &mut Command) { + let mut list = dylib_path(); + for path in path { + list.insert(0, path); + } + cmd.env(dylib_path_var(), t!(env::join_paths(list))); +} + +#[allow(dead_code)] // this will be used soon +pub fn up_to_date(src: &Path, dst: &Path) -> bool { + let threshold = mtime(dst); + let meta = t!(fs::metadata(src)); + if meta.is_dir() { + dir_up_to_date(src, &threshold) + } else { + FileTime::from_last_modification_time(&meta) <= threshold + } +} + +fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool { + t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { + let meta = t!(e.metadata()); + if meta.is_dir() { + dir_up_to_date(&e.path(), threshold) + } else { + FileTime::from_last_modification_time(&meta) < *threshold + } + }) +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs new file mode 100644 index 00000000000..3158a3ab058 --- /dev/null +++ b/src/bootstrap/lib.rs @@ -0,0 +1,28 @@ +// 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. + +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; + +pub fn dylib_path_var() -> &'static str { + if cfg!(target_os = "windows") { + "PATH" + } else if cfg!(target_os = "macos") { + "DYLD_LIBRARY_PATH" + } else { + "LD_LIBRARY_PATH" + } +} + +pub fn dylib_path() -> Vec<PathBuf> { + env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new())) + .collect() +} diff --git a/src/bootstrap/main.rs b/src/bootstrap/main.rs new file mode 100644 index 00000000000..32432132c17 --- /dev/null +++ b/src/bootstrap/main.rs @@ -0,0 +1,38 @@ +// 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. + +#![deny(warnings)] + +extern crate bootstrap; +extern crate build_helper; +extern crate cmake; +extern crate filetime; +extern crate gcc; +extern crate getopts; +extern crate libc; +extern crate num_cpus; +extern crate rustc_serialize; +extern crate toml; + +use std::env; + +use build::{Flags, Config, Build}; + +mod build; + +fn main() { + let args = env::args().skip(1).collect::<Vec<_>>(); + let flags = Flags::parse(&args); + let mut config = Config::parse(&flags.build, flags.config.clone()); + if std::fs::metadata("config.mk").is_ok() { + config.update_with_config_mk(); + } + Build::new(flags, config).build(); +} diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in new file mode 100644 index 00000000000..1157346d774 --- /dev/null +++ b/src/bootstrap/mk/Makefile.in @@ -0,0 +1,23 @@ +# Copyright 20126 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. + +include config.mk +include $(CFG_SRC_DIR)mk/util.mk + +ifdef VERBOSE +BOOTSTRAP_ARGS := -v +else +BOOTSTRAP_ARGS := +endif + +BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ARGS) + +all: + $(Q)$(BOOTSTRAP) diff --git a/src/bootstrap/rustc.rs b/src/bootstrap/rustc.rs new file mode 100644 index 00000000000..0c30360ba79 --- /dev/null +++ b/src/bootstrap/rustc.rs @@ -0,0 +1,91 @@ +// 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. + +extern crate bootstrap; + +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; +use std::process::Command; + +fn main() { + let args = env::args_os().skip(1).collect::<Vec<_>>(); + // Detect whether or not we're a build script depending on whether --target + // is passed (a bit janky...) + let is_build_script = args.iter() + .position(|i| i.to_str() == Some("--target")) + .is_none(); + + // Build scripts always use the snapshot compiler which is guaranteed to be + // able to produce an executable, whereas intermediate compilers may not + // have the standard library built yet and may not be able to produce an + // executable. Otherwise we just use the standard compiler we're + // bootstrapping with. + let rustc = if is_build_script { + env::var_os("RUSTC_SNAPSHOT").unwrap() + } else { + env::var_os("RUSTC_REAL").unwrap() + }; + + let mut cmd = Command::new(rustc); + cmd.args(&args) + .arg("--cfg").arg(format!("stage{}", env::var("RUSTC_STAGE").unwrap())); + + if is_build_script { + // Build scripts are always built with the snapshot compiler, so we need + // to be sure to set up the right path information for the OS dynamic + // linker to find the libraries in question. + if let Some(p) = env::var_os("RUSTC_SNAPSHOT_LIBDIR") { + let mut path = bootstrap::dylib_path(); + path.insert(0, PathBuf::from(p)); + cmd.env(bootstrap::dylib_path_var(), env::join_paths(path).unwrap()); + } + } else { + cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").unwrap()); + + // When we build Rust dylibs they're all intended for intermediate + // usage, so make sure we pass the -Cprefer-dynamic flag instead of + // linking all deps statically into the dylib. + cmd.arg("-Cprefer-dynamic"); + + if let Some(s) = env::var_os("MUSL_ROOT") { + let mut root = OsString::from("native="); + root.push(&s); + root.push("/lib"); + cmd.arg("-L").arg(&root); + } + } + + // Set various options from config.toml to configure how we're building + // code. + if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) { + cmd.arg("-g"); + } + if env::var("RUSTC_RPATH") == Ok("true".to_string()) { + cmd.arg("-Crpath"); + } + let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { + Ok(s) => if s == "true" {"y"} else {"n"}, + Err(..) => "n", + }; + cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); + if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { + cmd.arg("-C").arg(format!("codegen-units={}", s)); + } + if let Ok(s) = env::var("RUSTC_FLAGS") { + cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>()); + } + + // Actually run the compiler! + std::process::exit(match cmd.status() { + Ok(s) => s.code().unwrap_or(1), + Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), + }) +} diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml new file mode 100644 index 00000000000..01d704f816b --- /dev/null +++ b/src/build_helper/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "build_helper" +version = "0.1.0" +authors = ["The Rust Project Developers"] + +[lib] +name = "build_helper" +path = "lib.rs" diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs new file mode 100644 index 00000000000..092a1cabc74 --- /dev/null +++ b/src/build_helper/lib.rs @@ -0,0 +1,68 @@ +// 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. + +#![deny(warnings)] + +use std::process::{Command, Stdio}; +use std::path::{Path, PathBuf}; + +pub fn run(cmd: &mut Command) { + println!("running: {:?}", cmd); + run_silent(cmd); +} + +pub fn run_silent(cmd: &mut Command) { + let status = match cmd.status() { + Ok(status) => status, + Err(e) => fail(&format!("failed to execute command: {}", e)), + }; + if !status.success() { + fail(&format!("command did not execute successfully: {:?}\n\ + expected success, got: {}", cmd, status)); + } +} + +pub fn gnu_target(target: &str) -> String { + match target { + "i686-pc-windows-msvc" => "i686-pc-win32".to_string(), + "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(), + "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(), + "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(), + s => s.to_string(), + } +} + +pub fn cc2ar(cc: &Path, target: &str) -> PathBuf { + if target.contains("musl") || target.contains("msvc") { + PathBuf::from("ar") + } else { + let file = cc.file_name().unwrap().to_str().unwrap(); + cc.parent().unwrap().join(file.replace("gcc", "ar") + .replace("cc", "ar") + .replace("clang", "ar")) + } +} + +pub fn output(cmd: &mut Command) -> String { + let output = match cmd.stderr(Stdio::inherit()).output() { + Ok(status) => status, + Err(e) => fail(&format!("failed to execute command: {}", e)), + }; + if !output.status.success() { + panic!("command did not execute successfully: {:?}\n\ + expected success, got: {}", cmd, output.status); + } + String::from_utf8(output.stdout).unwrap() +} + +fn fail(s: &str) -> ! { + println!("\n\n{}\n\n", s); + std::process::exit(1); +} diff --git a/src/etc/tidy.py b/src/etc/tidy.py index 942793adc31..fd3f4bf0b13 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -147,7 +147,7 @@ try: report_err("snapshot out of date (" + date + "): " + line) else: - if "SNAP" in line: + if "SNAP " in line: report_warn("unmatched SNAP line: " + line) if cr_flag in line: diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml new file mode 100644 index 00000000000..5af8d9e8e27 --- /dev/null +++ b/src/liballoc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "alloc" +version = "0.0.0" + +[lib] +name = "alloc" +path = "lib.rs" +test = false + +[dependencies] +core = { path = "../libcore" } +libc = { path = "../rustc/libc_shim" } +alloc_system = { path = "../liballoc_system" } diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml new file mode 100644 index 00000000000..768a0c2c0a5 --- /dev/null +++ b/src/liballoc_jemalloc/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "alloc_jemalloc" +version = "0.0.0" +build = "build.rs" +links = "jemalloc" + +[lib] +name = "alloc_jemalloc" +path = "lib.rs" +test = false + +[dependencies] +core = { path = "../libcore" } +libc = { path = "../rustc/libc_shim" } + +[build-dependencies] +build_helper = { path = "../build_helper" } +gcc = "0.3.17" + +[features] +debug = [] diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs new file mode 100644 index 00000000000..4bc752af48e --- /dev/null +++ b/src/liballoc_jemalloc/build.rs @@ -0,0 +1,106 @@ +// 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. + +extern crate build_helper; +extern crate gcc; + +use std::env; +use std::path::PathBuf; +use std::process::Command; +use build_helper::run; + +fn main() { + println!("cargo:rustc-cfg=cargobuild"); + + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let src_dir = env::current_dir().unwrap(); + + if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") { + let jemalloc = PathBuf::from(jemalloc); + println!("cargo:rustc-link-search=native={}", + jemalloc.parent().unwrap().display()); + let stem = jemalloc.file_stem().unwrap().to_str().unwrap(); + let name = jemalloc.file_name().unwrap().to_str().unwrap(); + let kind = if name.ends_with(".a") {"static"} else {"dylib"}; + println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]); + return + } + + let compiler = gcc::Config::new().get_compiler(); + let ar = build_helper::cc2ar(compiler.path(), &target); + let cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) + .collect::<Vec<_>>().join(" "); + + let mut cmd = Command::new("sh"); + cmd.arg(src_dir.join("../jemalloc/configure").to_str().unwrap() + .replace("C:\\", "/c/") + .replace("\\", "/")) + .current_dir(&build_dir) + .env("CC", compiler.path()) + .env("EXTRA_CFLAGS", cflags) + .env("AR", &ar) + .env("RANLIB", format!("{} s", ar.display())); + + if target.contains("windows-gnu") { + // A bit of history here, this used to be --enable-lazy-lock added in + // #14006 which was filed with jemalloc in jemalloc/jemalloc#83 which + // was also reported to MinGW: + // + // http://sourceforge.net/p/mingw-w64/bugs/395/ + // + // When updating jemalloc to 4.0, however, it was found that binaries + // would exit with the status code STATUS_RESOURCE_NOT_OWNED indicating + // that a thread was unlocking a mutex it never locked. Disabling this + // "lazy lock" option seems to fix the issue, but it was enabled by + // default for MinGW targets in 13473c7 for jemalloc. + // + // As a result of all that, force disabling lazy lock on Windows, and + // after reading some code it at least *appears* that the initialization + // of mutexes is otherwise ok in jemalloc, so shouldn't cause problems + // hopefully... + // + // tl;dr: make windows behave like other platforms by disabling lazy + // locking, but requires passing an option due to a historical + // default with jemalloc. + cmd.arg("--disable-lazy-lock"); + } else if target.contains("ios") || target.contains("android") { + cmd.arg("--disable-tls"); + } + + if cfg!(feature = "debug-jemalloc") { + cmd.arg("--enable-debug"); + } + + // Turn off broken quarantine (see jemalloc/jemalloc#161) + cmd.arg("--disable-fill"); + cmd.arg("--with-jemalloc-prefix=je_"); + cmd.arg(format!("--host={}", build_helper::gnu_target(&target))); + cmd.arg(format!("--build={}", build_helper::gnu_target(&host))); + + run(&mut cmd); + run(Command::new("make") + .current_dir(&build_dir) + .arg("build_lib_static") + .arg("-j").arg(env::var("NUM_JOBS").unwrap())); + + if target.contains("windows") { + println!("cargo:rustc-link-lib=static=jemalloc"); + } else { + println!("cargo:rustc-link-lib=static=jemalloc_pic"); + } + println!("cargo:rustc-link-search=native={}/lib", build_dir.display()); + if target.contains("android") { + println!("cargo:rustc-link-lib=gcc"); + } else if !target.contains("windows") { + println!("cargo:rustc-link-lib=pthread"); + } +} diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index d02e9e4ba13..2c46e37ac32 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -38,7 +38,10 @@ use libc::{c_int, c_void, size_t}; not(target_os = "android"), not(target_env = "musl")), link(name = "pthread"))] -extern "C" { +#[cfg(not(cargobuild))] +extern {} + +extern { fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void; fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; diff --git a/src/liballoc_system/Cargo.toml b/src/liballoc_system/Cargo.toml new file mode 100644 index 00000000000..88e8e2d7adb --- /dev/null +++ b/src/liballoc_system/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "alloc_system" +version = "0.0.0" + +[lib] +name = "alloc_system" +path = "lib.rs" +test = false + +[dependencies] +core = { path = "../libcore" } +libc = { path = "../rustc/libc_shim" } diff --git a/src/libarena/Cargo.toml b/src/libarena/Cargo.toml new file mode 100644 index 00000000000..b53c0a2f48b --- /dev/null +++ b/src/libarena/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "arena" +version = "0.0.0" + +[lib] +name = "arena" +path = "lib.rs" +crate-type = ["dylib"] diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml new file mode 100644 index 00000000000..18e322ff74f --- /dev/null +++ b/src/libcollections/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "collections" +version = "0.0.0" + +[lib] +name = "collections" +path = "lib.rs" +test = false + +[dependencies] +alloc = { path = "../liballoc" } +core = { path = "../libcore" } +rustc_unicode = { path = "../librustc_unicode" } diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml new file mode 100644 index 00000000000..24455a1d841 --- /dev/null +++ b/src/libcore/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "core" +version = "0.0.0" + +[lib] +name = "core" +path = "lib.rs" +test = false diff --git a/src/libflate/Cargo.toml b/src/libflate/Cargo.toml new file mode 100644 index 00000000000..52aa6bb86ef --- /dev/null +++ b/src/libflate/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "flate" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "flate" +path = "lib.rs" +crate-type = ["dylib"] + +[build-dependencies] +build_helper = { path = "../build_helper" } +gcc = "0.3" diff --git a/src/libflate/build.rs b/src/libflate/build.rs new file mode 100644 index 00000000000..245c705dfcc --- /dev/null +++ b/src/libflate/build.rs @@ -0,0 +1,18 @@ +// 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. + +extern crate gcc; + +fn main() { + println!("cargo:rustc-cfg=cargobuild"); + gcc::Config::new() + .file("../rt/miniz.c") + .compile("libminiz.a"); +} diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index f316250d96d..a6bf735e459 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -79,7 +79,10 @@ impl Drop for Bytes { } #[link(name = "miniz", kind = "static")] -extern "C" { +#[cfg(not(cargobuild))] +extern {} + +extern { /// Raw miniz compression function. fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void, src_buf_len: size_t, diff --git a/src/libfmt_macros/Cargo.toml b/src/libfmt_macros/Cargo.toml new file mode 100644 index 00000000000..b3f4d2deae2 --- /dev/null +++ b/src/libfmt_macros/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "fmt_macros" +version = "0.0.0" + +[lib] +name = "fmt_macros" +path = "lib.rs" +crate-type = ["dylib"] diff --git a/src/libgetopts/Cargo.toml b/src/libgetopts/Cargo.toml new file mode 100644 index 00000000000..99e3b892858 --- /dev/null +++ b/src/libgetopts/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "getopts" +version = "0.0.0" + +[lib] +name = "getopts" +path = "lib.rs" +crate-type = ["dylib", "rlib"] diff --git a/src/libgraphviz/Cargo.toml b/src/libgraphviz/Cargo.toml new file mode 100644 index 00000000000..76ef3a1d188 --- /dev/null +++ b/src/libgraphviz/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "graphviz" +version = "0.0.0" + +[lib] +name = "graphviz" +path = "lib.rs" +crate-type = ["dylib"] diff --git a/src/liblog/Cargo.toml b/src/liblog/Cargo.toml new file mode 100644 index 00000000000..31a862478d0 --- /dev/null +++ b/src/liblog/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "log" +version = "0.0.0" + +[lib] +name = "log" +path = "lib.rs" +crate-type = ["dylib", "rlib"] diff --git a/src/librand/Cargo.toml b/src/librand/Cargo.toml new file mode 100644 index 00000000000..784654c0859 --- /dev/null +++ b/src/librand/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rand" +version = "0.0.0" + +[lib] +name = "rand" +path = "lib.rs" +test = false + +[dependencies] +core = { path = "../libcore" } diff --git a/src/librbml/Cargo.toml b/src/librbml/Cargo.toml new file mode 100644 index 00000000000..ab89ac2b7a1 --- /dev/null +++ b/src/librbml/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rbml" +version = "0.0.0" + +[lib] +name = "rbml" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +serialize = { path = "../libserialize" } diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml new file mode 100644 index 00000000000..2aefeb5fc2d --- /dev/null +++ b/src/librustc/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc" +version = "0.0.0" + +[lib] +name = "rustc" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +arena = { path = "../libarena" } +flate = { path = "../libflate" } +fmt_macros = { path = "../libfmt_macros" } +getopts = { path = "../libgetopts" } +graphviz = { path = "../libgraphviz" } +log = { path = "../liblog" } +rbml = { path = "../librbml" } +rustc_back = { path = "../librustc_back" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_front = { path = "../librustc_front" } +rustc_llvm = { path = "../librustc_llvm" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_back/Cargo.toml b/src/librustc_back/Cargo.toml new file mode 100644 index 00000000000..255ca60e2b8 --- /dev/null +++ b/src/librustc_back/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_back" +version = "0.0.0" + +[lib] +name = "rustc_back" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +syntax = { path = "../libsyntax" } +serialize = { path = "../libserialize" } +rustc_llvm = { path = "../librustc_llvm" } +rustc_front = { path = "../librustc_front" } +log = { path = "../liblog" } + +[features] +jemalloc = [] diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index a6aef52caf6..0920155ef42 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -501,9 +501,9 @@ impl Target { } fn maybe_jemalloc() -> String { - if cfg!(disable_jemalloc) { - "alloc_system".to_string() - } else { + if cfg!(feature = "jemalloc") { "alloc_jemalloc".to_string() + } else { + "alloc_system".to_string() } } diff --git a/src/librustc_bitflags/Cargo.toml b/src/librustc_bitflags/Cargo.toml new file mode 100644 index 00000000000..e82c6ec05c8 --- /dev/null +++ b/src/librustc_bitflags/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_bitflags" +version = "0.0.0" + +[lib] +name = "rustc_bitflags" +path = "lib.rs" +test = false + +[dependencies] +core = { path = "../libcore" } diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml new file mode 100644 index 00000000000..f78f6fb86ae --- /dev/null +++ b/src/librustc_borrowck/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_borrowck" +version = "0.0.0" + +[lib] +name = "rustc_borrowck" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +syntax = { path = "../libsyntax" } +graphviz = { path = "../libgraphviz" } +rustc = { path = "../librustc" } +rustc_front = { path = "../librustc_front" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml new file mode 100644 index 00000000000..e2e16059d98 --- /dev/null +++ b/src/librustc_data_structures/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_data_structures" +version = "0.0.0" + +[lib] +name = "rustc_data_structures" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +serialize = { path = "../libserialize" } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml new file mode 100644 index 00000000000..bf86e8f039a --- /dev/null +++ b/src/librustc_driver/Cargo.toml @@ -0,0 +1,33 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_driver" +version = "0.0.0" + +[lib] +name = "rustc_driver" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +arena = { path = "../libarena" } +flate = { path = "../libflate" } +getopts = { path = "../libgetopts" } +graphviz = { path = "../libgraphviz" } +log = { path = "../liblog" } +rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } +rustc_borrowck = { path = "../librustc_borrowck" } +rustc_front = { path = "../librustc_front" } +rustc_lint = { path = "../librustc_lint" } +rustc_llvm = { path = "../librustc_llvm" } +rustc_mir = { path = "../librustc_mir" } +rustc_plugin = { path = "../librustc_plugin" } +rustc_passes = { path = "../librustc_passes" } +rustc_privacy = { path = "../librustc_privacy" } +rustc_resolve = { path = "../librustc_resolve" } +rustc_trans = { path = "../librustc_trans" } +rustc_typeck = { path = "../librustc_typeck" } +rustc_metadata = { path = "../librustc_metadata" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } +syntax_ext = { path = "../libsyntax_ext" } diff --git a/src/librustc_front/Cargo.toml b/src/librustc_front/Cargo.toml new file mode 100644 index 00000000000..eae0b0646a3 --- /dev/null +++ b/src/librustc_front/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_front" +version = "0.0.0" + +[lib] +name = "rustc_front" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +syntax = { path = "../libsyntax" } +serialize = { path = "../libserialize" } diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml new file mode 100644 index 00000000000..33443957d1b --- /dev/null +++ b/src/librustc_lint/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_lint" +version = "0.0.0" + +[lib] +name = "rustc_lint" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } +rustc_front = { path = "../librustc_front" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml new file mode 100644 index 00000000000..62e1a71d196 --- /dev/null +++ b/src/librustc_llvm/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_llvm" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "rustc_llvm" +path = "lib.rs" +crate-type = ["dylib"] + +[features] +static-libstdcpp = [] + +[build-dependencies] +build_helper = { path = "../build_helper" } +gcc = "0.3" diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs new file mode 100644 index 00000000000..1c9982790cf --- /dev/null +++ b/src/librustc_llvm/build.rs @@ -0,0 +1,132 @@ +// 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. + +extern crate gcc; +extern crate build_helper; + +use std::process::Command; +use std::env; +use std::path::PathBuf; + +use build_helper::output; + +fn main() { + println!("cargo:rustc-cfg=cargobuild"); + + let target = env::var("TARGET").unwrap(); + let llvm_config = env::var_os("LLVM_CONFIG").map(PathBuf::from) + .unwrap_or_else(|| { + match env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) { + Some(dir) => { + let to_test = dir.parent().unwrap().parent().unwrap() + .join(&target).join("llvm/bin/llvm-config"); + if Command::new(&to_test).output().is_ok() { + return to_test + } + } + None => {} + } + PathBuf::from("llvm-config") + }); + + println!("cargo:rerun-if-changed={}", llvm_config.display()); + + let optional_components = ["x86", "arm", "aarch64", "mips", "powerpc", + "pnacl"]; + + // FIXME: surely we don't need all these components, right? Stuff like mcjit + // or interpreter the compiler itself never uses. + let required_components = &["ipo", "bitreader", "bitwriter", "linker", + "asmparser", "mcjit", "interpreter", + "instrumentation"]; + + let components = output(Command::new(&llvm_config).arg("--components")); + let mut components = components.split_whitespace().collect::<Vec<_>>(); + components.retain(|c| { + optional_components.contains(c) || required_components.contains(c) + }); + + for component in required_components { + if !components.contains(component) { + panic!("require llvm component {} but wasn't found", component); + } + } + + for component in components.iter() { + println!("cargo:rustc-cfg=llvm_component=\"{}\"", component); + } + + // Link in our own LLVM shims, compiled with the same flags as LLVM + let mut cmd = Command::new(&llvm_config); + cmd.arg("--cxxflags"); + let cxxflags = output(&mut cmd); + let mut cfg = gcc::Config::new(); + for flag in cxxflags.split_whitespace() { + cfg.flag(flag); + } + cfg.file("../rustllvm/ExecutionEngineWrapper.cpp") + .file("../rustllvm/PassWrapper.cpp") + .file("../rustllvm/RustWrapper.cpp") + .file("../rustllvm/ArchiveWrapper.cpp") + .cpp(true) + .cpp_link_stdlib(None) // we handle this below + .compile("librustllvm.a"); + + // Link in all LLVM libraries + let mut cmd = Command::new(&llvm_config); + cmd.arg("--libs").arg("--system-libs").args(&components[..]); + for lib in output(&mut cmd).split_whitespace() { + let name = if lib.starts_with("-l") { + &lib[2..] + } else if lib.starts_with("-") { + &lib[1..] + } else { + continue + }; + + // Don't need or want this library, but LLVM's CMake build system + // doesn't provide a way to disable it, so filter it here even though we + // may or may not have built it. We don't reference anything from this + // library and it otherwise may just pull in extra dependencies on + // libedit which we don't want + if name == "LLVMLineEditor" { + continue + } + + let kind = if name.starts_with("LLVM") {"static"} else {"dylib"}; + println!("cargo:rustc-link-lib={}={}", kind, name); + } + + // LLVM ldflags + let mut cmd = Command::new(&llvm_config); + cmd.arg("--ldflags"); + for lib in output(&mut cmd).split_whitespace() { + if lib.starts_with("-l") { + println!("cargo:rustc-link-lib={}", &lib[2..]); + } else if lib.starts_with("-L") { + println!("cargo:rustc-link-search=native={}", &lib[2..]); + } + } + + // C++ runtime library + if !target.contains("msvc") { + if let Some(s) = env::var_os("LLVM_STATIC_STDCPP") { + assert!(!cxxflags.contains("stdlib=libc++")); + let path = PathBuf::from(s); + println!("cargo:rustc-link-search=native={}", + path.parent().unwrap().display()); + println!("cargo:rustc-link-lib=static=stdc++"); + } else if cxxflags.contains("stdlib=libc++") { + println!("cargo:rustc-link-lib=c++"); + } else { + println!("cargo:rustc-link-lib=stdc++"); + } + } +} diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 059287ccb5e..1933c926e30 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -609,6 +609,9 @@ pub mod debuginfo { // automatically updated whenever LLVM is updated to include an up-to-date // set of the libraries we need to link to LLVM for. #[link(name = "rustllvm", kind = "static")] +#[cfg(not(cargobuild))] +extern {} + #[linked_from = "rustllvm"] // not quite true but good enough extern { /* Create and destroy contexts. */ @@ -2163,53 +2166,6 @@ extern { pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef); } -#[cfg(have_component_x86)] -extern { - pub fn LLVMInitializeX86TargetInfo(); - pub fn LLVMInitializeX86Target(); - pub fn LLVMInitializeX86TargetMC(); - pub fn LLVMInitializeX86AsmPrinter(); - pub fn LLVMInitializeX86AsmParser(); -} -#[cfg(have_component_arm)] -extern { - pub fn LLVMInitializeARMTargetInfo(); - pub fn LLVMInitializeARMTarget(); - pub fn LLVMInitializeARMTargetMC(); - pub fn LLVMInitializeARMAsmPrinter(); - pub fn LLVMInitializeARMAsmParser(); -} -#[cfg(have_component_aarch64)] -extern { - pub fn LLVMInitializeAArch64TargetInfo(); - pub fn LLVMInitializeAArch64Target(); - pub fn LLVMInitializeAArch64TargetMC(); - pub fn LLVMInitializeAArch64AsmPrinter(); - pub fn LLVMInitializeAArch64AsmParser(); -} -#[cfg(have_component_mips)] -extern { - pub fn LLVMInitializeMipsTargetInfo(); - pub fn LLVMInitializeMipsTarget(); - pub fn LLVMInitializeMipsTargetMC(); - pub fn LLVMInitializeMipsAsmPrinter(); - pub fn LLVMInitializeMipsAsmParser(); -} -#[cfg(have_component_powerpc)] -extern { - pub fn LLVMInitializePowerPCTargetInfo(); - pub fn LLVMInitializePowerPCTarget(); - pub fn LLVMInitializePowerPCTargetMC(); - pub fn LLVMInitializePowerPCAsmPrinter(); - pub fn LLVMInitializePowerPCAsmParser(); -} -#[cfg(have_component_pnacl)] -extern { - pub fn LLVMInitializePNaClTargetInfo(); - pub fn LLVMInitializePNaClTarget(); - pub fn LLVMInitializePNaClTargetMC(); -} - // LLVM requires symbols from this library, but apparently they're not printed // during llvm-config? #[cfg(windows)] @@ -2396,20 +2352,14 @@ pub unsafe fn debug_loc_to_string(c: ContextRef, tr: DebugLocRef) -> String { pub fn initialize_available_targets() { macro_rules! init_target( - ($cfg:ident $arch:ident) => { { + ($cfg:meta, $($method:ident),*) => { { #[cfg($cfg)] fn init() { + extern { + $(fn $method();)* + } unsafe { - let f = concat_idents!(LLVMInitialize, $arch, TargetInfo); - f(); - let f = concat_idents!(LLVMInitialize, $arch, Target); - f(); - let f = concat_idents!(LLVMInitialize, $arch, TargetMC); - f(); - let f = concat_idents!(LLVMInitialize, $arch, AsmPrinter); - f(); - let f = concat_idents!(LLVMInitialize, $arch, AsmParser); - f(); + $($method();)* } } #[cfg(not($cfg))] @@ -2417,26 +2367,40 @@ pub fn initialize_available_targets() { init(); } } ); - - init_target!(have_component_powerpc PowerPC); - init_target!(have_component_mips Mips); - init_target!(have_component_aarch64 AArch64); - init_target!(have_component_arm ARM); - init_target!(have_component_x86 X86); - - // PNaCl doesn't provide some of the optional target components, so we - // manually initialize it here. - #[cfg(have_component_pnacl)] - fn init_pnacl() { - unsafe { - LLVMInitializePNaClTargetInfo(); - LLVMInitializePNaClTarget(); - LLVMInitializePNaClTargetMC(); - } - } - #[cfg(not(have_component_pnacl))] - fn init_pnacl() { } - init_pnacl(); + init_target!(llvm_component = "x86", + LLVMInitializeX86TargetInfo, + LLVMInitializeX86Target, + LLVMInitializeX86TargetMC, + LLVMInitializeX86AsmPrinter, + LLVMInitializeX86AsmParser); + init_target!(llvm_component = "arm", + LLVMInitializeARMTargetInfo, + LLVMInitializeARMTarget, + LLVMInitializeARMTargetMC, + LLVMInitializeARMAsmPrinter, + LLVMInitializeARMAsmParser); + init_target!(llvm_component = "aarch64", + LLVMInitializeAArch64TargetInfo, + LLVMInitializeAArch64Target, + LLVMInitializeAArch64TargetMC, + LLVMInitializeAArch64AsmPrinter, + LLVMInitializeAArch64AsmParser); + init_target!(llvm_component = "mips", + LLVMInitializeMipsTargetInfo, + LLVMInitializeMipsTarget, + LLVMInitializeMipsTargetMC, + LLVMInitializeMipsAsmPrinter, + LLVMInitializeMipsAsmParser); + init_target!(llvm_component = "powerpc", + LLVMInitializePowerPCTargetInfo, + LLVMInitializePowerPCTarget, + LLVMInitializePowerPCTargetMC, + LLVMInitializePowerPCAsmPrinter, + LLVMInitializePowerPCAsmParser); + init_target!(llvm_component = "pnacl", + LLVMInitializePNaClTargetInfo, + LLVMInitializePNaClTarget, + LLVMInitializePNaClTargetMC); } pub fn last_error() -> Option<String> { @@ -2486,6 +2450,7 @@ impl Drop for OperandBundleDef { // parts of LLVM that rustllvm depends on aren't thrown away by the linker. // Works to the above fix for #15460 to ensure LLVM dependencies that // are only used by rustllvm don't get stripped by the linker. +#[cfg(not(cargobuild))] mod llvmdeps { include! { env!("CFG_LLVM_LINKAGE_FILE") } } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml new file mode 100644 index 00000000000..3f8249aabf9 --- /dev/null +++ b/src/librustc_metadata/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_metadata" +version = "0.0.0" + +[lib] +name = "rustc_metadata" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +flate = { path = "../libflate" } +log = { path = "../liblog" } +rbml = { path = "../librbml" } +rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } +rustc_front = { path = "../librustc_front" } +rustc_llvm = { path = "../librustc_llvm" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml new file mode 100644 index 00000000000..93817ab0db6 --- /dev/null +++ b/src/librustc_mir/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_mir" +version = "0.0.0" + +[lib] +name = "rustc_mir" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +graphviz = { path = "../libgraphviz" } +log = { path = "../liblog" } +rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_front = { path = "../librustc_front" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml new file mode 100644 index 00000000000..7cc6510fa1f --- /dev/null +++ b/src/librustc_passes/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_passes" +version = "0.0.0" + +[lib] +name = "rustc_passes" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +rustc = { path = "../librustc" } +rustc_front = { path = "../librustc_front" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_platform_intrinsics/Cargo.toml b/src/librustc_platform_intrinsics/Cargo.toml new file mode 100644 index 00000000000..97bf4f854cc --- /dev/null +++ b/src/librustc_platform_intrinsics/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_platform_intrinsics" +version = "0.0.0" + +[lib] +name = "rustc_platform_intrinsics" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +rustc_llvm = { path = "../librustc_llvm" } +rustc = { path = "../librustc" } diff --git a/src/librustc_plugin/Cargo.toml b/src/librustc_plugin/Cargo.toml new file mode 100644 index 00000000000..59cfe158624 --- /dev/null +++ b/src/librustc_plugin/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_plugin" +version = "0.0.0" + +[lib] +name = "rustc_plugin" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +rustc = { path = "../librustc" } +rustc_front = { path = "../librustc_front" } +rustc_metadata = { path = "../librustc_metadata" } +rustc_mir = { path = "../librustc_mir" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_privacy/Cargo.toml b/src/librustc_privacy/Cargo.toml new file mode 100644 index 00000000000..56d6ca5543a --- /dev/null +++ b/src/librustc_privacy/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_privacy" +version = "0.0.0" + +[lib] +name = "rustc_privacy" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +rustc = { path = "../librustc" } +rustc_front = { path = "../librustc_front" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml new file mode 100644 index 00000000000..da01a36d762 --- /dev/null +++ b/src/librustc_resolve/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_resolve" +version = "0.0.0" + +[lib] +name = "rustc_resolve" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +syntax = { path = "../libsyntax" } +rustc = { path = "../librustc" } +rustc_front = { path = "../librustc_front" } +arena = { path = "../libarena" } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml new file mode 100644 index 00000000000..24320c4d563 --- /dev/null +++ b/src/librustc_trans/Cargo.toml @@ -0,0 +1,25 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_trans" +version = "0.0.0" + +[lib] +name = "rustc_trans" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +arena = { path = "../libarena" } +flate = { path = "../libflate" } +getopts = { path = "../libgetopts" } +graphviz = { path = "../libgraphviz" } +log = { path = "../liblog" } +rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_front = { path = "../librustc_front" } +rustc_llvm = { path = "../librustc_llvm" } +rustc_mir = { path = "../librustc_mir" } +rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml new file mode 100644 index 00000000000..fd33e9da1f9 --- /dev/null +++ b/src/librustc_typeck/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_typeck" +version = "0.0.0" + +[lib] +name = "rustc_typeck" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +log = { path = "../liblog" } +syntax = { path = "../libsyntax" } +arena = { path = "../libarena" } +fmt_macros = { path = "../libfmt_macros" } +rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } +rustc_front = { path = "../librustc_front" } +rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } diff --git a/src/librustc_unicode/Cargo.toml b/src/librustc_unicode/Cargo.toml new file mode 100644 index 00000000000..1f4213f0abe --- /dev/null +++ b/src/librustc_unicode/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_unicode" +version = "0.0.0" + +[lib] +name = "rustc_unicode" +path = "lib.rs" +test = false + +[dependencies] +core = { path = "../libcore" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml new file mode 100644 index 00000000000..6b0ad30f450 --- /dev/null +++ b/src/librustdoc/Cargo.toml @@ -0,0 +1,30 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustdoc" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "rustdoc" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +arena = { path = "../libarena" } +getopts = { path = "../libgetopts" } +rustc = { path = "../librustc" } +rustc_back = { path = "../librustc_back" } +rustc_driver = { path = "../librustc_driver" } +rustc_front = { path = "../librustc_front" } +rustc_lint = { path = "../librustc_lint" } +rustc_metadata = { path = "../librustc_metadata" } +rustc_resolve = { path = "../librustc_resolve" } +rustc_trans = { path = "../librustc_trans" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } +test = { path = "../libtest" } +log = { path = "../liblog" } + +[build-dependencies] +build_helper = { path = "../build_helper" } +gcc = "0.3" diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs new file mode 100644 index 00000000000..171954f325a --- /dev/null +++ b/src/librustdoc/build.rs @@ -0,0 +1,27 @@ +// 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. + +extern crate gcc; + +fn main() { + println!("cargo:rustc-cfg=cargobuild"); + let mut cfg = gcc::Config::new(); + cfg.file("../rt/hoedown/src/autolink.c") + .file("../rt/hoedown/src/buffer.c") + .file("../rt/hoedown/src/document.c") + .file("../rt/hoedown/src/escape.c") + .file("../rt/hoedown/src/html.c") + .file("../rt/hoedown/src/html_blocks.c") + .file("../rt/hoedown/src/html_smartypants.c") + .file("../rt/hoedown/src/stack.c") + .file("../rt/hoedown/src/version.c") + .include("../rt/hoedown/src") + .compile("libhoedown.a"); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a5436886a7e..c0846cae687 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -157,6 +157,9 @@ struct hoedown_buffer { // hoedown FFI #[link(name = "hoedown", kind = "static")] +#[cfg(not(cargobuild))] +extern {} + extern { fn hoedown_html_renderer_new(render_flags: libc::c_uint, nesting_level: libc::c_int) diff --git a/src/libserialize/Cargo.toml b/src/libserialize/Cargo.toml new file mode 100644 index 00000000000..919cda49c00 --- /dev/null +++ b/src/libserialize/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "serialize" +version = "0.0.0" + +[lib] +name = "serialize" +path = "lib.rs" +crate-type = ["dylib", "rlib"] + +[dependencies] +log = { path = "../liblog" } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml new file mode 100644 index 00000000000..390c64d7408 --- /dev/null +++ b/src/libstd/Cargo.toml @@ -0,0 +1,30 @@ +[package] +authors = ["The Rust Project Developers"] +name = "std" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "std" +path = "lib.rs" +crate-type = ["dylib", "rlib"] +test = false + +[dependencies] +alloc = { path = "../liballoc" } +alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true } +alloc_system = { path = "../liballoc_system" } +collections = { path = "../libcollections" } +core = { path = "../libcore" } +libc = { path = "../rustc/libc_shim" } +rand = { path = "../librand" } +rustc_bitflags = { path = "../librustc_bitflags" } +rustc_unicode = { path = "../librustc_unicode" } + +[build-dependencies] +build_helper = { path = "../build_helper" } +gcc = "0.3" + +[features] +jemalloc = ["alloc_jemalloc"] +debug-jemalloc = ["alloc_jemalloc/debug"] diff --git a/src/libstd/build.rs b/src/libstd/build.rs new file mode 100644 index 00000000000..8fb49a1be4e --- /dev/null +++ b/src/libstd/build.rs @@ -0,0 +1,112 @@ +// 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. + +extern crate gcc; +extern crate build_helper; + +use std::env; +use std::fs; +use std::path::PathBuf; +use std::process::Command; + +use build_helper::run; + +fn main() { + println!("cargo:rustc-cfg=cargobuild"); + + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + if !target.contains("apple") && !target.contains("msvc") { + build_libbacktrace(&host, &target); + } + + if target.contains("unknown-linux") { + if target.contains("musl") { + println!("cargo:rustc-link-lib=static=unwind"); + } else { + println!("cargo:rustc-link-lib=dl"); + println!("cargo:rustc-link-lib=rt"); + println!("cargo:rustc-link-lib=pthread"); + println!("cargo:rustc-link-lib=gcc_s"); + } + } else if target.contains("android") { + println!("cargo:rustc-link-lib=dl"); + println!("cargo:rustc-link-lib=log"); + println!("cargo:rustc-link-lib=gcc"); + } else if target.contains("freebsd") { + println!("cargo:rustc-link-lib=execinfo"); + println!("cargo:rustc-link-lib=pthread"); + println!("cargo:rustc-link-lib=gcc_s"); + } else if target.contains("dragonfly") || target.contains("bitrig") || + target.contains("netbsd") || target.contains("openbsd") { + println!("cargo:rustc-link-lib=pthread"); + + if target.contains("rumprun") { + println!("cargo:rustc-link-lib=unwind"); + } else if target.contains("netbsd") || target.contains("openbsd") { + println!("cargo:rustc-link-lib=gcc"); + } else if target.contains("bitrig") { + println!("cargo:rustc-link-lib=c++abi"); + } else if target.contains("dragonfly") { + println!("cargo:rustc-link-lib=gcc_pic"); + } + } else if target.contains("apple-darwin") { + println!("cargo:rustc-link-lib=System"); + } else if target.contains("apple-ios") { + println!("cargo:rustc-link-lib=System"); + println!("cargo:rustc-link-lib=objc"); + println!("cargo:rustc-link-lib=framework=Security"); + println!("cargo:rustc-link-lib=framework=Foundation"); + } else if target.contains("windows") { + if target.contains("windows-gnu") { + println!("cargo:rustc-link-lib=gcc_eh"); + } + println!("cargo:rustc-link-lib=advapi32"); + println!("cargo:rustc-link-lib=ws2_32"); + println!("cargo:rustc-link-lib=userenv"); + println!("cargo:rustc-link-lib=shell32"); + } +} + +fn build_libbacktrace(host: &str, target: &str) { + let src_dir = env::current_dir().unwrap().join("../libbacktrace"); + let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + println!("cargo:rustc-link-lib=static=backtrace"); + println!("cargo:rustc-link-search=native={}/.libs", build_dir.display()); + + if fs::metadata(&build_dir.join(".libs/libbacktrace.a")).is_ok() { + return + } + + let compiler = gcc::Config::new().get_compiler(); + let ar = build_helper::cc2ar(compiler.path(), target); + let cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) + .collect::<Vec<_>>().join(" "); + run(Command::new("sh") + .current_dir(&build_dir) + .arg(src_dir.join("configure").to_str().unwrap() + .replace("C:\\", "/c/") + .replace("\\", "/")) + .arg("--with-pic") + .arg("--disable-multilib") + .arg("--disable-shared") + .arg("--disable-host-shared") + .arg(format!("--host={}", build_helper::gnu_target(target))) + .arg(format!("--build={}", build_helper::gnu_target(host))) + .env("CC", compiler.path()) + .env("AR", &ar) + .env("RANLIB", format!("{} s", ar.display())) + .env("CFLAGS", cflags)); + run(Command::new("make") + .current_dir(&build_dir) + .arg(format!("INCDIR={}", src_dir.display())) + .arg("-j").arg(env::var("NUM_JOBS").unwrap())); +} diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 8d92909faf5..8a422246514 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -269,7 +269,10 @@ mod imp { const kSecRandomDefault: *const SecRandom = ptr::null(); #[link(name = "Security", kind = "framework")] - extern "C" { + #[cfg(not(cargobuild))] + extern {} + + extern { fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int; } diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index b1b9ffc4dc6..a11200873d5 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -12,6 +12,8 @@ //! the standard library This varies per-platform, but these libraries are //! necessary for running libstd. +#![cfg(not(cargobuild))] + // LLVM implements the `frem` instruction as a call to `fmod`, which lives in // libm. Hence, we must explicitly link to it. // diff --git a/src/libstd/sys/common/gnu/libbacktrace.rs b/src/libstd/sys/common/gnu/libbacktrace.rs index f8463388384..8b3cb04030c 100644 --- a/src/libstd/sys/common/gnu/libbacktrace.rs +++ b/src/libstd/sys/common/gnu/libbacktrace.rs @@ -40,7 +40,7 @@ pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, errnum: libc::c_int); enum backtrace_state {} #[link(name = "backtrace", kind = "static")] - #[cfg(not(test))] + #[cfg(all(not(test), not(cargobuild)))] extern {} extern { diff --git a/src/libstd/sys/common/unwind/gcc.rs b/src/libstd/sys/common/unwind/gcc.rs index 12cd07a4f4f..7cf9e2a54bd 100644 --- a/src/libstd/sys/common/unwind/gcc.rs +++ b/src/libstd/sys/common/unwind/gcc.rs @@ -252,6 +252,9 @@ pub mod eh_frame_registry { // See also: rtbegin.rs, `unwind` module. #[link(name = "gcc_eh")] + #[cfg(not(cargobuild))] + extern {} + extern { fn __register_frame_info(eh_frame_begin: *const u8, object: *mut u8); fn __deregister_frame_info(eh_frame_begin: *const u8, object: *mut u8); diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 9def3adc303..b6a0bd84409 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -339,7 +339,6 @@ pub fn args() -> Args { pub fn args() -> Args { use mem; - #[link(name = "objc")] extern { fn sel_registerName(name: *const libc::c_uchar) -> Sel; fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; @@ -347,6 +346,8 @@ pub fn args() -> Args { } #[link(name = "Foundation", kind = "framework")] + #[link(name = "objc")] + #[cfg(not(cargobuild))] extern {} type Sel = *const libc::c_void; diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 6e8090a2235..9fdeb0aef14 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -966,6 +966,9 @@ pub enum EXCEPTION_DISPOSITION { #[link(name = "userenv")] #[link(name = "shell32")] #[link(name = "advapi32")] +#[cfg(not(cargobuild))] +extern {} + extern "system" { pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml new file mode 100644 index 00000000000..3a1d18b85b6 --- /dev/null +++ b/src/libsyntax/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["The Rust Project Developers"] +name = "syntax" +version = "0.0.0" + +[lib] +name = "syntax" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +arena = { path = "../libarena" } +fmt_macros = { path = "../libfmt_macros" } +serialize = { path = "../libserialize" } +term = { path = "../libterm" } +log = { path = "../liblog" } diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml new file mode 100644 index 00000000000..e137815cd32 --- /dev/null +++ b/src/libsyntax_ext/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "syntax_ext" +version = "0.0.0" + +[lib] +name = "syntax_ext" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +fmt_macros = { path = "../libfmt_macros" } +syntax = { path = "../libsyntax" } diff --git a/src/libterm/Cargo.toml b/src/libterm/Cargo.toml new file mode 100644 index 00000000000..cdfc957297d --- /dev/null +++ b/src/libterm/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "term" +version = "0.0.0" + +[lib] +name = "term" +path = "lib.rs" +crate-type = ["dylib", "rlib"] + +[dependencies] +log = { path = "../liblog" } diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml new file mode 100644 index 00000000000..96a84496b9c --- /dev/null +++ b/src/libtest/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "test" +version = "0.0.0" + +[lib] +name = "test" +path = "lib.rs" +crate-type = ["dylib", "rlib"] + +[dependencies] +getopts = { path = "../libgetopts" } +term = { path = "../libterm" } +serialize = { path = "../libserialize" } diff --git a/src/nightlies.txt b/src/nightlies.txt new file mode 100644 index 00000000000..86186222d90 --- /dev/null +++ b/src/nightlies.txt @@ -0,0 +1,2 @@ +rustc: 2015-12-19 +cargo: 2016-01-21 diff --git a/src/rustbook/Cargo.toml b/src/rustbook/Cargo.toml new file mode 100644 index 00000000000..c684c474efa --- /dev/null +++ b/src/rustbook/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustbook" +version = "0.0.0" + +[lib] +name = "rustbook" +path = "main.rs" +crate-type = ["dylib"] + +[dependencies] +rustc_back = { path = "../librustc_back" } +rustdoc = { path = "../librustdoc" } diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs index e8345dc9586..bd4fc899293 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -36,7 +36,7 @@ mod test; static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT; -fn main() { +pub fn main() { let mut term = Term::new(); let cmd: Vec<_> = env::args().collect(); diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock new file mode 100644 index 00000000000..2a7da33bb68 --- /dev/null +++ b/src/rustc/Cargo.lock @@ -0,0 +1,368 @@ +[root] +name = "rustc-main" +version = "0.0.0" +dependencies = [ + "rustbook 0.0.0", + "rustc_back 0.0.0", + "rustc_driver 0.0.0", + "rustdoc 0.0.0", +] + +[[package]] +name = "advapi32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arena" +version = "0.0.0" + +[[package]] +name = "build_helper" +version = "0.1.0" + +[[package]] +name = "flate" +version = "0.0.0" +dependencies = [ + "build_helper 0.1.0", + "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fmt_macros" +version = "0.0.0" + +[[package]] +name = "gcc" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getopts" +version = "0.0.0" + +[[package]] +name = "graphviz" +version = "0.0.0" + +[[package]] +name = "log" +version = "0.0.0" + +[[package]] +name = "rbml" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "serialize 0.0.0", +] + +[[package]] +name = "rustbook" +version = "0.0.0" +dependencies = [ + "rustc_back 0.0.0", + "rustdoc 0.0.0", +] + +[[package]] +name = "rustc" +version = "0.0.0" +dependencies = [ + "arena 0.0.0", + "flate 0.0.0", + "fmt_macros 0.0.0", + "getopts 0.0.0", + "graphviz 0.0.0", + "log 0.0.0", + "rbml 0.0.0", + "rustc_back 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_front 0.0.0", + "rustc_llvm 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_back" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "rustc_front 0.0.0", + "rustc_llvm 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_borrowck" +version = "0.0.0" +dependencies = [ + "graphviz 0.0.0", + "log 0.0.0", + "rustc 0.0.0", + "rustc_front 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_data_structures" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "serialize 0.0.0", +] + +[[package]] +name = "rustc_driver" +version = "0.0.0" +dependencies = [ + "arena 0.0.0", + "flate 0.0.0", + "getopts 0.0.0", + "graphviz 0.0.0", + "log 0.0.0", + "rustc 0.0.0", + "rustc_back 0.0.0", + "rustc_borrowck 0.0.0", + "rustc_front 0.0.0", + "rustc_lint 0.0.0", + "rustc_llvm 0.0.0", + "rustc_metadata 0.0.0", + "rustc_mir 0.0.0", + "rustc_passes 0.0.0", + "rustc_plugin 0.0.0", + "rustc_privacy 0.0.0", + "rustc_resolve 0.0.0", + "rustc_trans 0.0.0", + "rustc_typeck 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", + "syntax_ext 0.0.0", +] + +[[package]] +name = "rustc_front" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_lint" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "rustc 0.0.0", + "rustc_back 0.0.0", + "rustc_front 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_llvm" +version = "0.0.0" +dependencies = [ + "build_helper 0.1.0", + "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_metadata" +version = "0.0.0" +dependencies = [ + "flate 0.0.0", + "log 0.0.0", + "rbml 0.0.0", + "rustc 0.0.0", + "rustc_back 0.0.0", + "rustc_front 0.0.0", + "rustc_llvm 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_mir" +version = "0.0.0" +dependencies = [ + "graphviz 0.0.0", + "log 0.0.0", + "rustc 0.0.0", + "rustc_back 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_front 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_passes" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "rustc 0.0.0", + "rustc_front 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_platform_intrinsics" +version = "0.0.0" +dependencies = [ + "rustc 0.0.0", + "rustc_llvm 0.0.0", +] + +[[package]] +name = "rustc_plugin" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "rustc 0.0.0", + "rustc_front 0.0.0", + "rustc_metadata 0.0.0", + "rustc_mir 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_privacy" +version = "0.0.0" +dependencies = [ + "log 0.0.0", + "rustc 0.0.0", + "rustc_front 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_resolve" +version = "0.0.0" +dependencies = [ + "arena 0.0.0", + "log 0.0.0", + "rustc 0.0.0", + "rustc_front 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_trans" +version = "0.0.0" +dependencies = [ + "arena 0.0.0", + "flate 0.0.0", + "getopts 0.0.0", + "graphviz 0.0.0", + "log 0.0.0", + "rustc 0.0.0", + "rustc_back 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_front 0.0.0", + "rustc_llvm 0.0.0", + "rustc_mir 0.0.0", + "rustc_platform_intrinsics 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustc_typeck" +version = "0.0.0" +dependencies = [ + "arena 0.0.0", + "fmt_macros 0.0.0", + "log 0.0.0", + "rustc 0.0.0", + "rustc_back 0.0.0", + "rustc_front 0.0.0", + "rustc_platform_intrinsics 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "rustdoc" +version = "0.0.0" +dependencies = [ + "arena 0.0.0", + "build_helper 0.1.0", + "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.0.0", + "log 0.0.0", + "rustc 0.0.0", + "rustc_back 0.0.0", + "rustc_driver 0.0.0", + "rustc_front 0.0.0", + "rustc_lint 0.0.0", + "rustc_metadata 0.0.0", + "rustc_resolve 0.0.0", + "rustc_trans 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", + "test 0.0.0", +] + +[[package]] +name = "serialize" +version = "0.0.0" +dependencies = [ + "log 0.0.0", +] + +[[package]] +name = "syntax" +version = "0.0.0" +dependencies = [ + "arena 0.0.0", + "fmt_macros 0.0.0", + "log 0.0.0", + "serialize 0.0.0", + "term 0.0.0", +] + +[[package]] +name = "syntax_ext" +version = "0.0.0" +dependencies = [ + "fmt_macros 0.0.0", + "syntax 0.0.0", +] + +[[package]] +name = "term" +version = "0.0.0" +dependencies = [ + "log 0.0.0", +] + +[[package]] +name = "test" +version = "0.0.0" +dependencies = [ + "getopts 0.0.0", + "serialize 0.0.0", + "term 0.0.0", +] + +[[package]] +name = "winapi" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml new file mode 100644 index 00000000000..9fcefd9d3a4 --- /dev/null +++ b/src/rustc/Cargo.toml @@ -0,0 +1,36 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc-main" +version = "0.0.0" + +[[bin]] +name = "rustc" +path = "rustc.rs" + +[[bin]] +name = "rustdoc" +path = "rustdoc.rs" + +[[bin]] +name = "rustbook" +path = "rustbook.rs" + +[profile.release] +opt-level = 2 + +# These options are controlled from our rustc wrapper script, so turn them off +# here and have them controlled elsewhere. +[profile.dev] +debug = false +debug-assertions = false + +# All optional dependencies so the features passed to this Cargo.toml select +# what should actually be built. +[dependencies] +rustbook = { path = "../rustbook", optional = true } +rustc_back = { path = "../librustc_back" } +rustc_driver = { path = "../librustc_driver" } +rustdoc = { path = "../librustdoc", optional = true } + +[features] +jemalloc = ["rustc_back/jemalloc"] diff --git a/src/rustc/libc_shim/Cargo.toml b/src/rustc/libc_shim/Cargo.toml new file mode 100644 index 00000000000..a7860b50e08 --- /dev/null +++ b/src/rustc/libc_shim/Cargo.toml @@ -0,0 +1,20 @@ +# This is a shim Cargo.toml over the "real Cargo.toml" found in the libc +# repository itself. The purpose for this is to add a build script which prints +# out `--cfg stdbuild` to mirror the makefiles' build system. +# +# Note that other than that this isn't actually needed, and we should probably +# remove this shim in favor of just working with cargo features directly with +# libc. That should make everything nicer! + +[package] +name = "libc" +version = "0.0.0" +authors = ["The Rust Project Developers"] +build = "build.rs" + +[lib] +name = "libc" +path = "../../liblibc/src/lib.rs" + +[dependencies] +core = { path = "../../libcore" } diff --git a/src/rustc/libc_shim/build.rs b/src/rustc/libc_shim/build.rs new file mode 100644 index 00000000000..bc428d69082 --- /dev/null +++ b/src/rustc/libc_shim/build.rs @@ -0,0 +1,15 @@ +// 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. + +// See comments in Cargo.toml for why this exists + +fn main() { + println!("cargo:rustc-cfg=stdbuild"); +} diff --git a/src/rustc/rustbook.rs b/src/rustc/rustbook.rs new file mode 100644 index 00000000000..6f78f78bc55 --- /dev/null +++ b/src/rustc/rustbook.rs @@ -0,0 +1,14 @@ +// 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. + +extern crate rustbook; + +fn main() { rustbook::main() } + diff --git a/src/rustc/rustc.rs b/src/rustc/rustc.rs new file mode 100644 index 00000000000..bfd01146d2c --- /dev/null +++ b/src/rustc/rustc.rs @@ -0,0 +1,15 @@ +// 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. + +#![feature(rustc_private)] + +extern crate rustc_driver; + +fn main() { rustc_driver::main() } diff --git a/src/rustc/rustdoc.rs b/src/rustc/rustdoc.rs new file mode 100644 index 00000000000..6fecd3a27a8 --- /dev/null +++ b/src/rustc/rustdoc.rs @@ -0,0 +1,15 @@ +// 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. + +#![feature(rustdoc)] + +extern crate rustdoc; + +fn main() { rustdoc::main() } diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock new file mode 100644 index 00000000000..d88e9c7e5aa --- /dev/null +++ b/src/rustc/std_shim/Cargo.lock @@ -0,0 +1,124 @@ +[root] +name = "std_shim" +version = "0.1.0" +dependencies = [ + "std 0.0.0", +] + +[[package]] +name = "advapi32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "alloc" +version = "0.0.0" +dependencies = [ + "alloc_system 0.0.0", + "core 0.0.0", + "libc 0.0.0", +] + +[[package]] +name = "alloc_jemalloc" +version = "0.0.0" +dependencies = [ + "build_helper 0.1.0", + "core 0.0.0", + "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.0.0", +] + +[[package]] +name = "alloc_system" +version = "0.0.0" +dependencies = [ + "core 0.0.0", + "libc 0.0.0", +] + +[[package]] +name = "build_helper" +version = "0.1.0" + +[[package]] +name = "collections" +version = "0.0.0" +dependencies = [ + "alloc 0.0.0", + "core 0.0.0", + "rustc_unicode 0.0.0", +] + +[[package]] +name = "core" +version = "0.0.0" + +[[package]] +name = "gcc" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.0.0" +dependencies = [ + "core 0.0.0", +] + +[[package]] +name = "rand" +version = "0.0.0" +dependencies = [ + "core 0.0.0", +] + +[[package]] +name = "rustc_bitflags" +version = "0.0.0" +dependencies = [ + "core 0.0.0", +] + +[[package]] +name = "rustc_unicode" +version = "0.0.0" +dependencies = [ + "core 0.0.0", +] + +[[package]] +name = "std" +version = "0.0.0" +dependencies = [ + "alloc 0.0.0", + "alloc_jemalloc 0.0.0", + "alloc_system 0.0.0", + "build_helper 0.1.0", + "collections 0.0.0", + "core 0.0.0", + "gcc 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.0.0", + "rand 0.0.0", + "rustc_bitflags 0.0.0", + "rustc_unicode 0.0.0", +] + +[[package]] +name = "winapi" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml new file mode 100644 index 00000000000..1ce3937157d --- /dev/null +++ b/src/rustc/std_shim/Cargo.toml @@ -0,0 +1,46 @@ +# This is a shim Cargo.toml which serves as a proxy for building the standard +# library. The reason for this is a little subtle, as one might reasonably +# expect that we just `cargo build` the standard library itself. +# +# One of the output artifacts for the standard library is a dynamic library, and +# on platforms like OSX the name of the output artifact is actually encoded into +# the library itself (similar to a soname on Linux). When the library is linked +# against, this encoded name is what's literally looked for at runtime when the +# dynamic loader is probing for libraries. +# +# Cargo, however, by default will not mangle the output filename of the +# top-level target. If we were to run `cargo build` on libstd itself, we would +# generate a file `libstd.so`. When installing, however, this file is called +# something like `libstd-abcdef0123.so`. On OSX at least this causes a failure +# at runtime because the encoded "soname" is `libstd.so`, not what the file is +# actually called. +# +# By using this shim library to build the standard library by proxy we sidestep +# this problem. The standard library is built with mangled hex already in its +# name so there's nothing extra we need to do. + +[package] +name = "std_shim" +version = "0.1.0" +authors = ["The Rust Project Developers"] + +[lib] +name = "std_shim" +path = "lib.rs" + +[profile.release] +opt-level = 2 + +# These options are controlled from our rustc wrapper script, so turn them off +# here and have them controlled elsewhere. +[profile.dev] +debug = false +debug-assertions = false + +[dependencies] +std = { path = "../../libstd" } + +# Reexport features from std +[features] +jemalloc = ["std/jemalloc"] +debug-jemalloc = ["std/debug-jemalloc"] diff --git a/src/rustc/std_shim/lib.rs b/src/rustc/std_shim/lib.rs new file mode 100644 index 00000000000..3cf4cfab135 --- /dev/null +++ b/src/rustc/std_shim/lib.rs @@ -0,0 +1,11 @@ +// 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. + +// See comments in Cargo.toml for why this exists |
