about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in104
-rwxr-xr-xconfigure5
-rw-r--r--mk/clean.mk11
-rw-r--r--mk/fuzzer.mk23
-rw-r--r--mk/host.mk56
-rw-r--r--mk/install.mk5
-rw-r--r--mk/snap.mk9
-rw-r--r--mk/stage0.mk15
-rw-r--r--mk/stageN.mk113
-rw-r--r--mk/target.mk61
10 files changed, 235 insertions, 167 deletions
diff --git a/Makefile.in b/Makefile.in
index 39bb0d0e1b6..e401ec0ab33 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,3 +1,47 @@
+# An explanation of how the build is structured:
+#
+# There are multiple build stages (0-3) needed to verify that the
+# compiler is properly self-hosting. Each stage is divided between
+# 'host' artifacts and 'target' artifacts, where the stageN host
+# compiler builds artifacts for 1 or more stageN target architectures.
+# Once the stageN target compiler has been built for the host
+# architecture it is promoted (copied) to a stageN+1 host artifact.
+#
+# The stage3 host compiler is a compiler that successfully builds
+# itself and should (in theory) be bitwise identical to the stage2
+# host compiler. The process is bootstrapped using a stage0 host
+# compiler downloaded from a previous snapshot.
+#
+# At no time should stageN artifacts be interacting with artifacts
+# from other stages. For consistency, we use the 'promotion' logic
+# for all artifacts, even those that don't make sense on non-host
+# architectures.
+#
+# The directory layout for a stage is intended to match the layout
+# of the installed compiler, and looks like the following:
+#
+# stageN - this is the system root, corresponding to, e.g. /usr
+#   bin - binaries compiled for the host
+#   lib - libraries used by the host compiler
+#     rustc - rustc's own place to organize libraries
+#       $(target) - target-specific artifacts
+#         bin - binaries for target architectures
+#         lib - libraries for target architectures
+#
+# A note about host libraries:
+#
+# The only libraries that get promoted to stageN/lib are those needed
+# by rustc. In general, rustc programs, even those compiled for the
+# host architecture will use libraries from the target
+# directories. This gives rust some freedom to experiment with how
+# libraries are managed and versioned without polluting the common
+# areas of the filesystem.
+#
+# General rust binaries may stil live in the host bin directory; they
+# will just link against the libraries in the target lib directory.
+#
+# Admittedly this is a little convoluted.
+
 ######################################################################
 # Residual auto-configuration
 ######################################################################
