43cf733bfa
Special thanks to @retep998 for the [excellent writeup](https://github.com/rust-lang/rfcs/issues/1061) of tasks to be done and @ricky26 for initially blazing the trail here! # MSVC Support This goal of this series of commits is to add MSVC support to the Rust compiler and build system, allowing it more easily interoperate with Visual Studio installations and native libraries compiled outside of MinGW. The tl;dr; of this change is that there is a new target of the compiler, `x86_64-pc-windows-msvc`, which will not interact with the MinGW toolchain at all and will instead use `link.exe` to assemble output artifacts. ## Why try to use MSVC? With today's Rust distribution, when you install a compiler on Windows you also install `gcc.exe` and a number of supporting libraries by default (this can be opted out of). This allows installations to remain independent of MinGW installations, but it still generally requires native code to be linked with MinGW instead of MSVC. Some more background can also be found in #1768 about the incompatibilities between MinGW and MSVC. Overall the current installation strategy is quite nice so long as you don't interact with native code, but once you do the usage of a MinGW-based `gcc.exe` starts to get quite painful. Relying on a nonstandard Windows toolchain has also been a long-standing "code smell" of Rust and has been slated for remedy for quite some time now. Using a standard toolchain is a great motivational factor for improving the interoperability of Rust code with the native system. ## What does it mean to use MSVC? "Using MSVC" can be a bit of a nebulous concept, but this PR defines it as: * The build system for Rust will build as much code as possible with the MSVC compiler, `cl.exe`. * The build system will use native MSVC tools for managing archives. * The compiler will link all output with `link.exe` instead of `gcc.exe`. None of these are currently implemented today, but all are required for the compiler to fluently interoperate with MSVC. ## How does this all work? At the highest level, this PR adds a new target triple to the Rust compiler: x86_64-pc-windows-msvc All logic for using MSVC or not is scoped within this triple and code can conditionally build for MSVC or MinGW via: #[cfg(target_env = "msvc")] It is expected that auto builders will be set up for MSVC-based compiles in addition to the existing MinGW-based compiles, and we will likely soon start shipping MSVC nightlies where `x86_64-pc-windows-msvc` is the host target triple of the compiler. # Summary of changes Here I'll explain at a high level what many of the changes made were targeted at, but many more details can be found in the commits themselves. Many thanks to @retep998 for the excellent writeup in rust-lang/rfcs#1061 and @rick26 for a lot of the initial proof-of-concept work! ## Build system changes As is probably expected, a large chunk of this PR is changes to Rust's build system to build with MSVC. At a high level **it is an explicit non goal** to enable building outside of a MinGW shell, instead all Makefile infrastructure we have today is retrofitted with support to use MSVC instead of the standard MSVC toolchain. Some of the high-level changes are: * The configure script now detects when MSVC is being targeted and adds a number of additional requirements about the build environment: * The `--msvc-root` option must be specified or `cl.exe` must be in PATH to discover where MSVC is installed. The compiler in use is also required to target x86_64. * Once the MSVC root is known, the INCLUDE/LIB environment variables are scraped so they can be reexported by the build system. * CMake is required to build LLVM with MSVC (and LLVM is also configured with CMake instead of the normal configure script). * jemalloc is currently unconditionally disabled for MSVC targets as jemalloc isn't a hard requirement and I don't know how to build it with MSVC. * Invocations of a C and/or C++ compiler are now abstracted behind macros to appropriately call the underlying compiler with the correct format of arguments, for example there is now a macro for "assemble an archive from objects" instead of hard-coded invocations of `$(AR) crus liboutput.a ...` * The output filenames for standard libraries such as morestack/compiler-rt are now "more correct" on windows as they are shipped as `foo.lib` instead of `libfoo.a`. * Rust targets can now depend on native tools provided by LLVM, and as you'll see in the commits the entire MSVC target depends on `llvm-ar.exe`. * Support for custom arbitrary makefile dependencies of Rust targets has been added. The MSVC target for `rustc_llvm` currently requires a custom `.DEF` file to be passed to the linker to get further linkages to complete. ## Compiler changes The modifications made to the compiler have so far largely been minor tweaks here and there, mostly just adding a layer of abstraction over whether MSVC or a GNU-like linker is being used. At a high-level these changes are: * The section name for metadata storage in dynamic libraries is called `.rustc` for MSVC-based platorms as section names cannot contain more than 8 characters. * The implementation of `rustc_back::Archive` was refactored, but the functionality has remained the same. * Targets can now specify the default `ar` utility to use, and for MSVC this defaults to `llvm-ar.exe` * The building of the linker command in `rustc_trans:🔙:link` has been abstracted behind a trait for the same code path to be used between GNU and MSVC linkers. ## Standard library changes Only a few small changes were required to the stadnard library itself, and only for minor differences between the C runtime of msvcrt.dll and MinGW's libc.a * Some function names for floating point functions have leading underscores, and some are not present at all. * Linkage to the `advapi32` library for crypto-related functions is now explicit. * Some small bits of C code here and there were fixed for compatibility with MSVC's cl.exe compiler. # Future Work This commit is not yet a 100% complete port to using MSVC as there are still some key components missing as well as some unimplemented optimizations. This PR is already getting large enough that I wanted to draw the line here, but here's a list of what is not implemented in this PR, on purpose: ## Unwinding The revision of our LLVM submodule [does not seem to implement][llvm] does not support lowering SEH exception handling on the Windows MSVC targets, so unwinding support is not currently implemented for the standard library (it's lowered to an abort). [llvm]: https://github.com/rust-lang/llvm/blob/rust-llvm-2015-02-19/lib/CodeGen/Passes.cpp#L454-L461 It looks like, however, that upstream LLVM has quite a bit more support for SEH unwinding and landing pads than the current revision we have, so adding support will likely just involve updating LLVM and then adding some shims of our own here and there. ## dllimport and dllexport An interesting part of Windows which MSVC forces our hand on (and apparently MinGW didn't) is the usage of `dllimport` and `dllexport` attributes in LLVM IR as well as native dependencies (in C these correspond to `__declspec(dllimport)`). Whenever a dynamic library is built by MSVC it must have its public interface specified by functions tagged with `dllexport` or otherwise they're not available to be linked against. This poses a few problems for the compiler, some of which are somewhat fundamental, but this commit alters the compiler to attach the `dllexport` attribute to all LLVM functions that are reachable (e.g. they're already tagged with external linkage). This is suboptimal for a few reasons: * If an object file will never be included in a dynamic library, there's no need to attach the dllexport attribute. Most object files in Rust are not destined to become part of a dll as binaries are statically linked by default. * If the compiler is emitting both an rlib and a dylib, the same source object file is currently used but with MSVC this may be less feasible. The compiler may be able to get around this, but it may involve some invasive changes to deal with this. The flipside of this situation is that whenever you link to a dll and you import a function from it, the import should be tagged with `dllimport`. At this time, however, the compiler does not emit `dllimport` for any declarations other than constants (where it is required), which is again suboptimal for even more reasons! * Calling a function imported from another dll without using `dllimport` causes the linker/compiler to have extra overhead (one `jmp` instruction on x86) when calling the function. * The same object file may be used in different circumstances, so a function may be imported from a dll if the object is linked into a dll, but it may be just linked against if linked into an rlib. * The compiler has no knowledge about whether native functions should be tagged dllimport or not. For now the compiler takes the perf hit (I do not have any numbers to this effect) by marking very little as `dllimport` and praying the linker will take care of everything. Fixing this problem will likely require adding a few attributes to Rust itself (feature gated at the start) and then strongly recommending static linkage on Windows! This may also involve shipping a statically linked compiler on Windows instead of a dynamically linked compiler, but these sorts of changes are pretty invasive and aren't part of this PR. ## CI integration Thankfully we don't need to set up a new snapshot bot for the changes made here as our snapshots are freestanding already, we should be able to use the same snapshot to bootstrap both MinGW and MSVC compilers (once a new snapshot is made from these changes). I plan on setting up a new suite of auto bots which are testing MSVC configurations for now as well, for now they'll just be bootstrapping and not running tests, but once unwinding is implemented they'll start running all tests as well and we'll eventually start gating on them as well. --- I'd love as many eyes on this as we've got as this was one of my first interactions with MSVC and Visual Studio, so there may be glaring holes that I'm missing here and there! cc @retep998, @ricky26, @vadimcn, @klutzy r? @brson
608 lines
20 KiB
Makefile
608 lines
20 KiB
Makefile
# Copyright 2014-2015 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.
|
|
|
|
######################################################################
|
|
# Version numbers and strings
|
|
######################################################################
|
|
|
|
# The version number
|
|
CFG_RELEASE_NUM=1.2.0
|
|
|
|
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
|
# NB Make sure it starts with a dot to conform to semver pre-release
|
|
# versions (section 9)
|
|
CFG_PRERELEASE_VERSION=.1
|
|
|
|
# Append a version-dependent hash to each library, so we can install different
|
|
# versions in the same place
|
|
CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE) | $(CFG_HASH_COMMAND))
|
|
|
|
ifeq ($(CFG_RELEASE_CHANNEL),stable)
|
|
# This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
|
|
CFG_RELEASE=$(CFG_RELEASE_NUM)
|
|
# This is the string used in dist artifact file names, e.g. "0.12.0", "nightly"
|
|
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)
|
|
CFG_DISABLE_UNSTABLE_FEATURES=1
|
|
endif
|
|
ifeq ($(CFG_RELEASE_CHANNEL),beta)
|
|
CFG_RELEASE=$(CFG_RELEASE_NUM)-beta
|
|
# When building beta distributables just reuse the same "beta" name
|
|
# so when we upload we'll always override the previous beta. This
|
|
# doesn't actually impact the version reported by rustc - it's just
|
|
# for file naming.
|
|
CFG_PACKAGE_VERS=beta
|
|
CFG_DISABLE_UNSTABLE_FEATURES=1
|
|
endif
|
|
ifeq ($(CFG_RELEASE_CHANNEL),nightly)
|
|
CFG_RELEASE=$(CFG_RELEASE_NUM)-nightly
|
|
# When building nightly distributables just reuse the same "nightly" name
|
|
# so when we upload we'll always override the previous nighly. This
|
|
# doesn't actually impact the version reported by rustc - it's just
|
|
# for file naming.
|
|
CFG_PACKAGE_VERS=nightly
|
|
endif
|
|
ifeq ($(CFG_RELEASE_CHANNEL),dev)
|
|
CFG_RELEASE=$(CFG_RELEASE_NUM)-dev
|
|
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-dev
|
|
endif
|
|
|
|
# The name of the package to use for creating tarballs, installers etc.
|
|
CFG_PACKAGE_NAME=rustc-$(CFG_PACKAGE_VERS)
|
|
|
|
# The version string plus commit information - this is what rustc reports
|
|
CFG_VERSION = $(CFG_RELEASE)
|
|
CFG_GIT_DIR := $(CFG_SRC_DIR).git
|
|
# since $(CFG_GIT) may contain spaces (especially on Windows),
|
|
# we need to escape them. (" " to r"\ ")
|
|
# Note that $(subst ...) ignores space after `subst`,
|
|
# so we use a hack: define $(SPACE) which contains space character.
|
|
SPACE :=
|
|
SPACE +=
|
|
ifneq ($(CFG_GIT),)
|
|
ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT_DIR))),)
|
|
CFG_VER_DATE = $(shell git --git-dir='$(CFG_GIT_DIR)' log -1 --date=short --pretty=format:'%cd')
|
|
CFG_VER_HASH = $(shell git --git-dir='$(CFG_GIT_DIR)' rev-parse HEAD)
|
|
CFG_SHORT_VER_HASH = $(shell git --git-dir='$(CFG_GIT_DIR)' rev-parse --short=9 HEAD)
|
|
CFG_VERSION += ($(CFG_SHORT_VER_HASH) $(CFG_VER_DATE))
|
|
endif
|
|
endif
|
|
|
|
CFG_BUILD_DATE = $(shell date +%F)
|
|
CFG_VERSION += (built $(CFG_BUILD_DATE))
|
|
|
|
# Windows exe's need numeric versions - don't use anything but
|
|
# numbers and dots here
|
|
CFG_VERSION_WIN = $(CFG_RELEASE_NUM)
|
|
|
|
CFG_INFO := $(info cfg: version $(CFG_VERSION))
|
|
|
|
######################################################################
|
|
# More configuration
|
|
######################################################################
|
|
|
|
MKFILE_DEPS := config.stamp $(call rwildcard,$(CFG_SRC_DIR)mk/,*)
|
|
MKFILES_FOR_TARBALL:=$(MKFILE_DEPS)
|
|
ifneq ($(NO_MKFILE_DEPS),)
|
|
MKFILE_DEPS :=
|
|
endif
|
|
NON_BUILD_HOST = $(filter-out $(CFG_BUILD),$(CFG_HOST))
|
|
NON_BUILD_TARGET = $(filter-out $(CFG_BUILD),$(CFG_TARGET))
|
|
|
|
ifneq ($(MAKE_RESTARTS),)
|
|
CFG_INFO := $(info cfg: make restarts: $(MAKE_RESTARTS))
|
|
endif
|
|
|
|
CFG_INFO := $(info cfg: build triple $(CFG_BUILD))
|
|
CFG_INFO := $(info cfg: host triples $(CFG_HOST))
|
|
CFG_INFO := $(info cfg: target triples $(CFG_TARGET))
|
|
|
|
ifneq ($(wildcard $(NON_BUILD_HOST)),)
|
|
CFG_INFO := $(info cfg: non-build host triples $(NON_BUILD_HOST))
|
|
endif
|
|
ifneq ($(wildcard $(NON_BUILD_TARGET)),)
|
|
CFG_INFO := $(info cfg: non-build target triples $(NON_BUILD_TARGET))
|
|
endif
|
|
|
|
CFG_RUSTC_FLAGS := $(RUSTFLAGS)
|
|
CFG_GCCISH_CFLAGS :=
|
|
CFG_GCCISH_LINK_FLAGS :=
|
|
|
|
# Turn off broken quarantine (see jemalloc/jemalloc#161)
|
|
CFG_JEMALLOC_FLAGS := --disable-fill
|
|
|
|
ifdef CFG_DISABLE_OPTIMIZE
|
|
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
|
|
CFG_RUSTC_FLAGS +=
|
|
CFG_JEMALLOC_FLAGS += --enable-debug
|
|
else
|
|
# The rtopt cfg turns off runtime sanity checks
|
|
CFG_RUSTC_FLAGS += -O --cfg rtopt
|
|
endif
|
|
|
|
CFG_JEMALLOC_FLAGS += $(JEMALLOC_FLAGS)
|
|
|
|
ifdef CFG_ENABLE_DEBUG_ASSERTIONS
|
|
$(info cfg: enabling debug assertions (CFG_ENABLE_DEBUG_ASSERTIONS))
|
|
CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on
|
|
else
|
|
CFG_RUSTC_FLAGS += --cfg ndebug
|
|
endif
|
|
|
|
ifdef CFG_ENABLE_DEBUGINFO
|
|
$(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO))
|
|
CFG_RUSTC_FLAGS += -g
|
|
endif
|
|
|
|
ifdef SAVE_TEMPS
|
|
CFG_RUSTC_FLAGS += --save-temps
|
|
endif
|
|
ifdef ASM_COMMENTS
|
|
CFG_RUSTC_FLAGS += -Z asm-comments
|
|
endif
|
|
ifdef TIME_PASSES
|
|
CFG_RUSTC_FLAGS += -Z time-passes
|
|
endif
|
|
ifdef TIME_LLVM_PASSES
|
|
CFG_RUSTC_FLAGS += -Z time-llvm-passes
|
|
endif
|
|
ifdef TRACE
|
|
CFG_RUSTC_FLAGS += -Z trace
|
|
endif
|
|
ifdef CFG_ENABLE_RPATH
|
|
CFG_RUSTC_FLAGS += -C rpath
|
|
endif
|
|
|
|
# The executables crated during this compilation process have no need to include
|
|
# static copies of libstd and libextra. We also generate dynamic versions of all
|
|
# libraries, so in the interest of space, prefer dynamic linking throughout the
|
|
# compilation process.
|
|
#
|
|
# Note though that these flags are omitted for the *bins* in stage2+. This means
|
|
# that the snapshot will be generated with a statically linked rustc so we only
|
|
# have to worry about the distribution of one file (with its native dynamic
|
|
# dependencies)
|
|
RUSTFLAGS_STAGE0 += -C prefer-dynamic
|
|
RUSTFLAGS_STAGE1 += -C prefer-dynamic
|
|
RUST_LIB_FLAGS_ST2 += -C prefer-dynamic
|
|
RUST_LIB_FLAGS_ST3 += -C prefer-dynamic
|
|
|
|
# Landing pads require a lot of codegen. We can get through bootstrapping faster
|
|
# by not emitting them.
|
|
RUSTFLAGS_STAGE0 += -Z no-landing-pads
|
|
|
|
# platform-specific auto-configuration
|
|
include $(CFG_SRC_DIR)mk/platform.mk
|
|
|
|
# Run the stage1/2 compilers under valgrind
|
|
ifdef VALGRIND_COMPILE
|
|
CFG_VALGRIND_COMPILE :=$(CFG_VALGRIND)
|
|
else
|
|
CFG_VALGRIND_COMPILE :=
|
|
endif
|
|
|
|
|
|
ifndef CFG_DISABLE_VALGRIND_RPASS
|
|
$(info cfg: enabling valgrind run-pass tests (CFG_ENABLE_VALGRIND_RPASS))
|
|
$(info cfg: valgrind-rpass command set to $(CFG_VALGRIND))
|
|
CFG_VALGRIND_RPASS :=$(CFG_VALGRIND)
|
|
else
|
|
$(info cfg: disabling valgrind run-pass tests)
|
|
CFG_VALGRIND_RPASS :=
|
|
endif
|
|
|
|
|
|
ifdef CFG_ENABLE_VALGRIND
|
|
$(info cfg: enabling valgrind (CFG_ENABLE_VALGRIND))
|
|
else
|
|
CFG_VALGRIND :=
|
|
endif
|
|
|
|
######################################################################
|
|
# Target-and-rule "utility variables"
|
|
######################################################################
|
|
|
|
define DEF_FOR_TARGET
|
|
X_$(1) := $(CFG_EXE_SUFFIX_$(1))
|
|
ifndef CFG_LLVM_TARGET_$(1)
|
|
CFG_LLVM_TARGET_$(1) := $(1)
|
|
endif
|
|
endef
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call DEF_FOR_TARGET,$(target))))
|
|
|
|
# "Source" files we generate in builddir along the way.
|
|
GENERATED :=
|
|
|
|
# Delete the built-in rules.
|
|
.SUFFIXES:
|
|
%:: %,v
|
|
%:: RCS/%,v
|
|
%:: RCS/%
|
|
%:: s.%
|
|
%:: SCCS/s.%
|
|
|
|
|
|
######################################################################
|
|
# Cleaning out old crates
|
|
######################################################################
|
|
|
|
# $(1) is the path for directory to match against
|
|
# $(2) is the glob to use in the match
|
|
#
|
|
# Note that a common bug is to accidentally construct the glob denoted
|
|
# by $(2) with a space character prefix, which invalidates the
|
|
# construction $(1)$(2).
|
|
define CHECK_FOR_OLD_GLOB_MATCHES
|
|
$(Q)MATCHES="$(wildcard $(1))"; if [ -n "$$MATCHES" ] ; then echo "warning: there are previous" \'$(notdir $(2))\' "libraries:" $$MATCHES; fi
|
|
endef
|
|
|
|
# Same interface as above, but deletes rather than just listing the files.
|
|
ifdef VERBOSE
|
|
define REMOVE_ALL_OLD_GLOB_MATCHES
|
|
$(Q)MATCHES="$(wildcard $(1))"; if [ -n "$$MATCHES" ] ; then echo "warning: removing previous" \'$(notdir $(1))\' "libraries:" $$MATCHES; rm $$MATCHES ; fi
|
|
endef
|
|
else
|
|
define REMOVE_ALL_OLD_GLOB_MATCHES
|
|
$(Q)MATCHES="$(wildcard $(1))"; if [ -n "$$MATCHES" ] ; then rm $$MATCHES ; fi
|
|
endef
|
|
endif
|
|
|
|
# We use a different strategy for LIST_ALL_OLD_GLOB_MATCHES_EXCEPT
|
|
# than in the macros above because it needs the result of running the
|
|
# `ls` command after other rules in the command list have run; the
|
|
# macro-expander for $(wildcard ...) would deliver its results too
|
|
# soon. (This is in contrast to the macros above, which are meant to
|
|
# be run at the outset of a command list in a rule.)
|
|
ifdef VERBOSE
|
|
define LIST_ALL_OLD_GLOB_MATCHES
|
|
@echo "info: now are following matches for" '$(notdir $(1))' "libraries:"
|
|
@( ls $(1) 2>/dev/null || true )
|
|
endef
|
|
else
|
|
define LIST_ALL_OLD_GLOB_MATCHES
|
|
endef
|
|
endif
|
|
|
|
######################################################################
|
|
# LLVM macros
|
|
######################################################################
|
|
|
|
# FIXME: x86-ism
|
|
LLVM_COMPONENTS=x86 arm aarch64 mips powerpc ipo bitreader bitwriter linker asmparser mcjit \
|
|
interpreter instrumentation
|
|
|
|
# Only build these LLVM tools
|
|
LLVM_TOOLS=bugpoint llc llvm-ar llvm-as llvm-dis llvm-mc opt llvm-extract
|
|
|
|
define DEF_LLVM_VARS
|
|
# The configure script defines these variables with the target triples
|
|
# separated by Z. This defines new ones with the expected format.
|
|
ifeq ($$(CFG_LLVM_ROOT),)
|
|
CFG_LLVM_BUILD_DIR_$(1):=$$(CFG_LLVM_BUILD_DIR_$(subst -,_,$(1)))
|
|
CFG_LLVM_INST_DIR_$(1):=$$(CFG_LLVM_INST_DIR_$(subst -,_,$(1)))
|
|
else
|
|
CFG_LLVM_INST_DIR_$(1):=$$(CFG_LLVM_ROOT)
|
|
endif
|
|
|
|
# Any rules that depend on LLVM should depend on LLVM_CONFIG
|
|
LLVM_CONFIG_$(1):=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-config$$(X_$(1))
|
|
LLVM_MC_$(1):=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-mc$$(X_$(1))
|
|
LLVM_AR_$(1):=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-ar$$(X_$(1))
|
|
LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
|
|
LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir)
|
|
LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir)
|
|
LLVM_LIBDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libdir)
|
|
LLVM_LIBDIR_RUSTFLAGS_$(1)=-L "$$(LLVM_LIBDIR_$(1))"
|
|
LLVM_LIBS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libs $$(LLVM_COMPONENTS))
|
|
LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags)
|
|
ifeq ($$(findstring freebsd,$(1)),freebsd)
|
|
# On FreeBSD, it may search wrong headers (that are for pre-installed LLVM),
|
|
# so we replace -I with -iquote to ensure that it searches bundled LLVM first.
|
|
LLVM_CXXFLAGS_$(1)=$$(subst -I, -iquote , $$(shell "$$(LLVM_CONFIG_$(1))" --cxxflags))
|
|
else
|
|
LLVM_CXXFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --cxxflags)
|
|
endif
|
|
LLVM_HOST_TRIPLE_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --host-target)
|
|
|
|
LLVM_AS_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-as$$(X_$(1))
|
|
LLC_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llc$$(X_$(1))
|
|
|
|
endef
|
|
|
|
$(foreach host,$(CFG_HOST), \
|
|
$(eval $(call DEF_LLVM_VARS,$(host))))
|
|
|
|
######################################################################
|
|
# 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
|
|
ifdef CFG_VER_DATE
|
|
export CFG_VER_DATE
|
|
endif
|
|
ifdef CFG_VER_HASH
|
|
export CFG_VER_HASH
|
|
endif
|
|
export CFG_BUILD_DATE
|
|
export CFG_VERSION
|
|
export CFG_VERSION_WIN
|
|
export CFG_RELEASE
|
|
export CFG_PACKAGE_NAME
|
|
export CFG_BUILD
|
|
export CFG_RELEASE_CHANNEL
|
|
export CFG_LLVM_ROOT
|
|
export CFG_PREFIX
|
|
export CFG_LIBDIR
|
|
export CFG_LIBDIR_RELATIVE
|
|
export CFG_DISABLE_INJECT_STD_VERSION
|
|
ifdef CFG_DISABLE_UNSTABLE_FEATURES
|
|
CFG_INFO := $(info cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATURES))
|
|
# Turn on feature-staging
|
|
export CFG_DISABLE_UNSTABLE_FEATURES
|
|
# Subvert unstable feature lints to do the self-build
|
|
export RUSTC_BOOTSTRAP_KEY:=$(CFG_BOOTSTRAP_KEY)
|
|
endif
|
|
export CFG_BOOTSTRAP_KEY
|
|
|
|
######################################################################
|
|
# Per-stage targets and runner
|
|
######################################################################
|
|
|
|
# Valid setting-strings are 'all', 'none', 'gdb', 'lldb'
|
|
# This 'function' will determine which debugger scripts to copy based on a
|
|
# target triple. See debuggers.mk for more information.
|
|
TRIPLE_TO_DEBUGGER_SCRIPT_SETTING=\
|
|
$(if $(findstring windows,$(1)),none,$(if $(findstring darwin,$(1)),lldb,gdb))
|
|
|
|
STAGES = 0 1 2 3
|
|
|
|
define SREQ
|
|
# $(1) is the stage number
|
|
# $(2) is the target triple
|
|
# $(3) is the host triple
|
|
|
|
# Destinations of artifacts for the host compiler
|
|
HROOT$(1)_H_$(3) = $(3)/stage$(1)
|
|
HBIN$(1)_H_$(3) = $$(HROOT$(1)_H_$(3))/bin
|
|
ifeq ($$(CFG_WINDOWSY_$(3)),1)
|
|
HLIB$(1)_H_$(3) = $$(HROOT$(1)_H_$(3))/$$(CFG_LIBDIR_RELATIVE)
|
|
else
|
|
ifeq ($(1),0)
|
|
HLIB$(1)_H_$(3) = $$(HROOT$(1)_H_$(3))/lib
|
|
else
|
|
HLIB$(1)_H_$(3) = $$(HROOT$(1)_H_$(3))/$$(CFG_LIBDIR_RELATIVE)
|
|
endif
|
|
endif
|
|
|
|
# Destinations of artifacts for target architectures
|
|
TROOT$(1)_T_$(2)_H_$(3) = $$(HLIB$(1)_H_$(3))/rustlib/$(2)
|
|
TBIN$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/bin
|
|
TLIB$(1)_T_$(2)_H_$(3) = $$(TROOT$(1)_T_$(2)_H_$(3))/lib
|
|
|
|
# Preqrequisites for using the stageN compiler
|
|
ifeq ($(1),0)
|
|
HSREQ$(1)_H_$(3) = $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3))
|
|
else
|
|
HSREQ$(1)_H_$(3) = \
|
|
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
|
$$(MKFILE_DEPS) \
|
|
tmp/install-debugger-scripts$(1)_H_$(3)-$$(call TRIPLE_TO_DEBUGGER_SCRIPT_SETTING,$(3)).done
|
|
endif
|
|
|
|
# Prerequisites for using the stageN compiler to build target artifacts
|
|
TSREQ$(1)_T_$(2)_H_$(3) = \
|
|
$$(HSREQ$(1)_H_$(3)) \
|
|
$$(foreach obj,$$(INSTALLED_OBJECTS_$(2)),\
|
|
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
|
|
|
|
# Prerequisites for a working stageN compiler and libraries, for a specific
|
|
# target
|
|
SREQ$(1)_T_$(2)_H_$(3) = \
|
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
|
$$(foreach dep,$$(TARGET_CRATES), \
|
|
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
|
|
tmp/install-debugger-scripts$(1)_T_$(2)_H_$(3)-$$(call TRIPLE_TO_DEBUGGER_SCRIPT_SETTING,$(2)).done
|
|
|
|
# Prerequisites for a working stageN compiler and complete set of target
|
|
# libraries
|
|
CSREQ$(1)_T_$(2)_H_$(3) = \
|
|
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
|
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
|
$$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep))
|
|
|
|
ifeq ($(1),0)
|
|
# Don't run the stage0 compiler under valgrind - that ship has sailed
|
|
CFG_VALGRIND_COMPILE$(1) =
|
|
else
|
|
CFG_VALGRIND_COMPILE$(1) = $$(CFG_VALGRIND_COMPILE)
|
|
endif
|
|
|
|
# Add RUSTFLAGS_STAGEN values to the build command
|
|
EXTRAFLAGS_STAGE$(1) = $$(RUSTFLAGS_STAGE$(1))
|
|
|
|
CFGFLAG$(1)_T_$(2)_H_$(3) = stage$(1)
|
|
|
|
endef
|
|
|
|
# Same macro/variables as above, but defined in a separate loop so it can use
|
|
# all the variables above for all archs. The RPATH_VAR setup sometimes needs to
|
|
# reach across triples to get things in order.
|
|
#
|
|
# Defines (with the standard $(1)_T_$(2)_H_$(3) suffix):
|
|
# * `LD_LIBRARY_PATH_ENV_NAME`: the name for the key to use in the OS
|
|
# environment to access or extend the lookup path for dynamic
|
|
# libraries. Note on Windows, that key is `$PATH`, and thus not
|
|
# only conflates programs with dynamic libraries, but also often
|
|
# contains spaces which confuse make.
|
|
# * `LD_LIBRARY_PATH_ENV_HOSTDIR`: the entry to add to lookup path for the host
|
|
# * `LD_LIBRARY_PATH_ENV_TARGETDIR`: the entry to add to lookup path for target
|
|
#
|
|
# Below that, HOST_RPATH_VAR and TARGET_RPATH_VAR are defined in terms of the
|
|
# above settings.
|
|
#
|
|
define SREQ_CMDS
|
|
|
|
ifeq ($$(OSTYPE_$(3)),apple-darwin)
|
|
LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := DYLD_LIBRARY_PATH
|
|
else
|
|
ifeq ($$(CFG_WINDOWSY_$(3)),1)
|
|
LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := PATH
|
|
else
|
|
LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3) := LD_LIBRARY_PATH
|
|
endif
|
|
endif
|
|
|
|
LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3) := \
|
|
$$(CURDIR)/$$(HLIB$(1)_H_$(3))
|
|
LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3) := \
|
|
$$(CURDIR)/$$(TLIB1_T_$(2)_H_$(CFG_BUILD))
|
|
|
|
HOST_RPATH_VAR$(1)_T_$(2)_H_$(3) := \
|
|
$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))=$$(LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3)):$$$$$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))
|
|
TARGET_RPATH_VAR$(1)_T_$(2)_H_$(3) := \
|
|
$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))=$$(LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3)):$$$$$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))
|
|
|
|
RPATH_VAR$(1)_T_$(2)_H_$(3) := $$(HOST_RPATH_VAR$(1)_T_$(2)_H_$(3))
|
|
|
|
# Pass --cfg stage0 only for the build->host part of stage0;
|
|
# if you're building a cross config, the host->* parts are
|
|
# effectively stage1, since it uses the just-built stage0.
|
|
#
|
|
# This logic is similar to how the LD_LIBRARY_PATH variable must
|
|
# change be slightly different when doing cross compilations.
|
|
# The build doesn't copy over all target libraries into
|
|
# a new directory, so we need to point the library path at
|
|
# the build directory where all the target libraries came
|
|
# from (the stage0 build host). Otherwise the relative rpaths
|
|
# inside of the rustc binary won't get resolved correctly.
|
|
ifeq ($(1),0)
|
|
ifneq ($(strip $(CFG_BUILD)),$(strip $(3)))
|
|
CFGFLAG$(1)_T_$(2)_H_$(3) = stage1
|
|
|
|
RPATH_VAR$(1)_T_$(2)_H_$(3) := $$(TARGET_RPATH_VAR$(1)_T_$(2)_H_$(3))
|
|
endif
|
|
endif
|
|
|
|
STAGE$(1)_T_$(2)_H_$(3) := \
|
|
$$(Q)$$(RPATH_VAR$(1)_T_$(2)_H_$(3)) \
|
|
$$(call CFG_RUN_TARG_$(3),$(1), \
|
|
$$(CFG_VALGRIND_COMPILE$(1)) \
|
|
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
|
--cfg $$(CFGFLAG$(1)_T_$(2)_H_$(3)) \
|
|
$$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
|
|
$$(RUSTC_FLAGS_$(2))
|
|
|
|
PERF_STAGE$(1)_T_$(2)_H_$(3) := \
|
|
$$(Q)$$(call CFG_RUN_TARG_$(3),$(1), \
|
|
$$(CFG_PERF_TOOL) \
|
|
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
|
--cfg $$(CFGFLAG$(1)_T_$(2)_H_$(3)) \
|
|
$$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
|
|
$$(RUSTC_FLAGS_$(2))
|
|
|
|
endef
|
|
|
|
$(foreach build,$(CFG_HOST), \
|
|
$(eval $(foreach target,$(CFG_TARGET), \
|
|
$(eval $(foreach stage,$(STAGES), \
|
|
$(eval $(call SREQ,$(stage),$(target),$(build))))))))
|
|
|
|
$(foreach build,$(CFG_HOST), \
|
|
$(eval $(foreach target,$(CFG_TARGET), \
|
|
$(eval $(foreach stage,$(STAGES), \
|
|
$(eval $(call SREQ_CMDS,$(stage),$(target),$(build))))))))
|
|
|
|
######################################################################
|
|
# rustc-H-targets
|
|
#
|
|
# Builds a functional Rustc for the given host.
|
|
######################################################################
|
|
|
|
define DEF_RUSTC_STAGE_TARGET
|
|
# $(1) == architecture
|
|
# $(2) == stage
|
|
|
|
rustc-stage$(2)-H-$(1): \
|
|
$$(foreach target,$$(CFG_TARGET),$$(SREQ$(2)_T_$$(target)_H_$(1)))
|
|
|
|
endef
|
|
|
|
$(foreach host,$(CFG_HOST), \
|
|
$(eval $(foreach stage,1 2 3, \
|
|
$(eval $(call DEF_RUSTC_STAGE_TARGET,$(host),$(stage))))))
|
|
|
|
rustc-stage1: rustc-stage1-H-$(CFG_BUILD)
|
|
rustc-stage2: rustc-stage2-H-$(CFG_BUILD)
|
|
rustc-stage3: rustc-stage3-H-$(CFG_BUILD)
|
|
|
|
define DEF_RUSTC_TARGET
|
|
# $(1) == architecture
|
|
|
|
rustc-H-$(1): rustc-stage2-H-$(1)
|
|
endef
|
|
|
|
$(foreach host,$(CFG_TARGET), \
|
|
$(eval $(call DEF_RUSTC_TARGET,$(host))))
|
|
|
|
rustc-stage1: rustc-stage1-H-$(CFG_BUILD)
|
|
rustc-stage2: rustc-stage2-H-$(CFG_BUILD)
|
|
rustc-stage3: rustc-stage3-H-$(CFG_BUILD)
|
|
rustc: rustc-H-$(CFG_BUILD)
|
|
|
|
rustc-H-all: $(foreach host,$(CFG_HOST),rustc-H-$(host))
|
|
|
|
######################################################################
|
|
# Entrypoint rule
|
|
######################################################################
|
|
|
|
.DEFAULT_GOAL := all
|
|
|
|
define ALL_TARGET_N
|
|
ifneq ($$(findstring $(1),$$(CFG_HOST)),)
|
|
# This is a host
|
|
all-target-$(1)-host-$(2): $$(CSREQ2_T_$(1)_H_$(2))
|
|
else
|
|
# This is a target only
|
|
all-target-$(1)-host-$(2): $$(SREQ2_T_$(1)_H_$(2))
|
|
endif
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(foreach host,$(CFG_HOST), \
|
|
$(eval $(call ALL_TARGET_N,$(target),$(host)))))
|
|
|
|
ALL_TARGET_RULES = $(foreach target,$(CFG_TARGET), \
|
|
$(foreach host,$(CFG_HOST), \
|
|
all-target-$(target)-host-$(host)))
|
|
|
|
all: $(ALL_TARGET_RULES) $(GENERATED) docs
|
|
|
|
######################################################################
|
|
# Build system documentation
|
|
######################################################################
|
|
|
|
# $(1) is the name of the doc <section> in Makefile.in
|
|
# pick everything between tags | remove first line | remove last line
|
|
# | remove extra (?) line | strip leading `#` from lines
|
|
SHOW_DOCS = $(Q)awk '/<$(1)>/,/<\/$(1)>/' $(S)/Makefile.in | sed '1d' | sed '$$d' | sed 's/^\# \?//'
|
|
|
|
help:
|
|
$(call SHOW_DOCS,help)
|
|
|
|
tips:
|
|
$(call SHOW_DOCS,tips)
|
|
|
|
nitty-gritty:
|
|
$(call SHOW_DOCS,nitty-gritty)
|