Skip to content

Commit 5da0d41

Browse files
committed
Auto merge of #26601 - alexcrichton:xp, r=brson
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.
2 parents 8fa2185 + 10b103a commit 5da0d41

21 files changed

+677
-321
lines changed

configure

+47-13
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,7 @@ do
11141114
fi
11151115
;;
11161116

1117-
x86_64-*-msvc)
1117+
*-msvc)
11181118
# Currently the build system is not configured to build jemalloc
11191119
# with MSVC, so we omit this optional dependency.
11201120
step_msg "targeting MSVC, disabling jemalloc"
@@ -1154,22 +1154,45 @@ do
11541154
CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//')
11551155
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
11561156
CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
1157-
CFG_MSVC_CL="${CFG_MSVC_ROOT}/VC/bin/amd64/cl.exe"
1158-
CFG_MSVC_LIB="${CFG_MSVC_ROOT}/VC/bin/amd64/lib.exe"
1159-
CFG_MSVC_LINK="${CFG_MSVC_ROOT}/VC/bin/amd64/link.exe"
1157+
putvar CFG_MSVC_ROOT
1158+
1159+
case $i in
1160+
x86_64-*)
1161+
bits=x86_64
1162+
msvc_part=amd64
1163+
;;
1164+
i686-*)
1165+
bits=i386
1166+
msvc_part=
1167+
;;
1168+
*)
1169+
err "can only target x86 targets for MSVC"
1170+
;;
1171+
esac
1172+
bindir="${CFG_MSVC_ROOT}/VC/bin"
1173+
if [ ! -z "$msvc_part" ]; then
1174+
bindir="$bindir/$msvc_part"
1175+
fi
1176+
eval CFG_MSVC_BINDIR_$bits="\"$bindir\""
1177+
eval CFG_MSVC_CL_$bits="\"$bindir/cl.exe\""
1178+
eval CFG_MSVC_LIB_$bits="\"$bindir/lib.exe\""
1179+
eval CFG_MSVC_LINK_$bits="\"$bindir/link.exe\""
11601180

11611181
vcvarsall="${CFG_MSVC_ROOT}/VC/vcvarsall.bat"
1162-
CFG_MSVC_INCLUDE_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %INCLUDE%")
1182+
include_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %INCLUDE%")
11631183
need_ok "failed to learn about MSVC's INCLUDE"
1164-
CFG_MSVC_LIB_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %LIB%")
1184+
lib_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %LIB%")
11651185
need_ok "failed to learn about MSVC's LIB"
11661186

1167-
putvar CFG_MSVC_ROOT
1168-
putvar CFG_MSVC_CL
1169-
putvar CFG_MSVC_LIB
1170-
putvar CFG_MSVC_LINK
1171-
putvar CFG_MSVC_INCLUDE_PATH
1172-
putvar CFG_MSVC_LIB_PATH
1187+
eval CFG_MSVC_INCLUDE_PATH_${bits}="\"$include_path\""
1188+
eval CFG_MSVC_LIB_PATH_${bits}="\"$lib_path\""
1189+
1190+
putvar CFG_MSVC_BINDIR_${bits}
1191+
putvar CFG_MSVC_CL_${bits}
1192+
putvar CFG_MSVC_LIB_${bits}
1193+
putvar CFG_MSVC_LINK_${bits}
1194+
putvar CFG_MSVC_INCLUDE_PATH_${bits}
1195+
putvar CFG_MSVC_LIB_PATH_${bits}
11731196
;;
11741197

11751198
*)
@@ -1408,8 +1431,19 @@ do
14081431

