Skip to content

Commit

Permalink
Auto merge of #26601 - alexcrichton:xp, r=brson
Browse files Browse the repository at this point in the history
This series of commits (currently rebased on #26569 to avoid conflicts) adds support for the standard library to run on Windows XP. The main motivation behind this PR is that to enable any Rust code in Firefox we need to support Windows XP.

This PR doesn't yet intend to be a move to make Windows XP an officially supported platform, but instead simply get Rust code running on it. APIs like condition variables and RWLocks will immediately panic currently on XP, and it's unclear if that story wants to change much. Additionally, we may bind APIs like IOCP which aren't available on XP and would be *very* difficult to provide a fallback implementation. Essentially this PR enables running Rust on XP, but you still have to be careful to avoid non-XP portions of the standard library.

The major components of this PR are:

* Support for a new `i686-pc-windows-msvc` triple. This primarily involves a lot of build system hackery, but there are also a number of floating point functions which had to get switched up a bit.
* All APIs not available on Windows are now accessed through our dynamic-detection mechanism
* Mutexes on Windows were rewritten to use SRWLOCK as an optimization but can fall back to CRITICAL_SECTION.
  • Loading branch information
bors committed Jun 28, 2015
2 parents 8fa2185 + 10b103a commit 5da0d41
Show file tree
Hide file tree
Showing 21 changed files with 677 additions and 321 deletions.
60 changes: 47 additions & 13 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ do
fi
;;

x86_64-*-msvc)
*-msvc)
# Currently the build system is not configured to build jemalloc
# with MSVC, so we omit this optional dependency.
step_msg "targeting MSVC, disabling jemalloc"
Expand Down Expand Up @@ -1154,22 +1154,45 @@ do
CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//')
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
CFG_MSVC_CL="${CFG_MSVC_ROOT}/VC/bin/amd64/cl.exe"
CFG_MSVC_LIB="${CFG_MSVC_ROOT}/VC/bin/amd64/lib.exe"
CFG_MSVC_LINK="${CFG_MSVC_ROOT}/VC/bin/amd64/link.exe"
putvar CFG_MSVC_ROOT

case $i in
x86_64-*)
bits=x86_64
msvc_part=amd64
;;
i686-*)
bits=i386
msvc_part=
;;
*)
err "can only target x86 targets for MSVC"
;;
esac
bindir="${CFG_MSVC_ROOT}/VC/bin"
if [ ! -z "$msvc_part" ]; then
bindir="$bindir/$msvc_part"
fi
eval CFG_MSVC_BINDIR_$bits="\"$bindir\""
eval CFG_MSVC_CL_$bits="\"$bindir/cl.exe\""
eval CFG_MSVC_LIB_$bits="\"$bindir/lib.exe\""
eval CFG_MSVC_LINK_$bits="\"$bindir/link.exe\""

vcvarsall="${CFG_MSVC_ROOT}/VC/vcvarsall.bat"
CFG_MSVC_INCLUDE_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %INCLUDE%")
include_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %INCLUDE%")
need_ok "failed to learn about MSVC's INCLUDE"
CFG_MSVC_LIB_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %LIB%")
lib_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %LIB%")
need_ok "failed to learn about MSVC's LIB"

putvar CFG_MSVC_ROOT
putvar CFG_MSVC_CL
putvar CFG_MSVC_LIB
putvar CFG_MSVC_LINK
putvar CFG_MSVC_INCLUDE_PATH
putvar CFG_MSVC_LIB_PATH
eval CFG_MSVC_INCLUDE_PATH_${bits}="\"$include_path\""
eval CFG_MSVC_LIB_PATH_${bits}="\"$lib_path\""

putvar CFG_MSVC_BINDIR_${bits}
putvar CFG_MSVC_CL_${bits}
putvar CFG_MSVC_LIB_${bits}
putvar CFG_MSVC_LINK_${bits}
putvar CFG_MSVC_INCLUDE_PATH_${bits}
putvar CFG_MSVC_LIB_PATH_${bits}
;;

*)
Expand Down Expand Up @@ -1408,8 +1431,19 @@ do

