Skip to content

Commit 78a5d5b

Browse files
committed
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
2 parents 98ec51a + 55dd595 commit 78a5d5b

File tree

94 files changed

+4598
-95
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+4598
-95
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,4 @@ tmp.*.rs
9393
version.md
9494
version.ml
9595
version.texi
96+
/target

configure

+16-4
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
606606
opt dist-host-only 0 "only install bins for the host architecture"
607607
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
608608
opt llvm-version-check 1 "check if the LLVM version is supported, build anyway"
609+
opt rustbuild 0 "use the rust and cargo based build system"
609610

610611
# Optimization and debugging options. These may be overridden by the release channel, etc.
611612
opt_nosave optimize 1 "build optimized rust code"
@@ -625,7 +626,7 @@ valopt llvm-root "" "set LLVM root"
625626
valopt python "" "set path to python"
626627
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
627628
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
628-
valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path (deprecated)"
629+
valopt android-cross-path "" "Android NDK standalone path (deprecated)"
629630
valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path"
630631
valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
631632
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
@@ -1422,7 +1423,7 @@ done
14221423
step_msg "configuring submodules"
14231424

14241425
# Have to be in the top of src directory for this
1425-
if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ]
1426+
if [ -z $CFG_DISABLE_MANAGE_SUBMODULES ] && [ -z $CFG_ENABLE_RUSTBUILD ]
14261427
then
14271428
cd ${CFG_SRC_DIR}
14281429

@@ -1481,7 +1482,11 @@ do
14811482
;;
14821483
esac
14831484

1484-
if [ -z $CFG_LLVM_ROOT ]
1485+
if [ -n "$CFG_ENABLE_RUSTBUILD" ]
1486+
then
1487+
msg "not configuring LLVM, rustbuild in use"
1488+
do_reconfigure=0
1489+
elif [ -z $CFG_LLVM_ROOT ]
14851490
then
14861491
LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm
14871492
if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]
@@ -1812,8 +1817,15 @@ do
18121817
putvar $CFG_LLVM_INST_DIR
18131818
done
18141819

1820+
if [ -n "$CFG_ENABLE_RUSTBUILD" ]
1821+
then
1822+
INPUT_MAKEFILE=src/bootstrap/mk/Makefile.in
1823+
else
1824+
INPUT_MAKEFILE=Makefile.in
1825+
fi
1826+
18151827
msg
1816-
copy_if_changed ${CFG_SRC_DIR}Makefile.in ./Makefile
1828+
copy_if_changed ${CFG_SRC_DIR}${INPUT_MAKEFILE} ./Makefile
18171829
move_if_changed config.tmp config.mk
18181830
rm -f config.tmp
18191831
touch config.stamp

mk/crates.mk

+1-2
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ TARGET_CRATES += alloc_jemalloc
144144
DEPS_std += alloc_jemalloc
145145
DEPS_alloc_jemalloc := core libc native:jemalloc
146146
ONLY_RLIB_alloc_jemalloc := 1
147-
else
148-
RUSTFLAGS_rustc_back := --cfg disable_jemalloc
147+
RUSTFLAGS_rustc_back := --cfg 'feature="jemalloc"'
149148
endif
150149

151150
################################################################################

mk/llvm.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ $(foreach host,$(CFG_HOST), \
102102
define LLVM_LINKAGE_DEPS
103103
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.rustc_llvm: $$(LLVM_LINKAGE_PATH_$(2))
104104
RUSTFLAGS$(1)_rustc_llvm_T_$(2) += $$(shell echo $$(LLVM_ALL_COMPONENTS_$(2)) | tr '-' '_' |\
105-
sed -e 's/^ //;s/\([^ ]*\)/\-\-cfg have_component_\1/g')
105+
sed -e 's/^ //;s/\([^ ]*\)/\-\-cfg "llvm_component=\\"\1\\""/g')
106106
endef
107107

