about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--mk/cfg/i586-pc-windows-msvc.mk14
-rw-r--r--mk/cfg/i686-pc-windows-msvc.mk14
-rw-r--r--mk/cfg/x86_64-pc-windows-msvc.mk14
-rw-r--r--mk/platform.mk6
-rw-r--r--mk/tests.mk89
-rw-r--r--src/bootstrap/build/check.rs29
-rw-r--r--src/bootstrap/build/mod.rs4
-rw-r--r--src/bootstrap/build/step.rs5
-rw-r--r--src/etc/maketest.py96
-rw-r--r--src/test/run-make/issue-22131/Makefile2
-rw-r--r--src/test/run-make/tools.mk2
-rw-r--r--src/tools/compiletest/src/common.rs11
-rw-r--r--src/tools/compiletest/src/header.rs3
-rw-r--r--src/tools/compiletest/src/main.rs25
-rw-r--r--src/tools/compiletest/src/procsrv.rs14
-rw-r--r--src/tools/compiletest/src/runtest.rs117
16 files changed, 237 insertions, 208 deletions
diff --git a/mk/cfg/i586-pc-windows-msvc.mk b/mk/cfg/i586-pc-windows-msvc.mk
index da2680f7416..48f1ecec3a7 100644
--- a/mk/cfg/i586-pc-windows-msvc.mk
+++ b/mk/cfg/i586-pc-windows-msvc.mk
@@ -1,16 +1,16 @@
 # i586-pc-windows-msvc configuration
-CC_i586-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
-LINK_i586-pc-windows-msvc="$(CFG_MSVC_LINK_i386)" -nologo
-CXX_i586-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
-CPP_i586-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
-AR_i586-pc-windows-msvc="$(CFG_MSVC_LIB_i386)" -nologo
+CC_i586-pc-windows-msvc=$(CFG_MSVC_CL_i386)
+LINK_i586-pc-windows-msvc=$(CFG_MSVC_LINK_i386)
+CXX_i586-pc-windows-msvc=$(CFG_MSVC_CL_i386)
+CPP_i586-pc-windows-msvc=$(CFG_MSVC_CL_i386)
+AR_i586-pc-windows-msvc=$(CFG_MSVC_LIB_i386)
 CFG_LIB_NAME_i586-pc-windows-msvc=$(1).dll
 CFG_STATIC_LIB_NAME_i586-pc-windows-msvc=$(1).lib
 CFG_LIB_GLOB_i586-pc-windows-msvc=$(1)-*.{dll,lib}
 CFG_LIB_DSYM_GLOB_i586-pc-windows-msvc=$(1)-*.dylib.dSYM
 CFG_JEMALLOC_CFLAGS_i586-pc-windows-msvc :=
-CFG_GCCISH_CFLAGS_i586-pc-windows-msvc := -MD -arch:IA32
-CFG_GCCISH_CXXFLAGS_i586-pc-windows-msvc := -MD -arch:IA32
+CFG_GCCISH_CFLAGS_i586-pc-windows-msvc := -MD -arch:IA32 -nologo
+CFG_GCCISH_CXXFLAGS_i586-pc-windows-msvc := -MD -arch:IA32 -nologo
 CFG_GCCISH_LINK_FLAGS_i586-pc-windows-msvc :=
 CFG_GCCISH_DEF_FLAG_i586-pc-windows-msvc :=
 CFG_LLC_FLAGS_i586-pc-windows-msvc :=
diff --git a/mk/cfg/i686-pc-windows-msvc.mk b/mk/cfg/i686-pc-windows-msvc.mk
index 85b320a18a4..b0289b9892e 100644
--- a/mk/cfg/i686-pc-windows-msvc.mk
+++ b/mk/cfg/i686-pc-windows-msvc.mk
@@ -1,16 +1,16 @@
 # i686-pc-windows-msvc configuration
-CC_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
-LINK_i686-pc-windows-msvc="$(CFG_MSVC_LINK_i386)" -nologo
-CXX_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
-CPP_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
-AR_i686-pc-windows-msvc="$(CFG_MSVC_LIB_i386)" -nologo
+CC_i686-pc-windows-msvc=$(CFG_MSVC_CL_i386)
+LINK_i686-pc-windows-msvc=$(CFG_MSVC_LINK_i386)
+CXX_i686-pc-windows-msvc=$(CFG_MSVC_CL_i386)
+CPP_i686-pc-windows-msvc=$(CFG_MSVC_CL_i386)
+AR_i686-pc-windows-msvc=$(CFG_MSVC_LIB_i386)
 CFG_LIB_NAME_i686-pc-windows-msvc=$(1).dll
 CFG_STATIC_LIB_NAME_i686-pc-windows-msvc=$(1).lib
 CFG_LIB_GLOB_i686-pc-windows-msvc=$(1)-*.{dll,lib}
 CFG_LIB_DSYM_GLOB_i686-pc-windows-msvc=$(1)-*.dylib.dSYM
 CFG_JEMALLOC_CFLAGS_i686-pc-windows-msvc :=