14091432
msg "configuring LLVM with:"
14101433
msg "$CMAKE_ARGS"
1434+
case "$t" in
1435+
x86_64-*)
1436+
generator="Visual Studio 12 2013 Win64"
1437+
;;
1438+
i686-*)
1439+
generator="Visual Studio 12 2013"
1440+
;;
1441+
*)
1442+
err "can only build LLVM for x86 platforms"
1443+
;;
1444+
esac
14111445
(cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \
1412-
-G "Visual Studio 12 2013 Win64" \
1446+
-G "$generator" \
14131447
$CMAKE_ARGS)
14141448
need_ok "LLVM cmake configure failed"
14151449
fi

mk/cfg/i686-pc-windows-msvc.mk

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# i686-pc-windows-msvc configuration
2+
CC_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
3+
LINK_i686-pc-windows-msvc="$(CFG_MSVC_LINK_i386)" -nologo
4+
CXX_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
5+
CPP_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo
6+
AR_i686-pc-windows-msvc="$(CFG_MSVC_LIB_i386)" -nologo
7+
CFG_LIB_NAME_i686-pc-windows-msvc=$(1).dll
8+
CFG_STATIC_LIB_NAME_i686-pc-windows-msvc=$(1).lib
9+
CFG_LIB_GLOB_i686-pc-windows-msvc=$(1)-*.{dll,lib}
10+
CFG_LIB_DSYM_GLOB_i686-pc-windows-msvc=$(1)-*.dylib.dSYM
11+
CFG_JEMALLOC_CFLAGS_i686-pc-windows-msvc :=
12+
CFG_GCCISH_CFLAGS_i686-pc-windows-msvc := -MD
13+
CFG_GCCISH_CXXFLAGS_i686-pc-windows-msvc := -MD
14+
CFG_GCCISH_LINK_FLAGS_i686-pc-windows-msvc :=
15+
CFG_GCCISH_DEF_FLAG_i686-pc-windows-msvc :=
16+
CFG_LLC_FLAGS_i686-pc-windows-msvc :=
17+
CFG_INSTALL_NAME_i686-pc-windows-msvc =
18+
CFG_EXE_SUFFIX_i686-pc-windows-msvc := .exe
19+
CFG_WINDOWSY_i686-pc-windows-msvc := 1
20+
CFG_UNIXY_i686-pc-windows-msvc :=
21+
CFG_LDPATH_i686-pc-windows-msvc :=
22+
CFG_RUN_i686-pc-windows-msvc=$(2)
23+
CFG_RUN_TARG_i686-pc-windows-msvc=$(call CFG_RUN_i686-pc-windows-msvc,,$(2))
24+
CFG_GNU_TRIPLE_i686-pc-windows-msvc := i686-pc-win32
25+
26+
# All windows nightiles are currently a GNU triple, so this MSVC triple is not
27+
# bootstrapping from itself. This is relevant during stage0, and other parts of
28+
# the build system take this into account.
29+
BOOTSTRAP_FROM_i686-pc-windows-msvc := i686-pc-windows-gnu

mk/cfg/x86_64-pc-windows-msvc.mk

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# x86_64-pc-windows-msvc configuration
2-
CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
3-
LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK)" -nologo
4-
CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
5-
CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
6-
AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB)" -nologo
2+
CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
3+
LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK_x86_64)" -nologo
4+
CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
5+
CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo
6+
AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB_x86_64)" -nologo
77
CFG_LIB_NAME_x86_64-pc-windows-msvc=$(1).dll
88
CFG_STATIC_LIB_NAME_x86_64-pc-windows-msvc=$(1).lib
99
CFG_LIB_GLOB_x86_64-pc-windows-msvc=$(1)-*.{dll,lib}

mk/platform.mk

+1-17
Original file line numberDiff line numberDiff line change
@@ -239,23 +239,6 @@ endef
239239
$(foreach target,$(CFG_TARGET), \
240240
$(eval $(call CFG_MAKE_TOOLCHAIN,$(target))))
241241