108108
$(foreach source,$(CFG_HOST), \

src/bootstrap/Cargo.lock

+109
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bootstrap/Cargo.toml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[package]
2+
authors = ["The Rust Project Developers"]
3+
name = "bootstrap"
4+
version = "0.0.0"
5+
6+
[lib]
7+
name = "bootstrap"
8+
path = "lib.rs"
9+
10+
[[bin]]
11+
name = "bootstrap"
12+
path = "main.rs"
13+
14+
[[bin]]
15+
name = "rustc"
16+
path = "rustc.rs"
17+
18+
[dependencies]
19+
build_helper = { path = "../build_helper" }
20+
cmake = "0.1.10"
21+
filetime = "0.1"
22+
num_cpus = "0.2"
23+
toml = "0.1"
24+
getopts = "0.2"
25+
rustc-serialize = "0.3"
26+
winapi = "0.2"
27+
kernel32-sys = "0.2"
28+
gcc = "0.3.17"
29+
libc = "0.2"

src/bootstrap/README.md

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Bootstrapping Rust
2+
3+
This is an in-progress README which is targeted at helping to explain how Rust
4+
is bootstrapped and in general some of the technical details of the build
5+
system.
6+
7+
> **Note**: This build system is currently under active development and is not
8+
> intended to be the primarily used one just yet. The makefiles are currently
9+
> the ones that are still "guaranteed to work" as much as possible at least.
10+
11+
## Using the new build system
12+
13+
When configuring Rust via `./configure`, pass the following to enable building
14+
via this build system:
15+
16+
```
17+
./configure --enable-rustbuild
18+
```
19+
20+
## ...
21+
22+
## Directory Layout
23+
24+
This build system houses all output under the `target` directory, which looks
25+
like this:
26+
27+
```
28+
# Root folder of all output. Everything is scoped underneath here
29+
build/
30+
31+
# Location where the stage0 compiler downloads are all cached. This directory
32+
# only contains the tarballs themselves as they're extracted elsewhere.
33+
cache/
34+
2015-12-19/
35+
2016-01-15/
36+
2016-01-21/
37+
...
38+
39+
# Output directory for building this build system itself. The stage0
40+
# cargo/rustc are used to build the build system into this location.
41+
bootstrap/
42+
debug/
43+
release/
44+
45+
# Each remaining directory is scoped by the "host" triple of compilation at
46+
# hand.
47+
x86_64-unknown-linux-gnu/
48+
49+
# The build artifacts for the `compiler-rt` library for the target this
50+
# folder is under. The exact layout here will likely depend on the platform,
51+
# and this is also built with CMake so the build system is also likely
52+
# different.
53+
compiler-rt/build/
54+
55+
# Output folder for LLVM if it is compiled for this target
56+
llvm/
57+
58+
# build folder (e.g. the platform-specific build system). Like with
59+
# compiler-rt this is compiled with CMake
60+
build/
61+
62+
# Installation of LLVM. Note that we run the equivalent of 'make install'
63+
# for LLVM to setup these folders.
64+
bin/
65+
lib/
66+
include/
67+
share/
68+
...
69+
70+
# Location where the stage0 Cargo and Rust compiler are unpacked. This
71+
# directory is purely an extracted and overlaid tarball of these two (done
72+
# by the bootstrapy python script). In theory the build system does not
73+
# modify anything under this directory afterwards.
74+
stage0/
75+
76+
# These to build directories are the cargo output directories for builds of
77+
# the standard library and compiler, respectively. Internally these may also
78+
# have other target directories, which represent artifacts being compiled
79+
# from the host to the specified target.
80+
#
81+
# Essentially, each of these directories is filled in by one `cargo`
82+
# invocation. The build system instruments calling Cargo in the right order
83+
# with the right variables to ensure these are filled in correctly.
84+
stageN-std/
85+
stageN-rustc/
86+
87+
# This is a special case of the above directories, **not** filled in via
88+
# Cargo but rather the build system itself. The stage0 compiler already has
89+
# a set of target libraries for its own host triple (in its own sysroot)
90+
# inside of stage0/. When we run the stage0 compiler to bootstrap more
91+
# things, however, we don't want to use any of these libraries (as those are
92+
# the ones that we're building). So essentially, when the stage1 compiler is
93+
# being compiled (e.g. after libstd has been built), *this* is used as the
94+
# sysroot for the stage0 compiler being run.
95+
#
96+
# Basically this directory is just a temporary artifact use to configure the
97+
# stage0 compiler to ensure that the libstd we just built is used to
98+
# compile the stage1 compiler.
99+
stage0-rustc/lib/
100+
101+
# These output directories are intended to be standalone working
102+
# implementations of the compiler (corresponding to each stage). The build
103+
# system will link (using hard links) output from stageN-{std,rustc} into
104+
# each of these directories.
105+
#
106+
# In theory there is no extra build output in these directories.
107+
stage1/
108+
stage2/
109+
stage3/
110+
```

0 commit comments

Comments
 (0)