-CFG_GCCISH_CFLAGS_i686-pc-windows-msvc := -MD
-CFG_GCCISH_CXXFLAGS_i686-pc-windows-msvc := -MD
+CFG_GCCISH_CFLAGS_i686-pc-windows-msvc := -MD -nologo
+CFG_GCCISH_CXXFLAGS_i686-pc-windows-msvc := -MD -nologo
 CFG_GCCISH_LINK_FLAGS_i686-pc-windows-msvc :=
 CFG_GCCISH_DEF_FLAG_i686-pc-windows-msvc :=
 CFG_LLC_FLAGS_i686-pc-windows-msvc :=
diff --git a/mk/cfg/x86_64-pc-windows-msvc.mk b/mk/cfg/x86_64-pc-windows-msvc.mk
index a194dfd1a68..30e996a9727 100644
--- a/mk/cfg/x86_64-pc-windows-msvc.mk
+++ b/mk/cfg/x86_64-pc-windows-msvc.mk
@@ -1,16 +1,16 @@
 # x86_64-pc-windows-msvc configuration
-CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
-LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK_x86_64)" -nologo
-CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
-CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
-AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB_x86_64)" -nologo
+CC_x86_64-pc-windows-msvc=$(CFG_MSVC_CL_x86_64)
+LINK_x86_64-pc-windows-msvc=$(CFG_MSVC_LINK_x86_64)
+CXX_x86_64-pc-windows-msvc=$(CFG_MSVC_CL_x86_64)
+CPP_x86_64-pc-windows-msvc=$(CFG_MSVC_CL_x86_64)
+AR_x86_64-pc-windows-msvc=$(CFG_MSVC_LIB_x86_64)
 CFG_LIB_NAME_x86_64-pc-windows-msvc=$(1).dll
 CFG_STATIC_LIB_NAME_x86_64-pc-windows-msvc=$(1).lib
 CFG_LIB_GLOB_x86_64-pc-windows-msvc=$(1)-*.{dll,lib}
 CFG_LIB_DSYM_GLOB_x86_64-pc-windows-msvc=$(1)-*.dylib.dSYM
 CFG_JEMALLOC_CFLAGS_x86_64-pc-windows-msvc :=
-CFG_GCCISH_CFLAGS_x86_64-pc-windows-msvc := -MD
-CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-msvc := -MD
+CFG_GCCISH_CFLAGS_x86_64-pc-windows-msvc := -MD -nologo
+CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-msvc := -MD -nologo
 CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-msvc :=
 CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-msvc :=
 CFG_LLC_FLAGS_x86_64-pc-windows-msvc :=
diff --git a/mk/platform.mk b/mk/platform.mk
index 83fd4509da8..59c8f7726c9 100644
--- a/mk/platform.mk
+++ b/mk/platform.mk
@@ -148,7 +148,7 @@ define CC_MACROS
   CFG_CC_INCLUDE_$(1)=-I $$(1)
   ifeq ($$(findstring msvc,$(1)),msvc)
     CFG_CC_OUTPUT_$(1)=-Fo:$$(1)
-    CFG_CREATE_ARCHIVE_$(1)=$$(AR_$(1)) -OUT:$$(1)
+    CFG_CREATE_ARCHIVE_$(1)='$$(AR_$(1))' -OUT:$$(1)
   else
     CFG_CC_OUTPUT_$(1)=-o $$(1)
     CFG_CREATE_ARCHIVE_$(1)=$$(AR_$(1)) crus $$(1)
@@ -187,7 +187,7 @@ define CFG_MAKE_TOOLCHAIN
     endif
   endif
 
-  CFG_COMPILE_C_$(1) = $$(CC_$(1)) \
+  CFG_COMPILE_C_$(1) = '$$(CC_$(1))' \
         $$(CFLAGS) \
         $$(CFG_GCCISH_CFLAGS) \
         $$(CFG_GCCISH_CFLAGS_$(1)) \
@@ -198,7 +198,7 @@ define CFG_MAKE_TOOLCHAIN
         $$(CFG_GCCISH_LINK_FLAGS_$(1)) \
         $$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2) \
         $$(call CFG_INSTALL_NAME_$(1),$$(4))