242-
# These two environment variables are scraped by the `./configure` script and
243-
# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and
244-
# for `link.exe` to find standard libraries (the LIB variable).
245-
ifdef CFG_MSVC_INCLUDE_PATH
246-
export INCLUDE := $(CFG_MSVC_INCLUDE_PATH)
247-
endif
248-
ifdef CFG_MSVC_LIB_PATH
249-
export LIB := $(CFG_MSVC_LIB_PATH)
250-
endif
251-
252-
# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs,
253-
# but it's not the one that we want. As a result we make sure that our detected
254-
# `link.exe` shows up in PATH first.
255-
ifdef CFG_MSVC_LINK
256-
export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH)
257-
endif
258-
259242
# There are more comments about this available in the target specification for
260243
# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
261244
# instead of `lib.exe` for assembling archives, so we need to inject this custom
@@ -307,3 +290,4 @@ endef
307290

308291
$(foreach target,$(CFG_TARGET), \
309292
$(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target))))
293+

mk/rt.mk

+19
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
5555
rust_android_dummy.c
5656
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
5757
ifeq ($$(findstring msvc,$(1)),msvc)
58+
ifeq ($$(findstring i686,$(1)),i686)
59+
NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll
60+
else
5861
NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll
62+
endif
5963
else
6064
NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll
6165
endif
@@ -93,6 +97,17 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.S $$(MKFILE_DEPS) \
9397
@mkdir -p $$(@D)
9498
@$$(call E, compile: $$@)
9599
$$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<)
100+
101+
# On MSVC targets the compiler's default include path (e.g. where to find system
102+
# headers) is specified by the INCLUDE environment variable. This may not be set
103+
# so the ./configure script scraped the relevant values and this is the location
104+
# that we put them into cl.exe's environment.
105+
ifeq ($$(findstring msvc,$(1)),msvc)
106+
$$(RT_OUTPUT_DIR_$(1))/%.o: \
107+
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1)))
108+
$(1)/rustllvm/%.o: \
109+
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1)))
110+
endif
96111
endef
97112

98113
$(foreach target,$(CFG_TARGET),$(eval $(call NATIVE_LIBRARIES,$(target))))
@@ -240,8 +255,12 @@ COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1))
240255
ifeq ($$(findstring msvc,$(1)),msvc)
241256
COMPRT_CC_$(1) := gcc
242257
COMPRT_AR_$(1) := ar
258+
ifeq ($$(findstring i686,$(1)),i686)
259+
COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m32
260+
else
243261
COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m64
244262
endif
263+
endif
245264

246265
$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS)
247266
@$$(call E, make: compiler-rt)

mk/target.mk

+37
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,40 @@ $(foreach target,$(CFG_TARGET), \
220220
$(foreach crate,$(CRATES), \
221221
$(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \
222222
$(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool))))))
223+
224+
# For MSVC targets we need to set up some environment variables for the linker
225+
# to work correctly when building Rust crates. These two variables are:
226+
#
227+
# - LIB tells the linker the default search path for finding system libraries,
228+
# for example kernel32.dll
229+
# - PATH needs to be modified to ensure that MSVC's link.exe is first in the
230+
# path instead of MinGW's /usr/bin/link.exe (entirely unrelated)
231+
#
232+
# The values for these variables are detected by the configure script.
233+
define SETUP_LIB_MSVC_ENV_VARS
234+
ifeq ($$(findstring msvc,$(2)),msvc)
235+
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
236+
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
237+
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
238+
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
239+
endif
240+
endef
241+
define SETUP_TOOL_MSVC_ENV_VARS
242+
ifeq ($$(findstring msvc,$(2)),msvc)
243+
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
244+
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
245+
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
246+
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
247+
endif
248+
endef
249+
250+
$(foreach host,$(CFG_HOST), \
251+
$(foreach target,$(CFG_TARGET), \
252+
$(foreach stage,$(STAGES), \
253+
$(foreach crate,$(CRATES), \
254+
$(eval $(call SETUP_LIB_MSVC_ENV_VARS,$(stage),$(target),$(host),$(crate)))))))
255+
$(foreach host,$(CFG_HOST), \
256+
$(foreach target,$(CFG_TARGET), \
257+
$(foreach stage,$(STAGES), \
258+
$(foreach tool,$(TOOLS), \
259+
$(eval $(call SETUP_TOOL_MSVC_ENV_VARS,$(stage),$(target),$(host),$(tool)))))))