msg "configuring LLVM with:"
msg "$CMAKE_ARGS"
case "$t" in
x86_64-*)
generator="Visual Studio 12 2013 Win64"
;;
i686-*)
generator="Visual Studio 12 2013"
;;
*)
err "can only build LLVM for x86 platforms"
;;
esac
(cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \
-G "Visual Studio 12 2013 Win64" \
-G "$generator" \
$CMAKE_ARGS)
need_ok "LLVM cmake configure failed"
fi
Expand Down
29 changes: 29 additions & 0 deletions mk/cfg/i686-pc-windows-msvc.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 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
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_LINK_FLAGS_i686-pc-windows-msvc :=
CFG_GCCISH_DEF_FLAG_i686-pc-windows-msvc :=
CFG_LLC_FLAGS_i686-pc-windows-msvc :=
CFG_INSTALL_NAME_i686-pc-windows-msvc =
CFG_EXE_SUFFIX_i686-pc-windows-msvc := .exe
CFG_WINDOWSY_i686-pc-windows-msvc := 1
CFG_UNIXY_i686-pc-windows-msvc :=
CFG_LDPATH_i686-pc-windows-msvc :=
CFG_RUN_i686-pc-windows-msvc=$(2)
CFG_RUN_TARG_i686-pc-windows-msvc=$(call CFG_RUN_i686-pc-windows-msvc,,$(2))
CFG_GNU_TRIPLE_i686-pc-windows-msvc := i686-pc-win32

# All windows nightiles are currently a GNU triple, so this MSVC triple is not
# bootstrapping from itself. This is relevant during stage0, and other parts of
# the build system take this into account.
BOOTSTRAP_FROM_i686-pc-windows-msvc := i686-pc-windows-gnu
10 changes: 5 additions & 5 deletions mk/cfg/x86_64-pc-windows-msvc.mk
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# x86_64-pc-windows-msvc configuration
CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK)" -nologo
CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB)" -nologo
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
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}
Expand Down
18 changes: 1 addition & 17 deletions mk/platform.mk
Original file line number Diff line number Diff line change
Expand Up @@ -239,23 +239,6 @@ endef
$(foreach target,$(CFG_TARGET), \
$(eval $(call CFG_MAKE_TOOLCHAIN,$(target))))

# These two environment variables are scraped by the `./configure` script and
# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and
# for `link.exe` to find standard libraries (the LIB variable).
ifdef CFG_MSVC_INCLUDE_PATH
export INCLUDE := $(CFG_MSVC_INCLUDE_PATH)
endif
ifdef CFG_MSVC_LIB_PATH
export LIB := $(CFG_MSVC_LIB_PATH)
endif

# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs,
# but it's not the one that we want. As a result we make sure that our detected
# `link.exe` shows up in PATH first.
ifdef CFG_MSVC_LINK
export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH)
endif

# There are more comments about this available in the target specification for
# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
# instead of `lib.exe` for assembling archives, so we need to inject this custom
Expand Down Expand Up @@ -307,3 +290,4 @@ endef

$(foreach target,$(CFG_TARGET), \
$(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target))))

19 changes: 19 additions & 0 deletions mk/rt.mk
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
rust_android_dummy.c
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
ifeq ($$(findstring msvc,$(1)),msvc)
ifeq ($$(findstring i686,$(1)),i686)
NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll
else
NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll
endif
else
NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll
endif
Expand Down Expand Up @@ -93,6 +97,17 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.S $$(MKFILE_DEPS) \
@mkdir -p $$(@D)
@$$(call E, compile: $$@)
$$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)

# On MSVC targets the compiler's default include path (e.g. where to find system
# headers) is specified by the INCLUDE environment variable. This may not be set
# so the ./configure script scraped the relevant values and this is the location
# that we put them into cl.exe's environment.
ifeq ($$(findstring msvc,$(1)),msvc)
$$(RT_OUTPUT_DIR_$(1))/%.o: \
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1)))
$(1)/rustllvm/%.o: \
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1)))
endif
endef

$(foreach target,$(CFG_TARGET),$(eval $(call NATIVE_LIBRARIES,$(target))))
Expand Down Expand Up @@ -240,8 +255,12 @@ COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1))
ifeq ($$(findstring msvc,$(1)),msvc)
COMPRT_CC_$(1) := gcc
COMPRT_AR_$(1) := ar
ifeq ($$(findstring i686,$(1)),i686)
COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m32
else
COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m64
endif
endif

$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS)
@$$(call E, make: compiler-rt)
Expand Down
37 changes: 37 additions & 0 deletions mk/target.mk
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,40 @@ $(foreach target,$(CFG_TARGET), \
$(foreach crate,$(CRATES), \
$(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \
$(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool))))))