-  CFG_COMPILE_CXX_$(1) = $$(CXX_$(1)) \
+  CFG_COMPILE_CXX_$(1) = '$$(CXX_$(1))' \
         $$(CXXFLAGS) \
         $$(CFG_GCCISH_CFLAGS) \
         $$(CFG_GCCISH_CXXFLAGS) \
diff --git a/mk/tests.mk b/mk/tests.mk
index f5a499105be..9d45203b7b6 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -450,6 +450,7 @@ CODEGEN_RS := $(call rwildcard,$(S)src/test/codegen/,*.rs)
 CODEGEN_CC := $(call rwildcard,$(S)src/test/codegen/,*.cc)
 CODEGEN_UNITS_RS := $(call rwildcard,$(S)src/test/codegen-units/,*.rs)
 INCREMENTAL_RS := $(call rwildcard,$(S)src/test/incremental/,*.rs)
+RMAKE_RS := $(wildcard $(S)src/test/run-make/*/Makefile)
 RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs)
 
 RPASS_TESTS := $(RPASS_RS)
@@ -466,6 +467,7 @@ DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
 CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
 CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS)
 INCREMENTAL_TESTS := $(INCREMENTAL_RS)
+RMAKE_TESTS := $(RMAKE_RS)
 RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
 
 CTEST_SRC_BASE_rpass = run-pass
@@ -533,6 +535,11 @@ CTEST_BUILD_BASE_incremental = incremental
 CTEST_MODE_incremental = incremental
 CTEST_RUNTOOL_incremental = $(CTEST_RUNTOOL)
 
+CTEST_SRC_BASE_rmake = run-make
+CTEST_BUILD_BASE_rmake = run-make
+CTEST_MODE_rmake = run-make
+CTEST_RUNTOOL_rmake = $(CTEST_RUNTOOL)
+
 CTEST_SRC_BASE_rustdocck = rustdoc
 CTEST_BUILD_BASE_rustdocck = rustdoc
 CTEST_MODE_rustdocck = rustdoc
@@ -629,6 +636,11 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
         --host-rustcflags "$(RUSTC_FLAGS_$(3)) $$(CTEST_RUSTC_FLAGS) -L $$(RT_OUTPUT_DIR_$(3))" \
         --lldb-python-dir=$(CFG_LLDB_PYTHON_DIR) \
         --target-rustcflags "$(RUSTC_FLAGS_$(2)) $$(CTEST_RUSTC_FLAGS) -L $$(RT_OUTPUT_DIR_$(2))" \
+	--cc '$$(CC_$(3))' \
+	--cxx '$$(CXX_$(3))' \
+	--cflags "$$(CFG_GCCISH_CFLAGS_$(3))" \
+	--llvm-components "$$(LLVM_ALL_COMPONENTS_$(3))" \
+	--llvm-cxxflags "$$(LLVM_CXXFLAGS_$(3))" \
         $$(CTEST_TESTARGS)
 
 ifdef CFG_VALGRIND_RPASS
@@ -658,6 +670,9 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
 CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
 CTEST_DEPS_codegen-units_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_UNITS_TESTS)
 CTEST_DEPS_incremental_$(1)-T-$(2)-H-$(3) = $$(INCREMENTAL_TESTS)
+CTEST_DEPS_rmake_$(1)-T-$(2)-H-$(3) = $$(RMAKE_TESTS) \
+	$$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
+
 CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
 		$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
 		$(S)src/etc/htmldocck.py
@@ -703,6 +718,10 @@ endif
 
 ifeq ($$(CTEST_DONT_RUN_$(1)-T-$(2)-H-$(3)-$(4)),)
 $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
+	export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(3)))
+$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
+	export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(3)))
+$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
 		$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
                 $$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3))
 	@$$(call E, run $(4) [$(2)]: $$<)
@@ -724,7 +743,8 @@ endif
 endef
 
 CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
-	debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck incremental
+	debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck incremental \
+	rmake
 
 $(foreach host,$(CFG_HOST), \
  $(eval $(foreach target,$(CFG_TARGET), \
@@ -1009,70 +1029,3 @@ endef
 
 $(foreach crate,$(TEST_CRATES), \
  $(eval $(call DEF_CHECK_CRATE,$(crate))))
-
-######################################################################
-# RMAKE rules
-######################################################################
-
-RMAKE_TESTS := $(shell ls -d $(S)src/test/run-make/*/)
-RMAKE_TESTS := $(RMAKE_TESTS:$(S)src/test/run-make/%/=%)
-
-define DEF_RMAKE_FOR_T_H
-# $(1) the stage
-# $(2) target triple
-# $(3) host triple
-
-
-ifeq ($(2)$(3),$$(CFG_BUILD)$$(CFG_BUILD))
-check-stage$(1)-T-$(2)-H-$(3)-rmake-exec: \
-		$$(call TEST_OK_FILE,$(1),$(2),$(3),rmake)
-
-$$(call TEST_OK_FILE,$(1),$(2),$(3),rmake): \
-		$$(RMAKE_TESTS:%=$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok)
-	@touch $$@
-
-$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
-	export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(3)))
-$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
-	export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(3)))
-$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
-	export MSVC_LIB := "$$(CFG_MSVC_LIB_$$(HOST_$(3)))"
-$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
-		$(S)src/test/run-make/%/Makefile \
-		$$(CSREQ$(1)_T_$(2)_H_$(3))
-	@rm -rf $(3)/test/run-make/$$*
-	@mkdir -p $(3)/test/run-make/$$*
-	$$(Q)touch $$@.start_time
-	$$(Q)$$(CFG_PYTHON) $(S)src/etc/maketest.py $$(dir $$<) \
-        $$(MAKE) \
-	    $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
-	    $(3)/test/run-make/$$* \
-	    '$$(CC_$(3))' \
-	    "$$(CFG_GCCISH_CFLAGS_$(3))" \
-	    $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
-	    "$$(TESTNAME)" \
-	    $$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3)) \
-	    "$$(LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3))" \
-	    "$$(LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3))" \
-	    $(1) \
-	    $$(S) \
-	    $(3) \
-	    "$$(LLVM_LIBDIR_RUSTFLAGS_$(3))" \
-	    "$$(LLVM_ALL_COMPONENTS_$(3))" \
-	    "$$(LLVM_CXXFLAGS_$(3))" \
-	    '$$(CXX_$(3))'
-	@touch -r $$@.start_time $$@ && rm $$@.start_time
-else
-# FIXME #11094 - The above rule doesn't work right for multiple targets
-check-stage$(1)-T-$(2)-H-$(3)-rmake-exec:
-	@true
-
-endif
-
-
-endef
-
-$(foreach stage,$(STAGES), \
- $(foreach target,$(CFG_TARGET), \
-  $(foreach host,$(CFG_HOST), \
-   $(eval $(call DEF_RMAKE_FOR_T_H,$(stage),$(target),$(host))))))
diff --git a/src/bootstrap/build/check.rs b/src/bootstrap/build/check.rs
index 32164080947..a376b021a8a 100644
--- a/src/bootstrap/build/check.rs
+++ b/src/bootstrap/build/check.rs
@@ -12,6 +12,8 @@ use std::fs;
 use std::path::{PathBuf, Path};
 use std::process::Command;
 
