From 30ff17f809869dec37d7b501fb532dc88fd47832 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 31 Mar 2014 14:43:19 -0700 Subject: [PATCH 1/7] Upgrade LLVM This comes with a number of fixes to be compatible with upstream LLVM: * Previously all monomorphizations of "mem::size_of()" would receive the same symbol. In the past LLVM would silently rename duplicated symbols, but it appears to now be dropping the duplicate symbols and functions now. The symbol names of monomorphized functions are now no longer solely based on the type of the function, but rather the type and the unique hash for the monomorphization. * Split stacks are no longer a global feature controlled by a flag in LLVM. Instead, they are opt-in on a per-function basis through a function attribute. The rust #[no_split_stack] attribute will disable this, otherwise all functions have #[split_stack] attached to them. * The compare and swap instruction now takes two atomic orderings, one for the successful case and one for the failure case. LLVM internally has an implementation of calculating the appropriate failure ordering given a particular success ordering (previously only a success ordering was specified), and I copied that into the intrinsic translation so the failure ordering isn't supplied on a source level for now. * Minor tweaks to LLVM's API in terms of debuginfo, naming, c++11 conventions, etc. --- configure | 4 -- src/librustc/lib/llvm.rs | 6 ++- src/librustc/middle/trans/base.rs | 8 ++-- src/librustc/middle/trans/build.rs | 5 ++- src/librustc/middle/trans/builder.rs | 6 ++- src/librustc/middle/trans/debuginfo.rs | 6 ++- src/librustc/middle/trans/intrinsic.rs | 15 ++++++- src/librustc/middle/trans/monomorphize.rs | 7 ++-- src/llvm | 2 +- src/rustllvm/PassWrapper.cpp | 6 +++ src/rustllvm/RustWrapper.cpp | 48 ++++++++++++++++++----- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/rustllvm/rustllvm.h | 9 +++-- 13 files changed, 89 insertions(+), 35 deletions(-) diff --git a/configure b/configure index 3fe0f376feb81..8099aada558e7 100755 --- a/configure +++ b/configure @@ -921,10 +921,6 @@ do LLVM_OPTS="$LLVM_OPTS --disable-terminfo" # Try to have LLVM pull in as few dependencies as possible (#9397) LLVM_OPTS="$LLVM_OPTS --disable-zlib --disable-libffi" - # LLVM says it needs a "new" clang/gcc, but we seem to get by ok with - # older versions on the bots. Get by for a little longer by asking it to - # not do version detection - LLVM_OPTS="$LLVM_OPTS --disable-compiler-version-checks" # Use win32 native thread/lock apis instead of pthread wrapper. # (llvm's configure tries to find pthread first, so we have to disable it explicitly.) diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 62c14e560e798..10e717e550d1f 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1261,7 +1261,8 @@ pub mod llvm { LHS: ValueRef, CMP: ValueRef, RHS: ValueRef, - Order: AtomicOrdering) + Order: AtomicOrdering, + FailureOrder: AtomicOrdering) -> ValueRef; pub fn LLVMBuildAtomicRMW(B: BuilderRef, Op: AtomicBinOp, @@ -1586,7 +1587,8 @@ pub mod llvm { Scope: DIDescriptor, File: DIFile, Line: c_uint, - Col: c_uint) + Col: c_uint, + Discriminator: c_uint) -> DILexicalBlock; pub fn LLVMDIBuilderCreateStaticVariable(Builder: DIBuilderRef, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 5f063bb31ca5a..95b928587c4d1 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -445,8 +445,8 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) { } // Add the no-split-stack attribute if requested - if contains_name(attrs, "no_split_stack") { - set_no_split_stack(llfn); + if !contains_name(attrs, "no_split_stack") { + set_split_stack(llfn); } if contains_name(attrs, "cold") { @@ -458,8 +458,8 @@ pub fn set_always_inline(f: ValueRef) { lib::llvm::SetFunctionAttribute(f, lib::llvm::AlwaysInlineAttribute) } -pub fn set_no_split_stack(f: ValueRef) { - "no-split-stack".with_c_str(|buf| { +pub fn set_split_stack(f: ValueRef) { + "split-stack".with_c_str(|buf| { unsafe { llvm::LLVMAddFunctionAttrString(f, buf); } }) } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index c60a1e219d009..65db4bdc9ab9d 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -814,8 +814,9 @@ pub fn Resume(cx: &Block, exn: ValueRef) -> ValueRef { // Atomic Operations pub fn AtomicCmpXchg(cx: &Block, dst: ValueRef, cmp: ValueRef, src: ValueRef, - order: AtomicOrdering) -> ValueRef { - B(cx).atomic_cmpxchg(dst, cmp, src, order) + order: AtomicOrdering, + failure_order: AtomicOrdering) -> ValueRef { + B(cx).atomic_cmpxchg(dst, cmp, src, order, failure_order) } pub fn AtomicRMW(cx: &Block, op: AtomicBinOp, dst: ValueRef, src: ValueRef, diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs index 7d99ac3e7f38f..a02453a2554f4 100644 --- a/src/librustc/middle/trans/builder.rs +++ b/src/librustc/middle/trans/builder.rs @@ -949,9 +949,11 @@ impl<'a> Builder<'a> { // Atomic Operations pub fn atomic_cmpxchg(&self, dst: ValueRef, cmp: ValueRef, src: ValueRef, - order: AtomicOrdering) -> ValueRef { + order: AtomicOrdering, + failure_order: AtomicOrdering) -> ValueRef { unsafe { - llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, order) + llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, + order, failure_order) } } pub fn atomic_rmw(&self, op: AtomicBinOp, diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 0514642c58390..fd6a465eabb22 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -2422,7 +2422,8 @@ fn populate_scope_map(cx: &CrateContext, parent_scope, file_metadata, loc.line as c_uint, - loc.col.to_uint() as c_uint) + loc.col.to_uint() as c_uint, + 0) }; scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, ident: None }); @@ -2539,7 +2540,8 @@ fn populate_scope_map(cx: &CrateContext, parent_scope, file_metadata, loc.line as c_uint, - loc.col.to_uint() as c_uint) + loc.col.to_uint() as c_uint, + 0) }; scope_stack.push(ScopeStackEntry { diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index 6f4b115ad86e5..9e5213e6a99a2 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -223,10 +223,23 @@ pub fn trans_intrinsic(ccx: &CrateContext, match *split.get(1) { "cxchg" => { + // See include/llvm/IR/Instructions.h for their implementation + // of this, I assume that it's good enough for us to use for + // now. + let strongest_failure_ordering = match order { + lib::llvm::NotAtomic | lib::llvm::Unordered => + ccx.sess().fatal("cmpxchg must be atomic"), + lib::llvm::Monotonic | lib::llvm::Release => + lib::llvm::Monotonic, + lib::llvm::Acquire | lib::llvm::AcquireRelease => + lib::llvm::Acquire, + lib::llvm::SequentiallyConsistent => + lib::llvm::SequentiallyConsistent, + }; let old = AtomicCmpXchg(bcx, get_param(decl, first_real_arg), get_param(decl, first_real_arg + 1u), get_param(decl, first_real_arg + 2u), - order); + order, strongest_failure_ordering); Ret(bcx, old); } "load" => { diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 6f2dbc182b04f..35ae9a26954db 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -use back::link::mangle_exported_name; +use back::link::exported_name; use driver::session; use lib::llvm::ValueRef; use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint}; @@ -27,6 +26,7 @@ use syntax::abi; use syntax::ast; use syntax::ast_map; use syntax::ast_util::local_def; +use std::hash::sip; pub fn monomorphic_fn(ccx: &CrateContext, fn_id: ast::DefId, @@ -178,7 +178,8 @@ pub fn monomorphic_fn(ccx: &CrateContext, } let s = ccx.tcx.map.with_path(fn_id.node, |path| { - mangle_exported_name(ccx, path, mono_ty, fn_id.node) + exported_name(path, format!("h{}", sip::hash(&(hash_id, mono_ty))), + ccx.link_meta.crateid.version_or_default()) }); debug!("monomorphize_fn mangled to {}", s); diff --git a/src/llvm b/src/llvm index 263c617d66005..4b4d0533b4f76 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 263c617d66005999afa27d00809c1568a26112ee +Subproject commit 4b4d0533b4f76cc3fbba31bd9e7ac02e0c738b1d diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 2be7c84ab0348..32bac73debfb9 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -81,7 +81,9 @@ LLVMRustCreateTargetMachine(const char *triple, TargetOptions Options; Options.NoFramePointerElim = NoFramePointerElim; +#if LLVM_VERSION_MINOR < 5 Options.EnableSegmentedStacks = EnableSegmentedStacks; +#endif Options.FloatABIType = FloatABI::Default; Options.UseSoftFloat = UseSoftFloat; if (UseSoftFloat) { @@ -111,7 +113,11 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, LLVMPassManagerRef PMR, LLVMModuleRef M) { PassManagerBase *PM = unwrap(PMR); +#if LLVM_VERSION_MINOR >= 5 + PM->add(new DataLayoutPass(unwrap(M))); +#else PM->add(new DataLayout(unwrap(M))); +#endif unwrap(TM)->addAnalysisPasses(*PM); } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5a00a8034e6bc..035a39669de8d 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -129,9 +129,14 @@ extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef target, LLVMValueRef old, LLVMValueRef source, - AtomicOrdering order) { + AtomicOrdering order, + AtomicOrdering failure_order) { return wrap(unwrap(B)->CreateAtomicCmpXchg(unwrap(target), unwrap(old), - unwrap(source), order)); + unwrap(source), order +#if LLVM_VERSION_MINOR >= 5 + , failure_order +#endif + )); } extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B, AtomicOrdering order) { return wrap(unwrap(B)->CreateFence(order)); @@ -289,10 +294,9 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateStructType( RunTimeLang, unwrapDI(VTableHolder) #if LLVM_VERSION_MINOR >= 5 - ,UniqueId)); -#else - )); + ,UniqueId #endif + )); } extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType( @@ -318,10 +322,15 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock( LLVMValueRef Scope, LLVMValueRef File, unsigned Line, - unsigned Col) { + unsigned Col, + unsigned Discriminator) { return wrap(Builder->createLexicalBlock( unwrapDI(Scope), - unwrapDI(File), Line, Col)); + unwrapDI(File), Line, Col +#if LLVM_VERSION_MINOR >= 5 + , Discriminator +#endif + )); } extern "C" LLVMValueRef LLVMDIBuilderCreateStaticVariable( @@ -477,15 +486,16 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateUnionType( unwrapDI(Elements), RunTimeLang #if LLVM_VERSION_MINOR >= 5 - ,UniqueId)); -#else - )); + ,UniqueId #endif + )); } +#if LLVM_VERSION_MINOR < 5 extern "C" void LLVMSetUnnamedAddr(LLVMValueRef Value, LLVMBool Unnamed) { unwrap(Value)->setUnnamedAddr(Unnamed); } +#endif extern "C" LLVMValueRef LLVMDIBuilderCreateTemplateTypeParameter( DIBuilderRef Builder, @@ -620,6 +630,23 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { } #endif +#if LLVM_VERSION_MINOR >= 5 +extern "C" void* +LLVMRustOpenArchive(char *path) { + std::unique_ptr buf; + error_code err = MemoryBuffer::getFile(path, buf); + if (err) { + LLVMRustError = err.message().c_str(); + return NULL; + } + Archive *ret = new Archive(buf.release(), err); + if (err) { + LLVMRustError = err.message().c_str(); + return NULL; + } + return ret; +} +#else extern "C" void* LLVMRustOpenArchive(char *path) { OwningPtr buf; @@ -635,6 +662,7 @@ LLVMRustOpenArchive(char *path) { } return ret; } +#endif extern "C" const char* LLVMRustArchiveReadSection(Archive *ar, char *name, size_t *size) { diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 3426e823b9f67..340a491527710 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2014-02-25 +2014-04-14 diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index f046587052a12..42c60e72baba7 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -12,7 +12,6 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/Linker.h" #include "llvm/PassManager.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" @@ -43,8 +42,6 @@ #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Vectorize.h" -#include "llvm/DebugInfo.h" -#include "llvm/DIBuilder.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" @@ -53,8 +50,14 @@ #if LLVM_VERSION_MINOR >= 5 #include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/Linker/Linker.h" #else #include "llvm/Assembly/PrintModulePass.h" +#include "llvm/DebugInfo.h" +#include "llvm/DIBuilder.h" +#include "llvm/Linker.h" #endif // Used by RustMCJITMemoryManager::getPointerToNamedFunction() From 32a81d1e161a8b4a498c88ddb79955775d18fbfd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Apr 2014 09:49:34 -0700 Subject: [PATCH 2/7] configure: Enable libc++ with LLVM with clang When clang is enabled, also pass through --enable-libcpp to LLVM's configure command line to help it pick up the most recent c++ runtime library. This also changes the mklldeps.py script to pick up on whether LLVM was linked against stdc++ or c++ based on the --cxxflags that llvm-config prints. In an ongoing attempt to update LLVM, the bots need to update their C compilers to something that supports c++11 (LLVM recently switched). The OSX bots are running Lion (10.7), which only supports up to gcc 4.2 and clang 3.2. Apparently the libstdc++ is too old (even on the most updated command line tools) for LLVM, but using libc++ instead appears to work just fine. --- configure | 2 ++ src/etc/mklldeps.py | 31 +++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 8099aada558e7..5b6c26daaa34b 100755 --- a/configure +++ b/configure @@ -938,6 +938,7 @@ do LLVM_CXX_64="ccache clang++ -Qunused-arguments" LLVM_CC_64="ccache clang -Qunused-arguments" + LLVM_OPTS="$LLVM_OPTS --enable-libcpp" ;; ("clang") LLVM_CXX_32="clang++ -m32 -Qunused-arguments" @@ -945,6 +946,7 @@ do LLVM_CXX_64="clang++ -Qunused-arguments" LLVM_CC_64="clang -Qunused-arguments" + LLVM_OPTS="$LLVM_OPTS --enable-libcpp" ;; ("ccache gcc") LLVM_CXX_32="ccache g++ -m32" diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 189d0269cd88e..8ad9ea2813bed 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -56,7 +56,7 @@ f.write("#[cfg(" + ', '.join(cfg) + ")]\n") # LLVM libs - args = [llconfig, '--libs'] + args = [llconfig, '--libs', '--system-libs'] args.extend(components) proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() @@ -65,9 +65,13 @@ print("failed to run llconfig: args = `{}`".format(args)) sys.exit(1) - for lib in out.strip().split(' '): - lib = lib[2:] # chop of the leading '-l' - f.write("#[link(name = \"" + lib + "\", kind = \"static\")]\n") + for lib in out.strip().replace("\n", ' ').split(' '): + lib = lib.strip()[2:] # chop of the leading '-l' + f.write("#[link(name = \"" + lib + "\"") + # LLVM libraries are all static libraries + if 'LLVM' in lib: + f.write(", kind = \"static\"") + f.write(")]\n") # LLVM ldflags args = [llconfig, '--ldflags'] @@ -82,8 +86,19 @@ if lib[:2] == "-l": f.write("#[link(name = \"" + lib[2:] + "\")]\n") - #extra - f.write("#[link(name = \"stdc++\")]\n") - if os == 'win32': - f.write("#[link(name = \"imagehlp\")]\n") + # C++ runtime library + args = [llconfig, '--cxxflags'] + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = proc.communicate() + + if err: + print("failed to run llconfig: args = `{}`".format(args)) + sys.exit(1) + + if 'stdlib=libc++' in out: + f.write("#[link(name = \"c++\")]\n") + else: + f.write("#[link(name = \"stdc++\")]\n") + + # Attach everything to an extern block f.write("extern {}\n") From 682c401045fbc24ecec8cab0e315293192825c69 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Apr 2014 10:27:16 -0700 Subject: [PATCH 3/7] configure: Enable clang for older OSX gcc versions OSX often has a more recent version of clang than it does for GCC. When an older version of gcc is detected on OSX, the --enable-clang flag is implicitly enabled. --- configure | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 5b6c26daaa34b..8d0116cb0ca7d 100755 --- a/configure +++ b/configure @@ -579,26 +579,32 @@ then CFG_ENABLE_CLANG=1 putvar CFG_ENABLE_CLANG else - # on OS X, with xcode 5 and newer, certain developers may have - # cc, gcc and g++ point to a mixture of clang and gcc - # if so, this will create very strange build errors - # this last stanza is to detect some such problems and save the future rust - # contributor some time solving that issue. - # this detection could be generalized to other OSes aside from OS X - # but the issue seems most likely to happen on OS X - - chk_cc () { - $1 --version 2> /dev/null | grep -q $2 - } - # check that gcc, cc and g++ all point to the same compiler. - # note that for xcode 5, g++ points to clang, not clang++ - if !((chk_cc gcc clang && chk_cc g++ clang) || - (chk_cc gcc gcc &&( chk_cc g++ g++ || chk g++ gcc))) then - err "the gcc and g++ in your path point to different compilers. -Check which versions are in your path with cc --version and g++ --version. -To resolve this problem, either fix your PATH or run configure with --enable-clang" - fi + if [ $("$CFG_GCC" --version 2>&1 | grep -c ' 4\.[0-6]') -ne 0 ]; then + step_msg "older GCC found, using clang instead" + CFG_ENABLE_CLANG=1 + putvar CFG_ENABLE_CLANG + else + # on OS X, with xcode 5 and newer, certain developers may have + # cc, gcc and g++ point to a mixture of clang and gcc + # if so, this will create very strange build errors + # this last stanza is to detect some such problems and save the future rust + # contributor some time solving that issue. + # this detection could be generalized to other OSes aside from OS X + # but the issue seems most likely to happen on OS X + + chk_cc () { + $1 --version 2> /dev/null | grep -q $2 + } + # check that gcc, cc and g++ all point to the same compiler. + # note that for xcode 5, g++ points to clang, not clang++ + if !((chk_cc gcc clang && chk_cc g++ clang) || + (chk_cc gcc gcc &&( chk_cc g++ g++ || chk g++ gcc))) then + err "the gcc and g++ in your path point to different compilers. + Check which versions are in your path with cc --version and g++ --version. + To resolve this problem, either fix your PATH or run configure with --enable-clang" + fi + fi fi fi From 36d5635273f7759b9aedce04bc8b111edb9c0742 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Apr 2014 12:30:52 -0700 Subject: [PATCH 4/7] etc: The --system-libs flag is LLVM 3.5+ Older version of LLVM did not have this flag, so we need to fall back to our previous library detection when using older versions of LLVM. --- src/etc/mklldeps.py | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 8ad9ea2813bed..364564168a5e8 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -31,11 +31,20 @@ // take a look at src/etc/mklldeps.py if you're interested """) +def run(args): + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = proc.communicate() + + if err: + print("failed to run llconfig: args = `{}`".format(args)) + print(err) + sys.exit(1) + return out + for llconfig in sys.argv[3:]: f.write("\n") - proc = subprocess.Popen([llconfig, '--host-target'], stdout = subprocess.PIPE) - out, err = proc.communicate() + out = run([llconfig, '--host-target']) arch, os = out.split('-', 1) arch = 'x86' if arch == 'i686' or arch == 'i386' else arch if 'darwin' in os: @@ -55,16 +64,15 @@ f.write("#[cfg(" + ', '.join(cfg) + ")]\n") + version = run([llconfig, '--version']).strip() + # LLVM libs - args = [llconfig, '--libs', '--system-libs'] + if version < '3.5': + args = [llconfig, '--libs'] + else: + args = [llconfig, '--libs', '--system-libs'] args.extend(components) - proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = proc.communicate() - - if err: - print("failed to run llconfig: args = `{}`".format(args)) - sys.exit(1) - + out = run(args) for lib in out.strip().replace("\n", ' ').split(' '): lib = lib.strip()[2:] # chop of the leading '-l' f.write("#[link(name = \"" + lib + "\"") @@ -73,28 +81,19 @@ f.write(", kind = \"static\"") f.write(")]\n") - # LLVM ldflags - args = [llconfig, '--ldflags'] - proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = proc.communicate() - - if err: - print("failed to run llconfig: args = `{}`".format(args)) - sys.exit(1) + # llvm-config before 3.5 didn't have a system-libs flag + if version < '3.5': + if os == 'win32': + f.write("#[link(name = \"imagehlp\")]") + # LLVM ldflags + out = run([llconfig, '--ldflags']) for lib in out.strip().split(' '): if lib[:2] == "-l": f.write("#[link(name = \"" + lib[2:] + "\")]\n") # C++ runtime library - args = [llconfig, '--cxxflags'] - proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = proc.communicate() - - if err: - print("failed to run llconfig: args = `{}`".format(args)) - sys.exit(1) - + out = run([llconfig, '--cxxflags']) if 'stdlib=libc++' in out: f.write("#[link(name = \"c++\")]\n") else: From acdee8b904178e13616cea8c31bcdb1f063ddef5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Apr 2014 10:45:04 -0700 Subject: [PATCH 5/7] llvm: Add an option to statically link libstdc++ The goal of the snapshot bots is to produce binaries which can run in as many locations as possible. Currently we build on Centos 6 for this reason, but with LLVM's update to C++11, this reduces the number of platforms that we could possibly run on. This adds a --enable-llvm-static-stdcpp option to the ./configure script for Rust which will enable building a librustc with a static dependence on libstdc++. This normally isn't necessary, but this option can be used on the snapshot builders in order to continue to make binaries which should be able to run in as many locations as possible. --- configure | 1 + mk/llvm.mk | 17 +++++++++++++---- mk/target.mk | 1 + src/etc/mklldeps.py | 13 ++++++++++--- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 8d0116cb0ca7d..983be4e8a0c0a 100755 --- a/configure +++ b/configure @@ -388,6 +388,7 @@ opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt pax-flags 0 "apply PaX flags to rustc binaries (required for GRSecurity/PaX-patched kernels)" opt inject-std-version 1 "inject the current compiler version of libstd into programs" +opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt rpath 1 "build rpaths into rustc itself" opt nightly 0 "build nightly packages" opt verify-install 1 "verify installed binaries work" diff --git a/mk/llvm.mk b/mk/llvm.mk index 13c4ae5e860f7..789ce2dabc25e 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -42,16 +42,25 @@ $$(LLVM_STAMP_$(1)): $(S)src/rustllvm/llvm-auto-clean-trigger @$$(call E, make: done cleaning llvm) touch $$@ +ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1) +LLVM_STDCPP_LOCATION_$(1) = $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ + -print-file-name=libstdc++.a) +else +LLVM_STDCPP_LOCATION_$(1) = +endif + endef $(foreach host,$(CFG_HOST), \ - $(eval LLVM_CONFIGS := $(LLVM_CONFIGS) $(LLVM_CONFIG_$(host)))) + $(eval $(call DEF_LLVM_RULES,$(host)))) $(foreach host,$(CFG_HOST), \ - $(eval $(call DEF_LLVM_RULES,$(host)))) + $(eval LLVM_CONFIGS := $(LLVM_CONFIGS) $(LLVM_CONFIG_$(host)))) $(S)src/librustc/lib/llvmdeps.rs: \ $(LLVM_CONFIGS) \ - $(S)src/etc/mklldeps.py + $(S)src/etc/mklldeps.py \ + $(MKFILE_DEPS) $(Q)$(CFG_PYTHON) $(S)src/etc/mklldeps.py \ - "$@" "$(LLVM_COMPONENTS)" $(LLVM_CONFIGS) + "$@" "$(LLVM_COMPONENTS)" "$(CFG_ENABLE_LLVM_STATIC_STDCPP)" \ + $(LLVM_CONFIGS) diff --git a/mk/target.mk b/mk/target.mk index 11c57ac070f39..448299965a853 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -83,6 +83,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ $$(WFLAGS_ST$(1)) \ -L "$$(RT_OUTPUT_DIR_$(2))" \ -L "$$(LLVM_LIBDIR_$(2))" \ + -L "$$(dir $$(LLVM_STDCPP_LOCATION_$(2)))" \ --out-dir $$(@D) $$< @touch $$@ $$(call LIST_ALL_OLD_GLOB_MATCHES,\ diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 364564168a5e8..f745f5d61cb9a 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -11,11 +11,14 @@ import os import sys import subprocess +import itertools +from os import path f = open(sys.argv[1], 'wb') components = sys.argv[2].split(' ') components = [i for i in components if i] # ignore extra whitespaces +enable_static = sys.argv[3] f.write("""// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -41,7 +44,7 @@ def run(args): sys.exit(1) return out -for llconfig in sys.argv[3:]: +for llconfig in sys.argv[4:]: f.write("\n") out = run([llconfig, '--host-target']) @@ -94,9 +97,13 @@ def run(args): # C++ runtime library out = run([llconfig, '--cxxflags']) - if 'stdlib=libc++' in out: - f.write("#[link(name = \"c++\")]\n") + if enable_static == '1': + assert('stdlib=libc++' not in out) + f.write("#[link(name = \"stdc++\", kind = \"static\")]\n") else: + if 'stdlib=libc++' in out: + f.write("#[link(name = \"c++\")]\n") + else: f.write("#[link(name = \"stdc++\")]\n") # Attach everything to an extern block From ad3de7fdb58cb2beb06780794006b4184807c75e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Apr 2014 16:31:45 -0700 Subject: [PATCH 6/7] rustc: Hint to the linker about static/shared libs If a linker finds both a static and a dynamic version of the same library, then the linker often chooses the dynamic version. This is surprising when a native library is specified as being "static" in rust source. This modifies the linker command line to obey the hints given in rust source files and instructing the linker to prefer a particular version of a found library. Unfortunately, this patch has no effect on osx because the linker supports no such hint, and it also has no effect on windows because the linker apparently just ignores it. For now this is predominately used to enable the previous patch of linking to libstdc++ statically, but more support would need to be added for this in the future if we wanted to officially support it. cc #12557 (doesn't close because it doesn't support OSX and windows) --- src/librustc/back/link.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 9ac99b267169e..8ef5677db2764 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -1298,9 +1298,22 @@ fn add_local_native_libraries(args: &mut Vec<~str>, sess: &Session) { args.push("-L" + path.as_str().unwrap().to_owned()); } + // Some platforms take hints about whether a library is static or dynamic. + // For those that support this, we ensure we pass the option if the library + // was flagged "static" (most defaults are dynamic) to ensure that if + // libfoo.a and libfoo.so both exist that the right one is chosen. + let takes_hints = sess.targ_cfg.os != abi::OsMacos; + for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() { match kind { cstore::NativeUnknown | cstore::NativeStatic => { + if takes_hints { + if kind == cstore::NativeStatic { + args.push("-Wl,-Bstatic".to_owned()); + } else { + args.push("-Wl,-Bdynamic".to_owned()); + } + } args.push("-l" + *l); } cstore::NativeFramework => { @@ -1309,6 +1322,9 @@ fn add_local_native_libraries(args: &mut Vec<~str>, sess: &Session) { } } } + if takes_hints { + args.push("-Wl,-Bdynamic".to_owned()); + } } // # Rust Crate linking From 426d701f8bbd22aa22fefb69d71eaa7dc8bbe170 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 18 Apr 2014 16:54:38 -0700 Subject: [PATCH 7/7] debuginfo: Clamp the maximum dwarf version to 3 This is a consequence of #13611 and our bots running a "fairly old" gdb which doesn't understand the newer versions of dwarf. --- src/librustc/middle/trans/debuginfo.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index fd6a465eabb22..d6dd0213128a5 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -279,6 +279,12 @@ pub fn finalize(cx: &CrateContext) { if cx.sess().targ_cfg.os == abi::OsMacos { "Dwarf Version".with_c_str( |s| llvm::LLVMRustAddModuleFlag(cx.llmod, s, 2)); + } else { + // FIXME(#13611) this is a kludge fix because the linux bots have + // gdb 7.4 which doesn't understand dwarf4, we should + // do something more graceful here. + "Dwarf Version".with_c_str( + |s| llvm::LLVMRustAddModuleFlag(cx.llmod, s, 3)); } // Prevent bitcode readers from deleting the debug info.