@@ -142,12 +186,16 @@ COMPILER_INPUTS := $(wildcard $(addprefix $(S)src/comp/, \
 # Exports for sub-utilities
 ######################################################################
 
+# Note that any variable that re-configure should pick up needs to be
+# exported
+
 export CFG_SRC_DIR
 export CFG_BUILD_DIR
 export CFG_VERSION
 export CFG_HOST_TRIPLE
 export CFG_LLVM_ROOT
 export CFG_ENABLE_MINGW_CROSS
+export CFG_PREFIX
 
 ######################################################################
 # Subprograms
@@ -179,33 +227,34 @@ TARGET_HOST_ROOT$(1) = $$(TARGET_ROOT$(1)$$(CFG_HOST_TRIPLE))
 TARGET_HOST_BIN$(1) = $$(TARGET_BIN$(1)$$(CFG_HOST_TRIPLE))
 TARGET_HOST_LIB$(1) = $$(TARGET_LIB$(1)$$(CFG_HOST_TRIPLE))
 
+# The name of the standard library used by rustc
 ifdef CFG_DISABLE_SHAREDSTD
   HOST_STDLIB_DEFAULT$(1) = $$(HOST_LIB$(1))/libstd.rlib
+  TARGET_STDLIB_DEFAULT$(1)$(2) = $$(TARGET_LIB$(1)$(2))/libstd.rlib
 else
   HOST_STDLIB_DEFAULT$(1) = $$(HOST_LIB$(1))/$(CFG_STDLIB)
+  TARGET_STDLIB_DEFAULT$(1)$(2) = $$(TARGET_LIB$(1)$(2))/$(CFG_STDLIB)
 endif
 
-ifdef CFG_DISABLE_SHAREDSTD
-SREQ$(1)$(2) = $$(HOST_BIN$(1))/rustc$(X)          \
-           $$(HOST_LIB$(1))/$$(CFG_RUNTIME)     \
-           $$(HOST_STDLIB_DEFAULT$(1)) \
-           $$(HOST_LIB$(1))/$$(CFG_RUSTLLVM)    \
-           $$(TARGET_LIB$(1)$(2))/$$(CFG_RUNTIME) \
-           $$(TARGET_LIB$(1)$(2))/$$(CFG_STDLIB) \
-           $$(TARGET_LIB$(1)$(2))/intrinsics.bc \
-           $$(TARGET_LIB$(1)$(2))/main.o \
-           $$(MKFILES)
-else
-SREQ$(1)$(2) = $$(HOST_BIN$(1))/rustc$(X)          \
-           $$(HOST_LIB$(1))/$$(CFG_RUNTIME)     \
-           $$(HOST_STDLIB_DEFAULT$(1)) \
-           $$(HOST_LIB$(1))/$$(CFG_RUSTLLVM)    \
-           $$(TARGET_LIB$(1)$(2))/$$(CFG_RUNTIME) \
-           $$(TARGET_LIB$(1)$(2))/$$(CFG_STDLIB) \
-           $$(TARGET_LIB$(1)$(2))/intrinsics.bc \
-           $$(TARGET_LIB$(1)$(2))/main.o \
-           $$(MKFILES)
-endif
+# Preqrequisites for using the stageN compiler
+HOST_SREQ$(1) = \
+	$$(HOST_BIN$(1))/rustc$$(X) \
+	$$(HOST_LIB$(1))/$$(CFG_RUNTIME) \
+	$$(HOST_LIB$(1))/$$(CFG_RUSTLLVM) \
+	$$(HOST_STDLIB_DEFAULT$(1)) \
+	$$(MKFILES)
+
+# Prerequisites for using the stageN compiler to build target artifacts
+TARGET_SREQ$(1)$(2) = \
+	$$(HOST_SREQ$(1)) \
+	$$(TARGET_LIB$(1)$(2))/$$(CFG_RUNTIME) \
+	$$(TARGET_LIB$(1)$(2))/intrinsics.bc \
+	$$(TARGET_LIB$(1)$(2))/main.o
+
+# Prerequisites for complete stageN targets
+SREQ$(1)$(2) = \
+	$$(TARGET_SREQ$(1)$(2)) \
+	$$(TARGET_LIB$(1)$(2))/$$(CFG_STDLIB)
 
 ifeq ($(1),0)
 # Don't run the the stage0 compiler under valgrind - that ship has sailed
@@ -241,16 +290,14 @@ CFG_INFO := $(info cfg: *** compiler is in snapshot transition ***)
 CFG_INFO := $(info cfg: *** stage2 and later will not be built ***)
 CFG_INFO := $(info cfg:)
 
-FUZZ := $(HOST_BIN1)/fuzzer$(X)
+all: $(SREQ1$(CFG_HOST_TRIPLE)) $(GENERATED) $(DOCS)
 
-all: $(SREQ0$(CFG_HOST_TRIPLE)) $(SREQ1$(CFG_HOST_TRIPLE)) \
-     $(GENERATED) $(DOCS) $(FUZZ)
 else
 
-ALL_SREQS = $(foreach target,$(CFG_TARGET_TRIPLES), \
- $(SREQ0$(target)) $(SREQ1$(target)) $(SREQ2$(target)) $(SREQ3$(target)))
+FUZZ := $(HOST_BIN3)/fuzzer$(X)
+
+all: $(SREQ3$(CFG_HOST_TRIPLE)) $(GENERATED) $(DOCS) $(FUZZ)
 
-all: $(ALL_SREQS) $(GENERATED) $(DOCS) $(FUZZ)
 endif
 
 
@@ -268,7 +315,8 @@ config.mk: $(S)configure $(S)Makefile.in $(S)src/snapshots.txt
 ######################################################################
 
 include $(CFG_SRC_DIR)/mk/intrinsics.mk
-include $(CFG_SRC_DIR)/mk/stageN.mk
+include $(CFG_SRC_DIR)/mk/target.mk
+include $(CFG_SRC_DIR)/mk/host.mk
 include $(CFG_SRC_DIR)/mk/stage0.mk
 include $(CFG_SRC_DIR)/mk/rt.mk
 include $(CFG_SRC_DIR)/mk/rustllvm.mk
diff --git a/configure b/configure
index b54654e7a4e..32bfccf0bdb 100755
--- a/configure
+++ b/configure
@@ -224,6 +224,11 @@ opt mingw-cross 0 "cross-compile for win32 using mingw"
 if [ $HELP -eq 1 ]
 then
     echo ""
+    echo "Useful environment variables:"
+    echo ""
+    printf "    %-32s %s\n" "CFG_LLVM_ROOT" "The host LLVM install"
+    printf "    %-32s %s\n" "CFG_PREFIX" "The installation prefix"
+    echo ""
     exit 0
 fi
 
diff --git a/mk/clean.mk b/mk/clean.mk
index 0d55b0e724a..3fa470f6982 100644
--- a/mk/clean.mk
+++ b/mk/clean.mk
@@ -3,7 +3,8 @@
 ######################################################################
 
 CLEAN_STAGE_RULES = $(foreach target,$(CFG_TARGET_TRIPLES), \
- clean0$(target) clean1$(target) clean2$(target) clean3$(target))
+ clean0$(target) clean1$(target) clean2$(target) clean3$(target)) \
+ clean0 clean1 clean2 clean3
 
 
 .PHONY: clean
@@ -43,14 +44,20 @@ clean-misc:
 
 define CLEAN_STAGE_N
 
-clean$(1)$(2):
+clean$(1):
 	$(Q)rm -f $$(HOST_BIN$(1))/rustc
 	$(Q)rm -f $$(HOST_BIN$(1))/fuzzer
 	$(Q)rm -f $$(HOST_LIB$(1))/$(CFG_RUNTIME)
 	$(Q)rm -f $$(HOST_LIB$(1))/$(CFG_STDLIB)
 	$(Q)rm -f $$(HOST_LIB$(1))/$(CFG_RUSTLLVM)
+	$(Q)rm -f $$(HOST_LIB$(1))/libstd.rlib
+
+clean$(1)$(2):
+	$(Q)rm -f $$(TARGET_BIN$(1)$(2))/rustc
+	$(Q)rm -f $$(TARGET_BIN$(1)$(2))/fuzzer
 	$(Q)rm -f $$(TARGET_LIB$(1)$(2))/$(CFG_RUNTIME)
 	$(Q)rm -f $$(TARGET_LIB$(1)$(2))/$(CFG_STDLIB)
+	$(Q)rm -f $$(TARGET_LIB$(1)$(2))/$(CFG_RUSTLLVM)
 	$(Q)rm -f $$(TARGET_LIB$(1)$(2))/libstd.rlib
 	$(Q)rm -f $$(TARGET_LIB$(1)$(2))/intrinsics.bc
 	$(Q)rm -f $$(TARGET_LIB$(1)$(2))/main.o
diff --git a/mk/fuzzer.mk b/mk/fuzzer.mk
index fae07ba3a4c..ced5d6ce6fe 100644
--- a/mk/fuzzer.mk
+++ b/mk/fuzzer.mk
@@ -3,14 +3,23 @@ FUZZER_INPUTS := $(wildcard $(addprefix $(S)src/fuzzer/, *.rs))
 
 define FUZZ_STAGE_N
 
-stage$(2)/bin/fuzzer$$(X): $$(FUZZER_CRATE) $$(FUZZER_INPUTS) \
-                          $$(SREQ$(2)$$(CFG_HOST_TRIPLE)) \
-                          $$(HOST_LIB$(2))/$$(CFG_RUNTIME) \
-                          $$(HOST_LIB$(2))/$$(CFG_RUSTLLVM) \
-                          $$(HOST_LIB$(2))/$$(CFG_STDLIB) \
-                          $$(HOST_LIB$(2))/$$(CFG_LIBRUSTC)
+# We only really care about fuzzing on the host arch
+$$(TARGET_BIN$(1)$(CFG_HOST_TRIPLE))/fuzzer$$(X): \
+	$$(FUZZER_CRATE) $$(FUZZER_INPUTS) \
+	$$(TARGET_SREQ$(1)$(CFG_HOST_TRIPLE)) \
+	$$(TARGET_LIB$(1)$(CFG_HOST_TRIPLE))/$$(CFG_STDLIB) \
+	$$(TARGET_LIB$(1)$(CFG_HOST_TRIPLE))/$$(CFG_LIBRUSTC)
 	@$$(call E, compile_and_link: $$@)
-	$$(STAGE$(1)) -L $$(HOST_LIB$(2)) -o $$@ $$<
+	$$(STAGE$(1)) -o $$@ $$<
+
+# Promote the stageN target to stageN+1 host
+# FIXME: Shouldn't need to depend on host/librustc.so once
+# rpath is working
+$$(HOST_BIN$(2))/fuzzer$$(X): \
+	$$(TARGET_BIN$(1)$(CFG_HOST_TRIPLE))/fuzzer$$(X) \
+	$$(HOST_LIB$(2))/$$(CFG_LIBRUSTC)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
 
 endef
 
diff --git a/mk/host.mk b/mk/host.mk
new file mode 100644
index 00000000000..31e995d22c6
--- /dev/null
+++ b/mk/host.mk
@@ -0,0 +1,56 @@
+# HOST_STAGE_N template: arg 1 is the N we're promoting *from*, arg 2
+# is N+1. Must be invoked to promote target artifacts to host artifacts
+# for stage 1-3 (stage0 host artifacts come from the snapshot).
+#
+# The easiest way to read this template is to assume we're promoting
+# stage1 to stage2 and mentally gloss $(1) as 1, $(2) as 2.
+
+define HOST_STAGE_N
+
+# Host libraries and executables (stage$(2)/bin/rustc and its runtime needs)
+
+$$(HOST_BIN$(2))/rustc$$(X): \
+	$$(TARGET_HOST_BIN$(1))/rustc$$(X) \
+	$$(HOST_LIB$(2))/$$(CFG_RUNTIME) \
+	$$(HOST_LIB$(2))/$$(CFG_RUSTLLVM) \
+	$$(HOST_STDLIB_DEFAULT$(2))
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+# FIXME: The fuzzer depends on this. Remove once it's rpathed to correctly
+# find it in the appropriate target directory
+$$(HOST_LIB$(2))/$$(CFG_LIBRUSTC): \
+	$$(TARGET_HOST_LIB$(1))/$$(CFG_LIBRUSTC) \
+	$$(HOST_LIB$(2))/$$(CFG_RUNTIME) \
+	$$(HOST_LIB$(2))/$$(CFG_RUSTLLVM) \
+	$$(HOST_STDLIB_DEFAULT$(2))
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(HOST_LIB$(2))/$$(CFG_RUNTIME): \
+	$$(TARGET_HOST_LIB$(1))/$$(CFG_RUNTIME)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(HOST_LIB$(2))/$$(CFG_STDLIB): \
+	$$(TARGET_HOST_LIB$(1))/$$(CFG_STDLIB) \
+	$$(HOST_LIB$(2))/$$(CFG_RUNTIME)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(HOST_LIB$(2))/libstd.rlib: \
+	$$(TARGET_HOST_LIB$(1))/libstd.rlib \
+	$$(HOST_LIB$(2))/$$(CFG_RUNTIME)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(HOST_LIB$(2))/$$(CFG_RUSTLLVM): \
+	$$(TARGET_HOST_LIB$(1))/$$(CFG_RUSTLLVM)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+endef
+
+$(eval $(call HOST_STAGE_N,0,1))
+$(eval $(call HOST_STAGE_N,1,2))
+$(eval $(call HOST_STAGE_N,2,3))
diff --git a/mk/install.mk b/mk/install.mk
index 903c07d8c0d..badad0b1aac 100644
--- a/mk/install.mk
+++ b/mk/install.mk
@@ -1,10 +1,11 @@
 ifdef VERBOSE
  INSTALL = cp $(1)/$(3) $(2)/$(3)
 else
- INSTALL = @$(call E, install $(2)/$(3)) && cp $(1)/$(3) $(2)/$(3)
+ INSTALL = @$(call E, install: $(2)/$(3)) && cp $(1)/$(3) $(2)/$(3)
 endif
 
-ISTAGE = 1
+# The stage we install from
+ISTAGE = 3
 
 PREFIX_ROOT = $(CFG_PREFIX)
 PREFIX_BIN = $(PREFIX_ROOT)/bin
diff --git a/mk/snap.mk b/mk/snap.mk
index c26b1e9cbe2..7a0ed8ddb92 100644
--- a/mk/snap.mk
+++ b/mk/snap.mk
@@ -1,12 +1,9 @@
 
-snap-stage1: $(HOST_BIN1)/rustc$(X) $(HOST_LIB1)/$(CFG_RUNTIME) \
-	$(HOST_LIB1)/$(CFG_RUSTLLVM) $(HOST_LIB1)/$(CFG_STDLIB)
+snap-stage1: $(HOST_SREQ1)
 	$(S)src/etc/make-snapshot.py stage1
 
-snap-stage2: $(HOST_BIN2)/rustc$(X) $(HOST_LIB2)/$(CFG_RUNTIME) \
-	$(HOST_LIB2)/$(CFG_RUSTLLVM) $(HOST_LIB2)/$(CFG_STDLIB)
+snap-stage2: $(HOST_SREQ2)
 	$(S)src/etc/make-snapshot.py stage2
 
-snap-stage3: $(HOST_BIN3)/rustc$(X) $(HOST_LIB3)/$(CFG_RUNTIME) \
-	$(HOST_LIB3)/$(CFG_RUSTLLVM) $(HOST_LIB3)/$(CFG_STDLIB)
+snap-stage3: $(HOST_SREQ3)
 	$(S)src/etc/make-snapshot.py stage3
diff --git a/mk/stage0.mk b/mk/stage0.mk
index 3f4ed12f514..c2cb26da527 100644
--- a/mk/stage0.mk
+++ b/mk/stage0.mk
@@ -1,9 +1,13 @@
-$(HOST_BIN0)/rustc$(X): $(S)src/snapshots.txt $(S)src/etc/get-snapshot.py $(MKFILES)
+# Extract the snapshot host compiler
+
+$(HOST_BIN0)/rustc$(X): \
+	$(S)src/snapshots.txt \
+	$(S)src/etc/get-snapshot.py $(MKFILES)
 	@$(call E, fetch: $@)
 	$(Q)$(S)src/etc/get-snapshot.py
 	$(Q)touch $@
 
-# Host libs will be made in the process of making rustc above.
+# Host libs will be extracted by the above rule
 
 $(HOST_LIB0)/$(CFG_RUNTIME): $(HOST_BIN0)/rustc$(X)
 	$(Q)touch $@
@@ -13,10 +17,3 @@ $(HOST_LIB0)/$(CFG_STDLIB): $(HOST_BIN0)/rustc$(X)
 
 $(HOST_LIB0)/$(CFG_RUSTLLVM): $(HOST_BIN0)/rustc$(X)
 	$(Q)touch $@
-
-# Instantiate template (in stageN.mk) for building
-# target libraries.
-
-SREQpre = $(MKFILES)
-$(eval $(call TARGET_LIBS,pre,0,$(CFG_HOST_TRIPLE)))
-
diff --git a/mk/stageN.mk b/mk/stageN.mk
deleted file mode 100644
index f64c0088d29..00000000000
--- a/mk/stageN.mk
+++ /dev/null
@@ -1,113 +0,0 @@
-# STAGE_N template: arg 1 is the N we're building *from*, arg 2 is N+1, arg 3
-# is the target triple we're building for. You have to invoke this for each
-# target triple.
-#
-# The easiest way to read this template is to assume we're building stage2
-# using stage1, and mentally gloss $(1) as 1, $(2) as 2.
-#
-# TARGET_LIBS is pulled out seperately because we need to specially invoke
-# it to build stage0/lib/libstd using stage0/rustc and to use the
-# new rustrt in stage0/lib/.
-
-define STAGE_N
-
-# Host libraries and executables (stage$(2)/rustc and its runtime needs)
-#
-# NB: Due to make not wanting to run the same implicit rules twice on the same
-# rule tree (implicit-rule recursion prevention, see "Chains of Implicit
-# Rules" in GNU Make manual) we have to re-state the %.o and %.s patterns here
-# for different directories, to handle cases where (say) a test relies on a
-# compiler that relies on a .o file.
-
-$$(HOST_BIN$(2))/%.o: $$(HOST_BIN$(2))/%.s
-	@$$(call E, assemble [gcc]: $$@)
-	$$(Q)gcc $$(CFG_GCCISH_CFLAGS) -o $$@ -c $$<
-
-$$(HOST_LIB$(2))/%.o: $$(HOST_LIB$(2))/%.s
-	@$$(call E, assemble [gcc]: $$@)
-	$$(Q)gcc $$(CFG_GCCISH_CFLAGS) -o $$@ -c $$<
-
-$$(HOST_BIN$(2))/rustc$$(X): $$(COMPILER_CRATE) $$(COMPILER_INPUTS)          \
-                          $$(HOST_LIB$(2))/$$(CFG_RUNTIME)                       \
-                          $$(HOST_STDLIB_DEFAULT$(2)) \
-                          $$(HOST_LIB$(2))/$$(CFG_RUSTLLVM)                      \
-                          $$(SREQ$(1)$(3))
-	@$$(call E, compile_and_link: $$@)
-	$$(STAGE$(1)) -L $$(HOST_LIB$(2)) -o $$@ $$<
-
-$$(HOST_LIB$(2))/$$(CFG_LIBRUSTC): \
-          $$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
-          $$(SREQ$(2)$(3))
-	@$$(call E, compile_and_link: $$@)
-	$$(STAGE$(1)) -L $$(HOST_LIB$(2)) --lib -o $$@ $$<
-
-$$(HOST_LIB$(2))/$$(CFG_RUNTIME): rt/$$(CFG_RUNTIME)
-	@$$(call E, cp: $$@)
-	$$(Q)cp $$< $$@
-
-$$(HOST_LIB$(2))/$$(CFG_STDLIB): $$(TARGET_HOST_LIB$(1))/$$(CFG_STDLIB)
-	@$$(call E, cp: $$@)
-	$$(Q)cp $$< $$@
-
-$$(HOST_LIB$(2))/libstd.rlib: $$(TARGET_HOST_LIB$(1))/libstd.rlib
-	@$$(call E, cp: $$@)
-	$$(Q)cp $$< $$@
-
-$$(HOST_LIB$(2))/$$(CFG_RUSTLLVM): rustllvm/$$(CFG_RUSTLLVM)
-	@$$(call E, cp: $$@)
-	$$(Q)cp $$< $$@
-
-# Expand out target libraries
-
-$(eval $(call TARGET_LIBS,$(1),$(2),$(3)))
-
-endef
-
-
-define TARGET_LIBS
-
-# New per-target-arch target libraries; when we've transitioned to
-# using these exclusively, you should delete the non-arch-prefixed
-# rules above. They're duplicates, redundant.
-
-$$(TARGET_LIB$(2)$(3))/intrinsics.bc: $$(INTRINSICS_BC)
-	@$$(call E, cp: $$@)
-	$$(Q)cp $$< $$@
-
-$$(TARGET_LIB$(2)$(3))/main.o: rt/main.o
-	@$$(call E, cp: $$@)
-	$$(Q)cp $$< $$@
-
-$$(TARGET_LIB$(2)$(3))/$$(CFG_STDLIB): \
-        $$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
-        $$(HOST_BIN$(2))/rustc$$(X)               \
-        $$(HOST_LIB$(2))/$$(CFG_RUNTIME)          \
-        $$(HOST_LIB$(2))/$$(CFG_RUSTLLVM)         \
-        $$(TARGET_LIB$(2)$(3))/intrinsics.bc        \
-        $$(SREQ$(1)$(3))
-	@$$(call E, compile_and_link: $$@)
-	$$(STAGE$(2))  --lib -o $$@ $$<
-
-$$(TARGET_LIB$(2)$(3))/libstd.rlib: \
-        $$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
-        $$(HOST_BIN$(2))/rustc$$(X)               \
-        $$(HOST_LIB$(2))/$$(CFG_RUNTIME)          \
-        $$(HOST_LIB$(2))/$$(CFG_RUSTLLVM)         \
-        $$(TARGET_LIB$(2)$(3))/intrinsics.bc        \
-        $$(SREQ$(1)$(3))
-	@$$(call E, compile_and_link: $$@)
-	$$(STAGE$(2)) --lib --static -o $$@ $$<
-
-$$(TARGET_LIB$(2)$(3))/$$(CFG_RUNTIME): rt/$$(CFG_RUNTIME)
-	@$$(call E, cp: $$@)
-	$$(Q)cp $$< $$@
-
-endef
-
-
-
-# Instantiate template for 0->1, 1->2, 2->3 build dirs
-$(foreach target,$(CFG_TARGET_TRIPLES), \
- $(eval $(call STAGE_N,0,1,$(target)))   \
- $(eval $(call STAGE_N,1,2,$(target)))   \
- $(eval $(call STAGE_N,2,3,$(target))))
diff --git a/mk/target.mk b/mk/target.mk
new file mode 100644
index 00000000000..ccbfba24383
--- /dev/null
+++ b/mk/target.mk
@@ -0,0 +1,61 @@
+# TARGET_STAGE_N template: This defines how target artifacts are built
+# for all stage/target architecture combinations. Argument 1 is the
+# stage and arg 2 is the target triple
+
+# FIXME: We don't actually know how to build many of these when host
+# and target architectures are not the same
+
+define TARGET_STAGE_N
+
+$$(TARGET_LIB$(1)$(2))/intrinsics.bc: $$(INTRINSICS_BC)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(TARGET_LIB$(1)$(2))/main.o: rt/main.o
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(TARGET_LIB$(1)$(2))/$$(CFG_STDLIB): \
+	$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
+        $$(TARGET_SREQ$(1)$(2))
+	@$$(call E, compile_and_link: $$@)
+	$$(STAGE$(1))  --lib -o $$@ $$<
+
+$$(TARGET_LIB$(1)$(2))/libstd.rlib: \
+	$$(STDLIB_CRATE) $$(STDLIB_INPUTS) \
+        $$(TARGET_SREQ$(1)$(2))
+	@$$(call E, compile_and_link: $$@)
+	$$(STAGE$(1)) --lib --static -o $$@ $$<
+
+$$(TARGET_LIB$(1)$(2))/$$(CFG_RUNTIME): rt/$$(CFG_RUNTIME)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(TARGET_LIB$(1)$(2))/$$(CFG_RUSTLLVM): rustllvm/$$(CFG_RUSTLLVM)
+	@$$(call E, cp: $$@)
+	$$(Q)cp $$< $$@
+
+$$(TARGET_BIN$(1)$(2))/rustc$$(X): \
+	$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
+	$$(TARGET_SREQ$(1)$(2)) \
+	$$(TARGET_LIB$(1)$(2))/$$(CFG_RUSTLLVM) \
+	$$(TARGET_STDLIB_DEFAULT$(1)$(2))
+	@$$(call E, compile_and_link: $$@)
+	$$(STAGE$(1)) -o $$@ $$<
+
+$$(TARGET_LIB$(1)$(2))/$$(CFG_LIBRUSTC): \
+	$$(COMPILER_CRATE) $$(COMPILER_INPUTS) \
+	$$(TARGET_SREQ$(1)$(2)) \
+	$$(TARGET_LIB$(1)$(2))/$$(CFG_RUSTLLVM) \
+	$$(TARGET_STDLIB_DEFAULT$(1)$(2))
+	@$$(call E, compile_and_link: $$@)
+	$$(STAGE$(1)) --lib -o $$@ $$<
+
+endef
+
+# Instantiate template for all stages
+$(foreach target,$(CFG_TARGET_TRIPLES), \
+ $(eval $(call TARGET_STAGE_N,0,$(target))) \
+ $(eval $(call TARGET_STAGE_N,1,$(target))) \
+ $(eval $(call TARGET_STAGE_N,2,$(target))) \
+ $(eval $(call TARGET_STAGE_N,3,$(target))))