+use build_helper::output;
+
 use build::{Build, Compiler};
 
 pub fn linkcheck(build: &Build, stage: u32, host: &str) {
@@ -112,6 +114,33 @@ pub fn compiletest(build: &Build,
         cmd.arg("--verbose");
     }
 
+    if suite == "run-make" {
+        let llvm_config = build.llvm_config(target);
+        let llvm_components = output(Command::new(&llvm_config).arg("--components"));
+        let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
+        cmd.arg("--cc").arg(build.cc(target))
+           .arg("--cxx").arg(build.cxx(target))
+           .arg("--cflags").arg(build.cflags(target).join(" "))
+           .arg("--llvm-components").arg(llvm_components.trim())
+           .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim());
+    } else {
+        cmd.arg("--cc").arg("")
+           .arg("--cxx").arg("")
+           .arg("--cflags").arg("")
+           .arg("--llvm-components").arg("")
+           .arg("--llvm-cxxflags").arg("");
+    }
+
+    // Running a C compiler on MSVC requires a few env vars to be set, to be
+    // sure to set them here.
+    if target.contains("msvc") {
+        for &(ref k, ref v) in build.cc[target].0.env() {
+            if k != "PATH" {
+                cmd.env(k, v);
+            }
+        }
+    }
+
     build.run(&mut cmd);
 }
 