src/libcore/num/f32.rs

+54-6
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,37 @@ impl Float for f32 {
215215
/// Rounds towards minus infinity.
216216
#[inline]
217217
fn floor(self) -> f32 {
218-
unsafe { intrinsics::floorf32(self) }
218+
return floorf(self);
219+
220+
// On MSVC LLVM will lower many math intrinsics to a call to the
221+
// corresponding function. On MSVC, however, many of these functions
222+
// aren't actually available as symbols to call, but rather they are all
223+
// `static inline` functions in header files. This means that from a C
224+
// perspective it's "compatible", but not so much from an ABI
225+
// perspective (which we're worried about).
226+
//
227+
// The inline header functions always just cast to a f64 and do their
228+
// operation, so we do that here as well, but only for MSVC targets.
229+
//
230+
// Note that there are many MSVC-specific float operations which
231+
// redirect to this comment, so `floorf` is just one case of a missing
232+
// function on MSVC, but there are many others elsewhere.
233+
#[cfg(target_env = "msvc")]
234+
fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
235+
#[cfg(not(target_env = "msvc"))]
236+
fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
219237
}
220238

221239
/// Rounds towards plus infinity.
222240
#[inline]
223241
fn ceil(self) -> f32 {
224-
unsafe { intrinsics::ceilf32(self) }
242+
return ceilf(self);
243+
244+
// see notes above in `floor`
245+
#[cfg(target_env = "msvc")]
246+
fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
247+
#[cfg(not(target_env = "msvc"))]
248+
fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
225249
}
226250

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

300324
#[inline]
301325
fn powf(self, n: f32) -> f32 {
302-
unsafe { intrinsics::powf32(self, n) }
326+
return powf(self, n);
327+
328+
// see notes above in `floor`
329+
#[cfg(target_env = "msvc")]
330+
fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
331+
#[cfg(not(target_env = "msvc"))]
332+
fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
303333
}
304334

305335
#[inline]
@@ -317,7 +347,13 @@ impl Float for f32 {
317347
/// Returns the exponential of the number.
318348
#[inline]
319349
fn exp(self) -> f32 {
320-
unsafe { intrinsics::expf32(self) }
350+
return expf(self);
351+
352+
// see notes above in `floor`
353+
#[cfg(target_env = "msvc")]
354+
fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
355+
#[cfg(not(target_env = "msvc"))]
356+
fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
321357
}
322358

323359
/// Returns 2 raised to the power of the number.
@@ -329,7 +365,13 @@ impl Float for f32 {
329365
/// Returns the natural logarithm of the number.
330366
#[inline]
331367
fn ln(self) -> f32 {
332-
unsafe { intrinsics::logf32(self) }
368+
return logf(self);
369+
370+
// see notes above in `floor`
371+
#[cfg(target_env = "msvc")]
372+
fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
373+
#[cfg(not(target_env = "msvc"))]
374+
fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
333375
}
334376

335377
/// Returns the logarithm of the number with respect to an arbitrary base.
@@ -345,7 +387,13 @@ impl Float for f32 {
345387
/// Returns the base 10 logarithm of the number.
346388
#[inline]
347389
fn log10(self) -> f32 {
348-
unsafe { intrinsics::log10f32(self) }
390+
return log10f(self);
391+
392+
// see notes above in `floor`
393+
#[cfg(target_env = "msvc")]
394+
fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
395+
#[cfg(not(target_env = "msvc"))]
396+
fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
349397
}
350398

351399
/// Converts to degrees, assuming the number is in radians.

0 commit comments

Comments
 (0)