e648c96c5f
Rust's current compilation model makes it impossible on Windows to generate one object file with a complete and final set of dllexport annotations. This is because when an object is generated the compiler doesn't actually know if it will later be included in a dynamic library or not. The compiler works around this today by flagging *everything* as dllexport, but this has the drawback of exposing too much. Thankfully there are alternate methods of specifying the exported surface area of a dll on Windows, one of which is passing a `*.def` file to the linker which lists all public symbols of the dynamic library. This commit removes all locations that add `dllexport` to LLVM variables and instead dynamically generates a `*.def` file which is passed to the linker. This file will include all the public symbols of the current object file as well as all upstream libraries, and the crucial aspect is that it's only used when generating a dynamic library. When generating an executable this file isn't generated, so all the symbols aren't exported from an executable. To ensure that statically included native libraries are reexported correctly, the previously added support for the `#[linked_from]` attribute is used to determine the set of FFI symbols that are exported from a dynamic library, and this is required to get the compiler to link correctly.
298 lines
9.8 KiB
Makefile
298 lines
9.8 KiB
Makefile
# Copyright 2012-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.
|
|
|
|
|
|
# Create variables HOST_<triple> containing the host part
|
|
# of each target triple. For example, the triple i686-darwin-macos
|
|
# would create a variable HOST_i686-darwin-macos with the value
|
|
# i386.
|
|
define DEF_HOST_VAR
|
|
HOST_$(1) = $(subst i686,i386,$(word 1,$(subst -, ,$(1))))
|
|
endef
|
|
$(foreach t,$(CFG_TARGET),$(eval $(call DEF_HOST_VAR,$(t))))
|
|
$(foreach t,$(CFG_TARGET),$(info cfg: host for $(t) is $(HOST_$(t))))
|
|
|
|
# Ditto for OSTYPE
|
|
define DEF_OSTYPE_VAR
|
|
OSTYPE_$(1) = $(subst $(firstword $(subst -, ,$(1)))-,,$(1))
|
|
endef
|
|
$(foreach t,$(CFG_TARGET),$(eval $(call DEF_OSTYPE_VAR,$(t))))
|
|
$(foreach t,$(CFG_TARGET),$(info cfg: os for $(t) is $(OSTYPE_$(t))))
|
|
|
|
# On Darwin, we need to run dsymutil so the debugging information ends
|
|
# up in the right place. On other platforms, it automatically gets
|
|
# embedded into the executable, so use a no-op command.
|
|
CFG_DSYMUTIL := true
|
|
|
|
# Hack: not sure how to test if a file exists in make other than this
|
|
OS_SUPP = $(patsubst %,--suppressions=%, \
|
|
$(wildcard $(CFG_SRC_DIR)src/etc/$(CFG_OSTYPE).supp*))
|
|
|
|
ifdef CFG_DISABLE_OPTIMIZE_CXX
|
|
$(info cfg: disabling C++ optimization (CFG_DISABLE_OPTIMIZE_CXX))
|
|
CFG_GCCISH_CFLAGS += -O0
|
|
else
|
|
CFG_GCCISH_CFLAGS += -O2
|
|
endif
|
|
|
|
# The soname thing is for supporting a statically linked jemalloc.
|
|
# see https://blog.mozilla.org/jseward/2012/06/05/valgrind-now-supports-jemalloc-builds-directly/
|
|
ifdef CFG_VALGRIND
|
|
CFG_VALGRIND += --error-exitcode=100 \
|
|
--fair-sched=try \
|
|
--quiet \
|
|
--soname-synonyms=somalloc=NONE \
|
|
--suppressions=$(CFG_SRC_DIR)src/etc/x86.supp \
|
|
$(OS_SUPP)
|
|
ifdef CFG_ENABLE_HELGRIND
|
|
CFG_VALGRIND += --tool=helgrind
|
|
else
|
|
CFG_VALGRIND += --tool=memcheck \
|
|
--leak-check=full
|
|
endif
|
|
endif
|
|
|
|
# If we actually want to run Valgrind on a given platform, set this variable
|
|
define DEF_GOOD_VALGRIND
|
|
ifeq ($(OSTYPE_$(1)),unknown-linux-gnu)
|
|
GOOD_VALGRIND_$(1) = 1
|
|
endif
|
|
ifneq (,$(filter $(OSTYPE_$(1)),darwin freebsd))
|
|
ifeq (HOST_$(1),x86_64)
|
|
GOOD_VALGRIND_$(1) = 1
|
|
endif
|
|
endif
|
|
endef
|
|
$(foreach t,$(CFG_TARGET),$(eval $(call DEF_GOOD_VALGRIND,$(t))))
|
|
$(foreach t,$(CFG_TARGET),$(info cfg: good valgrind for $(t) is $(GOOD_VALGRIND_$(t))))
|
|
|
|
ifneq ($(findstring linux,$(CFG_OSTYPE)),)
|
|
ifdef CFG_PERF
|
|
ifneq ($(CFG_PERF_WITH_LOGFD),)
|
|
CFG_PERF_TOOL := $(CFG_PERF) stat -r 3 --log-fd 2
|
|
else
|
|
CFG_PERF_TOOL := $(CFG_PERF) stat -r 3
|
|
endif
|
|
else
|
|
ifdef CFG_VALGRIND
|
|
CFG_PERF_TOOL := \
|
|
$(CFG_VALGRIND) --tool=cachegrind --cache-sim=yes --branch-sim=yes
|
|
else
|
|
CFG_PERF_TOOL := /usr/bin/time --verbose
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
AR := ar
|
|
|
|
define SET_FROM_CFG
|
|
ifdef CFG_$(1)
|
|
ifeq ($(origin $(1)),undefined)
|
|
$$(info cfg: using $(1)=$(CFG_$(1)) (CFG_$(1)))
|
|
$(1)=$(CFG_$(1))
|
|
endif
|
|
ifeq ($(origin $(1)),default)
|
|
$$(info cfg: using $(1)=$(CFG_$(1)) (CFG_$(1)))
|
|
$(1)=$(CFG_$(1))
|
|
endif
|
|
endif
|
|
endef
|
|
|
|
$(foreach cvar,CC CXX CPP CFLAGS CXXFLAGS CPPFLAGS, \
|
|
$(eval $(call SET_FROM_CFG,$(cvar))))
|
|
|
|
CFG_RLIB_GLOB=lib$(1)-*.rlib
|
|
|
|
include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk)
|
|
|
|
define ADD_INSTALLED_OBJECTS
|
|
INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call ADD_INSTALLED_OBJECTS,$(target))))
|
|
|
|
define DEFINE_LINKER
|
|
ifndef LINK_$(1)
|
|
LINK_$(1) := $$(CC_$(1))
|
|
endif
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call DEFINE_LINKER,$(target))))
|
|
|
|
# The -Qunused-arguments sidesteps spurious warnings from clang
|
|
define FILTER_FLAGS
|
|
ifeq ($$(CFG_USING_CLANG),1)
|
|
ifneq ($(findstring clang,$$(shell $(CC_$(1)) -v)),)
|
|
CFG_GCCISH_CFLAGS_$(1) += -Qunused-arguments
|
|
CFG_GCCISH_CXXFLAGS_$(1) += -Qunused-arguments
|
|
endif
|
|
endif
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call FILTER_FLAGS,$(target))))
|
|
|
|
# Configure various macros to pass gcc or cl.exe style arguments
|
|
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)
|
|
else
|
|
CFG_CC_OUTPUT_$(1)=-o $$(1)
|
|
CFG_CREATE_ARCHIVE_$(1)=$$(AR_$(1)) crus $$(1)
|
|
endif
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call CC_MACROS,$(target))))
|
|
|
|
|
|
ifeq ($(CFG_CCACHE_CPP2),1)
|
|
CCACHE_CPP2=1
|
|
export CCACHE_CPP
|
|
endif
|
|
|
|
ifdef CFG_CCACHE_BASEDIR
|
|
CCACHE_BASEDIR=$(CFG_CCACHE_BASEDIR)
|
|
export CCACHE_BASEDIR
|
|
endif
|
|
|
|
FIND_COMPILER = $(word 1,$(1:ccache=))
|
|
|
|
define CFG_MAKE_TOOLCHAIN
|
|
# Prepend the tools with their prefix if cross compiling
|
|
ifneq ($(CFG_BUILD),$(1))
|
|
ifneq ($$(findstring msvc,$(1)),msvc)
|
|
CC_$(1)=$(CROSS_PREFIX_$(1))$(CC_$(1))
|
|
CXX_$(1)=$(CROSS_PREFIX_$(1))$(CXX_$(1))
|
|
CPP_$(1)=$(CROSS_PREFIX_$(1))$(CPP_$(1))
|
|
AR_$(1)=$(CROSS_PREFIX_$(1))$(AR_$(1))
|
|
LINK_$(1)=$(CROSS_PREFIX_$(1))$(LINK_$(1))
|
|
RUSTC_CROSS_FLAGS_$(1)=-C linker=$$(call FIND_COMPILER,$$(LINK_$(1))) \
|
|
-C ar=$$(call FIND_COMPILER,$$(AR_$(1))) $(RUSTC_CROSS_FLAGS_$(1))
|
|
|
|
RUSTC_FLAGS_$(1)=$$(RUSTC_CROSS_FLAGS_$(1)) $(RUSTC_FLAGS_$(1))
|
|
endif
|
|
endif
|
|
|
|
CFG_COMPILE_C_$(1) = $$(CC_$(1)) \
|
|
$$(CFG_GCCISH_CFLAGS) \
|
|
$$(CFG_GCCISH_CFLAGS_$(1)) \
|
|
-c $$(call CFG_CC_OUTPUT_$(1),$$(1)) $$(2)
|
|
CFG_LINK_C_$(1) = $$(CC_$(1)) \
|
|
$$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
|
|
$$(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_GCCISH_CFLAGS) \
|
|
$$(CFG_GCCISH_CXXFLAGS) \
|
|
$$(CFG_GCCISH_CFLAGS_$(1)) \
|
|
$$(CFG_GCCISH_CXXFLAGS_$(1)) \
|
|
-c $$(call CFG_CC_OUTPUT_$(1),$$(1)) $$(2)
|
|
CFG_LINK_CXX_$(1) = $$(CXX_$(1)) \
|
|
$$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
|
|
$$(CFG_GCCISH_LINK_FLAGS_$(1)) \
|
|
$$(CFG_GCCISH_DEF_FLAG_$(1))$$(3) $$(2) \
|
|
$$(call CFG_INSTALL_NAME_$(1),$$(4))
|
|
|
|
ifeq ($$(findstring $(HOST_$(1)),arm aarch64 mips mipsel powerpc),)
|
|
|
|
# On Bitrig, we need the relocation model to be PIC for everything
|
|
ifeq (,$(filter $(OSTYPE_$(1)),bitrig))
|
|
LLVM_MC_RELOCATION_MODEL="pic"
|
|
else
|
|
LLVM_MC_RELOCATION_MODEL="default"
|
|
endif
|
|
|
|
# We're using llvm-mc as our assembler because it supports
|
|
# .cfi pseudo-ops on mac
|
|
CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(2) | \
|
|
$$(LLVM_MC_$$(CFG_BUILD)) \
|
|
-assemble \
|
|
-relocation-model=$$(LLVM_MC_RELOCATION_MODEL) \
|
|
-filetype=obj \
|
|
-triple=$(1) \
|
|
-o=$$(1)
|
|
else
|
|
|
|
# For the ARM, AARCH64, MIPS and POWER crosses, use the toolchain assembler
|
|
# FIXME: We should be able to use the LLVM assembler
|
|
CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
|
|
$$(2) -c -o $$(1)
|
|
|
|
endif
|
|
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call CFG_MAKE_TOOLCHAIN,$(target))))
|
|
|
|
# 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
|
|
# dependency here.
|
|
define ADD_LLVM_AR_TO_MSVC_DEPS
|
|
ifeq ($$(findstring msvc,$(1)),msvc)
|
|
NATIVE_TOOL_DEPS_core_T_$(1) += llvm-ar.exe
|
|
INSTALLED_BINS_$(1) += llvm-ar.exe
|
|
endif
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call ADD_LLVM_AR_TO_MSVC_DEPS,$(target))))
|
|
|
|
# When working with MSVC on windows, each DLL needs to explicitly declare its
|
|
# interface to the outside world through some means. The options for doing so
|
|
# include:
|
|
#
|
|
# 1. A custom attribute on each function itself
|
|
# 2. A linker argument saying what to export
|
|
# 3. A file which lists all symbols that need to be exported
|
|
#
|
|
# The Rust compiler takes care (1) for us for all Rust code by annotating all
|
|
# public-facing functions with dllexport, but we have a few native dependencies
|
|
# which need to cross the DLL boundary. The most important of these dependencies
|
|
# is LLVM which is linked into `rustc_llvm.dll` but primarily used from
|
|
# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be
|
|
# exposed from `rustc_llvm.dll` to be forwarded over the boundary.
|
|
#
|
|
# Unfortunately, at this time, LLVM does not handle this sort of exportation on
|
|
# Windows for us, so we're forced to do it ourselves if we want it (which seems
|
|
# like the path of least resistance right now). To do this we generate a `.DEF`
|
|
# file [1] which we then custom-pass to the linker when building the rustc_llvm
|
|
# crate. This DEF file list all symbols that are exported from
|
|
# `src/librustc_llvm/lib.rs` and is generated by a small python script.
|
|
#
|
|
# Fun times!
|
|
#
|
|
# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
|
|
#
|
|
# FIXME(stage0): remove this macro and the usage below (and the commments above)
|
|
# when a new snapshot is available. Also remove the
|
|
# RUSTFLAGS$(1)_.._T_ variable in mk/target.mk along with
|
|
# CUSTOM_DEPS (as they were only added for this)
|
|
define ADD_RUSTC_LLVM_DEF_TO_MSVC
|
|
ifeq ($$(findstring msvc,$(1)),msvc)
|
|
RUSTFLAGS0_rustc_llvm_T_$(1) += -C link-args="-DEF:$(1)/rt/rustc_llvm.def"
|
|
CUSTOM_DEPS0_rustc_llvm_T_$(1) += $(1)/rt/rustc_llvm.def
|
|
|
|
$(1)/rt/rustc_llvm.def: $$(S)src/etc/mklldef.py $$(S)src/librustc_llvm/lib.rs
|
|
$$(CFG_PYTHON) $$^ $$@ rustc_llvm-$$(CFG_FILENAME_EXTRA)
|
|
endif
|
|
endef
|
|
|
|
$(foreach target,$(CFG_TARGET), \
|
|
$(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target))))
|
|
|