diff --git a/src/bootstrap/build/mod.rs b/src/bootstrap/build/mod.rs
index 3c3add3d9a1..97be285ce01 100644
--- a/src/bootstrap/build/mod.rs
+++ b/src/bootstrap/build/mod.rs
@@ -314,6 +314,10 @@ impl Build {
                 CheckErrorIndex { compiler } => {
                     check::error_index(self, &compiler);
                 }
+                CheckRMake { compiler } => {
+                    check::compiletest(self, &compiler, target.target,
+                                       "run-make", "run-make")
+                }
 
                 DistDocs { stage } => dist::docs(self, stage, target.target),
                 DistMingw { _dummy } => dist::mingw(self, target.target),
diff --git a/src/bootstrap/build/step.rs b/src/bootstrap/build/step.rs
index 133ae702869..59d644730a2 100644
--- a/src/bootstrap/build/step.rs
+++ b/src/bootstrap/build/step.rs
@@ -98,6 +98,7 @@ macro_rules! targets {
             (check_cfail_full, CheckCFailFull { compiler: Compiler<'a> }),
             (check_docs, CheckDocs { compiler: Compiler<'a> }),
             (check_error_index, CheckErrorIndex { compiler: Compiler<'a> }),
+            (check_rmake, CheckRMake { compiler: Compiler<'a> }),
 
             // Distribution targets, creating tarballs
             (dist, Dist { stage: u32 }),
@@ -345,6 +346,7 @@ impl<'a> Step<'a> {
                     self.check_cfail_full(compiler),
                     self.check_error_index(compiler),
                     self.check_docs(compiler),
+                    self.check_rmake(compiler),
                     self.check_linkcheck(stage),
                     self.check_tidy(stage),
                     self.dist(stage),
@@ -384,7 +386,8 @@ impl<'a> Step<'a> {
                 ]
             }
             Source::CheckRPassFull { compiler } |
-            Source::CheckCFailFull { compiler } => {
+            Source::CheckCFailFull { compiler } |
+            Source::CheckRMake { compiler } => {
                 vec![self.librustc(compiler),
                      self.tool_compiletest(compiler.stage)]
             }
diff --git a/src/etc/maketest.py b/src/etc/maketest.py
deleted file mode 100644
index c7d17b23bff..00000000000
--- a/src/etc/maketest.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# Copyright 2013-2014 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 subprocess
-import os
-import sys
-
-target_triple = sys.argv[14]
-
-def normalize_path(v):
-    """msys1/msys2 automatically converts `/abs/path1:/abs/path2` into
-    `c:\real\abs\path1;c:\real\abs\path2` (semicolons) if shell thinks
-    the value is list of paths.
-    (if there is only one path, it becomes `c:/real/abs/path`.)
-    this causes great confusion and error: shell and Makefile doesn't like
-    windows paths so it is really error-prone. revert it for peace."""
-    v = v.replace('\\', '/')
-    # c:/path -> /c/path
-    # "c:/path" -> "/c/path"
-    start = v.find(':/')
-    while start != -1:
-        v = v[:start - 1] + '/' + v[start - 1:start] + v[start + 1:]
-        start = v.find(':/')
-    return v
-
-
-def putenv(name, value):
-    if os.name == 'nt':
-        value = normalize_path(value)
-    os.putenv(name, value)
-
-
-def convert_path_spec(name, value):
-    if os.name == 'nt' and name != 'PATH':
-        value = ":".join(normalize_path(v) for v in value.split(";"))
-    return value
-
-make = sys.argv[2]
-putenv('RUSTC', os.path.abspath(sys.argv[3]))
-putenv('TMPDIR', os.path.abspath(sys.argv[4]))
-putenv('CC', sys.argv[5] + ' ' + sys.argv[6])
-putenv('CFLAGS', sys.argv[6])
-putenv('RUSTDOC', os.path.abspath(sys.argv[7]))
-filt = sys.argv[8]
-putenv('LD_LIB_PATH_ENVVAR', sys.argv[9])
-putenv('HOST_RPATH_DIR', os.path.abspath(sys.argv[10]))
-putenv('TARGET_RPATH_DIR', os.path.abspath(sys.argv[11]))
-putenv('RUST_BUILD_STAGE', sys.argv[12])
-putenv('S', os.path.abspath(sys.argv[13]))
-putenv('RUSTFLAGS', sys.argv[15])
-putenv('LLVM_COMPONENTS', sys.argv[16])
-putenv('LLVM_CXXFLAGS', sys.argv[17])
-putenv('CXX', sys.argv[18])
-putenv('PYTHON', sys.executable)
-os.putenv('TARGET', target_triple)
-
-if 'msvc' in target_triple:
-    os.putenv('IS_MSVC', '1')
-
-if filt not in sys.argv[1]:
-    sys.exit(0)
-print('maketest: ' + os.path.basename(os.path.dirname(sys.argv[1])))
-
-path = sys.argv[1]
-if path[-1] == '/':
-    # msys1 has a bug that `make` fails to include `../tools.mk` (parent dir)
-    # if `-C path` option is given and `path` is absolute directory with
-    # trailing slash (`c:/path/to/test/`).
-    # the easist workaround is to remove the slash (`c:/path/to/test`).
-    # msys2 seems to fix this problem.
-    path = path[:-1]
-
-proc = subprocess.Popen([make, '-C', path],
-                        stdout=subprocess.PIPE,
-                        stderr=subprocess.PIPE)
-out, err = proc.communicate()
-i = proc.wait()
-
-if i != 0:
-    print """\
------ %s --------------------
------- stdout ---------------------------------------------
-%s
------- stderr ---------------------------------------------
-%s
-------        ---------------------------------------------
-""" % (sys.argv[1], out, err)
-
-    sys.exit(i)
diff --git a/src/test/run-make/issue-22131/Makefile b/src/test/run-make/issue-22131/Makefile
index ec1e282666a..1e8568626a6 100644
--- a/src/test/run-make/issue-22131/Makefile
+++ b/src/test/run-make/issue-22131/Makefile
@@ -2,6 +2,6 @@
 
 all: foo.rs
 	$(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs
-	$(HOST_RPATH_ENV) $(RUSTDOC) --test --cfg 'feature="bar"' \
+	$(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \
 		-L $(TMPDIR) foo.rs |\
 		grep -q 'test foo_0 ... ok'
diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk
index dab6511eb9d..38afa42a293 100644
--- a/src/test/run-make/tools.mk
+++ b/src/test/run-make/tools.mk
@@ -5,7 +5,7 @@ HOST_RPATH_ENV = \
 TARGET_RPATH_ENV = \
     $(LD_LIB_PATH_ENVVAR)="$(TMPDIR):$(TARGET_RPATH_DIR):$($(LD_LIB_PATH_ENVVAR))"
 
-BARE_RUSTC := $(HOST_RPATH_ENV) $(RUSTC)
+BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)'
 RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS)
 #CC := $(CC) -L $(TMPDIR)
 HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 81265f6ccaf..e7019de8f43 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -27,6 +27,7 @@ pub enum Mode {
     Rustdoc,
     CodegenUnits,
     Incremental,
+    RunMake,
 }
 
 impl FromStr for Mode {
@@ -45,6 +46,7 @@ impl FromStr for Mode {
           "rustdoc" => Ok(Rustdoc),
           "codegen-units" => Ok(CodegenUnits),
           "incremental" => Ok(Incremental),
+          "run-make" => Ok(RunMake),
           _ => Err(()),
         }
     }
@@ -65,6 +67,7 @@ impl fmt::Display for Mode {
             Rustdoc => "rustdoc",
             CodegenUnits => "codegen-units",
             Incremental => "incremental",
+            RunMake => "run-make",
         }, f)
     }
 }
@@ -165,4 +168,12 @@ pub struct Config {
 
     // Print one character per test instead of one line
     pub quiet: bool,
+
+    // Configuration for various run-make tests frobbing things like C compilers
+    // or querying about various LLVM component information.
+    pub cc: String,
+    pub cxx: String,
+    pub cflags: String,
+    pub llvm_components: String,
+    pub llvm_cxxflags: String,
 }
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index ef93fcfa013..c8df8739f52 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -291,6 +291,9 @@ pub fn early_props(config: &Config, testfile: &Path) -> EarlyProps {
 fn iter_header(testfile: &Path,
                cfg: Option<&str>,
                it: &mut FnMut(&str)) {
+    if testfile.is_dir() {
+        return
+    }
     let rdr = BufReader::new(File::open(testfile).unwrap());
     for ln in rdr.lines() {
         // Assume that any directives will be found before the first
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index a9810099dbf..26382967c6b 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -35,7 +35,7 @@ use std::io;
 use std::path::{Path, PathBuf};
 use getopts::{optopt, optflag, reqopt};
 use common::Config;
-use common::{Pretty, DebugInfoGdb, DebugInfoLldb};
+use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode};
 use test::TestPaths;
 use util::logv;
 
@@ -100,6 +100,11 @@ pub fn parse_config(args: Vec<String> ) -> Config {
           optopt("", "adb-path", "path to the android debugger", "PATH"),
           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
           optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH"),
+          reqopt("", "cc", "path to a C compiler", "PATH"),
+          reqopt("", "cxx", "path to a C++ compiler", "PATH"),
+          reqopt("", "cflags", "flags for the C compiler", "FLAGS"),
+          reqopt("", "llvm-components", "list of LLVM components built in", "LIST"),
+          reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS"),
           optflag("h", "help", "show this message"));
 
     let (argv0, args_) = args.split_first().unwrap();
@@ -175,6 +180,12 @@ pub fn parse_config(args: Vec<String> ) -> Config {
         lldb_python_dir: matches.opt_str("lldb-python-dir"),
         verbose: matches.opt_present("verbose"),
         quiet: matches.opt_present("quiet"),
+
+        cc: matches.opt_str("cc").unwrap(),
+        cxx: matches.opt_str("cxx").unwrap(),
+        cflags: matches.opt_str("cflags").unwrap(),
+        llvm_components: matches.opt_str("llvm-components").unwrap(),
+        llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(),
     }
 }
 
@@ -307,9 +318,19 @@ fn collect_tests_from_dir(config: &Config,
     // `compiletest-ignore-dir`.
     for file in fs::read_dir(dir)? {
         let file = file?;
-        if file.file_name() == *"compiletest-ignore-dir" {
+        let name = file.file_name();
+        if name == *"compiletest-ignore-dir" {
             return Ok(());
         }
+        if name == *"Makefile" && config.mode == Mode::RunMake {
+            let paths = TestPaths {
+                file: dir.to_path_buf(),
+                base: base.to_path_buf(),
+                relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
+            };
+            tests.push(make_test(config, &paths));
+            return Ok(())
+        }
     }
 
     let dirs = fs::read_dir(dir)?;
diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs
index f418edf6686..53b7cd059be 100644
--- a/src/tools/compiletest/src/procsrv.rs
+++ b/src/tools/compiletest/src/procsrv.rs
@@ -14,16 +14,20 @@ use std::io::prelude::*;
 use std::path::PathBuf;
 use std::process::{ExitStatus, Command, Child, Output, Stdio};
 
-fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) {
-    // Need to be sure to put both the lib_path and the aux path in the dylib
-    // search path for the child.
-    let var = if cfg!(windows) {
+pub fn dylib_env_var() -> &'static str {
+    if cfg!(windows) {
         "PATH"
     } else if cfg!(target_os = "macos") {
         "DYLD_LIBRARY_PATH"
     } else {
         "LD_LIBRARY_PATH"
-    };
+    }
+}
+
+fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) {
+    // Need to be sure to put both the lib_path and the aux path in the dylib
+    // search path for the child.
+    let var = dylib_env_var();
     let mut path = env::split_paths(&env::var_os(var).unwrap_or(OsString::new()))
                        .collect::<Vec<_>>();
     if let Some(p) = aux_path {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index e0abf8200a0..fb296d57ebf 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -11,7 +11,7 @@
 use common::Config;
 use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
 use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
-use common::{Incremental};
+use common::{Incremental, RunMake};
 use errors::{self, ErrorKind, Error};
 use json;
 use header::TestProps;
@@ -24,7 +24,7 @@ use std::env;
 use std::collections::HashSet;
 use std::fmt;
 use std::fs::{self, File};
-use std::io::BufReader;
+use std::io::{self, BufReader};
 use std::io::prelude::*;
 use std::net::TcpStream;
 use std::path::{Path, PathBuf};
@@ -62,6 +62,7 @@ pub fn run(config: Config, testpaths: &TestPaths) {
         Rustdoc => run_rustdoc_test(&config, &props, &testpaths),
         CodegenUnits => run_codegen_units_test(&config, &props, &testpaths),
         Incremental => run_incremental_test(&config, &props, &testpaths),
+        RunMake => run_rmake_test(&config, &props, &testpaths),
     }
 }
 
@@ -1233,7 +1234,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
                             testpaths: &TestPaths, args: ProcArgs,
                             input: Option<String>) -> ProcRes {
     if !props.aux_builds.is_empty() {
-        ensure_dir(&aux_output_dir_name(config, testpaths));
+        create_dir_racy(&aux_output_dir_name(config, testpaths));
     }
 
     let aux_dir = aux_output_dir_name(config, testpaths);
@@ -1307,11 +1308,6 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
                     input)
 }
 
-fn ensure_dir(path: &Path) {
-    if path.is_dir() { return; }
-    fs::create_dir_all(path).unwrap();
-}
-
 fn compose_and_run(config: &Config,
                    testpaths: &TestPaths,
                    ProcArgs{ args, prog }: ProcArgs,
@@ -1373,6 +1369,7 @@ fn make_compile_args<F>(config: &Config,
         DebugInfoLldb |
         Codegen |
         Rustdoc |
+        RunMake |
         CodegenUnits => {
             // do not use JSON output
         }
@@ -1520,6 +1517,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
 }
 
 fn dump_output(config: &Config, testpaths: &TestPaths, out: &str, err: &str) {
+    create_dir_racy(output_base_name(config, testpaths).parent().unwrap());
     dump_output_file(config, testpaths, out, "out");
     dump_output_file(config, testpaths, err, "err");
     maybe_dump_to_stdout(config, out, err);
@@ -1825,7 +1823,7 @@ fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
 
     let out_dir = output_base_name(config, testpaths);
     let _ = fs::remove_dir_all(&out_dir);
-    ensure_dir(&out_dir);
+    create_dir_racy(&out_dir);
 
     let proc_res = document(config, props, testpaths, &out_dir);
     if !proc_res.status.success() {
@@ -2029,7 +2027,7 @@ fn run_incremental_test(config: &Config, props: &TestProps, testpaths: &TestPath
     if incremental_dir.exists() {
         fs::remove_dir_all(&incremental_dir).unwrap();
     }
-    fs::create_dir_all(&incremental_dir).unwrap();
+    create_dir_racy(&incremental_dir);
 
     if config.verbose {
         print!("incremental_dir={}", incremental_dir.display());
@@ -2063,3 +2061,102 @@ fn run_incremental_test(config: &Config, props: &TestProps, testpaths: &TestPath
         }
     }
 }
+
+fn run_rmake_test(config: &Config, _props: &TestProps, testpaths: &TestPaths) {
+    let cwd = env::current_dir().unwrap();
+    let src_root = config.src_base.parent().unwrap().parent().unwrap()
+                                  .parent().unwrap();
+    let src_root = cwd.join(&src_root);
+
+    let tmpdir = cwd.join(output_base_name(config, testpaths));
+    if tmpdir.exists() {
+        aggressive_rm_rf(&tmpdir).unwrap();
+    }
+    create_dir_racy(&tmpdir);
+
+    let mut cmd = Command::new("make");
+    cmd.current_dir(&testpaths.file)
+       .env("TARGET", &config.target)
+       .env("PYTHON", &config.docck_python)
+       .env("S", src_root)
+       .env("RUST_BUILD_STAGE", &config.stage_id)
+       .env("RUSTC", cwd.join(&config.rustc_path))
+       .env("RUSTDOC", cwd.join(&config.rustdoc_path))
+       .env("TMPDIR", &tmpdir)
+       .env("LD_LIB_PATH_ENVVAR", procsrv::dylib_env_var())
+       .env("HOST_RPATH_DIR", cwd.join(&config.compile_lib_path))
+       .env("TARGET_RPATH_DIR", cwd.join(&config.run_lib_path))
+       .env("LLVM_COMPONENTS", &config.llvm_components)
+       .env("LLVM_CXXFLAGS", &config.llvm_cxxflags);
+
+    if config.target.contains("msvc") {
+        // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
+        // and that `lib.exe` lives next to it.
+        let lib = Path::new(&config.cc).parent().unwrap().join("lib.exe");
+
+        // MSYS doesn't like passing flags of the form `/foo` as it thinks it's
+        // a path and instead passes `C:\msys64\foo`, so convert all
+        // `/`-arguments to MSVC here to `-` arguments.
+        let cflags = config.cflags.split(' ').map(|s| s.replace("/", "-"))
+                           .collect::<Vec<_>>().join(" ");
+
+        cmd.env("IS_MSVC", "1")
+           .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
+           .env("CC", format!("'{}' {}", config.cc, cflags))
+           .env("CXX", &config.cxx);
+    } else {
+        cmd.env("CC", format!("{} {}", config.cc, config.cflags))
+           .env("CXX", format!("{} {}", config.cxx, config.cflags));
+    }
+
+    let output = cmd.output().expect("failed to spawn `make`");
+    if !output.status.success() {
+        let res = ProcRes {
+            status: Status::Normal(output.status),
+            stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
+            stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
+            cmdline: format!("{:?}", cmd),
+        };
+        fatal_proc_rec(None, "make failed", &res);
+    }
+}
+
+fn aggressive_rm_rf(path: &Path) -> io::Result<()> {
+    for e in try!(path.read_dir()) {
+        let entry = try!(e);
+        let path = entry.path();
+        if try!(entry.file_type()).is_dir() {
+            try!(aggressive_rm_rf(&path));
+        } else {
+            // Remove readonly files as well on windows (by default we can't)
+            try!(fs::remove_file(&path).or_else(|e| {
+                if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied {
+                    let mut meta = try!(entry.metadata()).permissions();
+                    meta.set_readonly(false);
+                    try!(fs::set_permissions(&path, meta));
+                    fs::remove_file(&path)
+                } else {
+                    Err(e)
+                }
+            }))
+        }
+    }
+    fs::remove_dir(path)
+}
+
+// Like std::fs::create_dir_all, except handles concurrent calls among multiple
+// threads or processes.
+fn create_dir_racy(path: &Path) {
+    match fs::create_dir(path) {
+        Ok(()) => return,
+        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => return,
+        Err(ref e) if e.kind() == io::ErrorKind::NotFound => {}
+        Err(e) => panic!("failed to create dir {:?}: {}", path, e),
+    }
+    create_dir_racy(path.parent().unwrap());
+    match fs::create_dir(path) {
+        Ok(()) => {}
+        Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {}
+        Err(e) => panic!("failed to create dir {:?}: {}", path, e),
+    }
+}