# For MSVC targets we need to set up some environment variables for the linker
# to work correctly when building Rust crates. These two variables are:
#
# - LIB tells the linker the default search path for finding system libraries,
# for example kernel32.dll
# - PATH needs to be modified to ensure that MSVC's link.exe is first in the
# path instead of MinGW's /usr/bin/link.exe (entirely unrelated)
#
# The values for these variables are detected by the configure script.
define SETUP_LIB_MSVC_ENV_VARS
ifeq ($$(findstring msvc,$(2)),msvc)
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
endif
endef
define SETUP_TOOL_MSVC_ENV_VARS
ifeq ($$(findstring msvc,$(2)),msvc)
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
endif
endef

$(foreach host,$(CFG_HOST), \
$(foreach target,$(CFG_TARGET), \
$(foreach stage,$(STAGES), \
$(foreach crate,$(CRATES), \
$(eval $(call SETUP_LIB_MSVC_ENV_VARS,$(stage),$(target),$(host),$(crate)))))))
$(foreach host,$(CFG_HOST), \
$(foreach target,$(CFG_TARGET), \
$(foreach stage,$(STAGES), \
$(foreach tool,$(TOOLS), \
$(eval $(call SETUP_TOOL_MSVC_ENV_VARS,$(stage),$(target),$(host),$(tool)))))))
60 changes: 54 additions & 6 deletions src/libcore/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,37 @@ impl Float for f32 {
/// Rounds towards minus infinity.
#[inline]
fn floor(self) -> f32 {
unsafe { intrinsics::floorf32(self) }
return floorf(self);

// On MSVC LLVM will lower many math intrinsics to a call to the
// corresponding function. On MSVC, however, many of these functions
// aren't actually available as symbols to call, but rather they are all
// `static inline` functions in header files. This means that from a C
// perspective it's "compatible", but not so much from an ABI
// perspective (which we're worried about).
//
// The inline header functions always just cast to a f64 and do their
// operation, so we do that here as well, but only for MSVC targets.
//
// Note that there are many MSVC-specific float operations which
// redirect to this comment, so `floorf` is just one case of a missing
// function on MSVC, but there are many others elsewhere.
#[cfg(target_env = "msvc")]
fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
#[cfg(not(target_env = "msvc"))]
fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
}

/// Rounds towards plus infinity.
#[inline]
fn ceil(self) -> f32 {
unsafe { intrinsics::ceilf32(self) }
return ceilf(self);

// see notes above in `floor`
#[cfg(target_env = "msvc")]
fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
#[cfg(not(target_env = "msvc"))]
fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
}

/// Rounds to nearest integer. Rounds half-way cases away from zero.
Expand Down Expand Up @@ -299,7 +323,13 @@ impl Float for f32 {

#[inline]
fn powf(self, n: f32) -> f32 {
unsafe { intrinsics::powf32(self, n) }
return powf(self, n);

// see notes above in `floor`
#[cfg(target_env = "msvc")]
fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
#[cfg(not(target_env = "msvc"))]
fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
}

#[inline]
Expand All @@ -317,7 +347,13 @@ impl Float for f32 {
/// Returns the exponential of the number.
#[inline]
fn exp(self) -> f32 {
unsafe { intrinsics::expf32(self) }
return expf(self);

// see notes above in `floor`
#[cfg(target_env = "msvc")]
fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
#[cfg(not(target_env = "msvc"))]
fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
}

/// Returns 2 raised to the power of the number.
Expand All @@ -329,7 +365,13 @@ impl Float for f32 {
/// Returns the natural logarithm of the number.
#[inline]
fn ln(self) -> f32 {
unsafe { intrinsics::logf32(self) }
return logf(self);

// see notes above in `floor`
#[cfg(target_env = "msvc")]
fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
#[cfg(not(target_env = "msvc"))]
fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
}

/// Returns the logarithm of the number with respect to an arbitrary base.
Expand All @@ -345,7 +387,13 @@ impl Float for f32 {
/// Returns the base 10 logarithm of the number.
#[inline]
fn log10(self) -> f32 {
unsafe { intrinsics::log10f32(self) }
return log10f(self);

// see notes above in `floor`
#[cfg(target_env = "msvc")]
fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
#[cfg(not(target_env = "msvc"))]
fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
}

/// Converts to degrees, assuming the number is in radians.
Expand Down
Loading

0 comments on commit 5da0d41

Please sign in to comment.