Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure LLVM is in the link path for rustc tools #70123

Merged
merged 4 commits into from
Mar 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{Duration, Instant};

use build_helper::t;
use build_helper::{output, t};

use crate::cache::{Cache, Interned, INTERNER};
use crate::check;
Expand All @@ -23,7 +23,7 @@ use crate::install;
use crate::native;
use crate::test;
use crate::tool;
use crate::util::{self, add_lib_path, exe, libdir};
use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir};
use crate::{Build, DocTests, GitRepo, Mode};

pub use crate::Compiler;
Expand Down Expand Up @@ -660,7 +660,7 @@ impl<'a> Builder<'a> {
return;
}

add_lib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command);
add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command);
}

/// Gets a path to the compiler specified.
Expand Down Expand Up @@ -698,6 +698,20 @@ impl<'a> Builder<'a> {
cmd
}

/// Return the path to `llvm-config` for the target, if it exists.
///
/// Note that this returns `None` if LLVM is disabled, or if we're in a
/// check build or dry-run, where there's no need to build all of LLVM.
fn llvm_config(&self, target: Interned<String>) -> Option<PathBuf> {
if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run {
let llvm_config = self.ensure(native::Llvm { target });
if llvm_config.is_file() {
return Some(llvm_config);
}
}
None
}

/// Prepares an invocation of `cargo` to be run.
///
/// This will create a `Command` that represents a pending execution of
Expand Down Expand Up @@ -1034,6 +1048,17 @@ impl<'a> Builder<'a> {
.env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler));
}

// Tools that use compiler libraries may inherit the `-lLLVM` link
// requirement, but the `-L` library path is not propagated across
// separate Cargo projects. We can add LLVM's library path to the
// platform-specific environment variable as a workaround.
if mode == Mode::ToolRustc {
if let Some(llvm_config) = self.llvm_config(target) {
let llvm_libdir = output(Command::new(&llvm_config).arg("--libdir"));
add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
}
}

if self.config.incremental {
cargo.env("CARGO_INCREMENTAL", "1");
} else {
Expand Down
38 changes: 0 additions & 38 deletions src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,44 +451,6 @@ impl Step for Rustc {
false,
);

// We used to build librustc_codegen_llvm as a separate step,
// which produced a dylib that the compiler would dlopen() at runtime.
// This meant that we only needed to make sure that libLLVM.so was
// installed by the time we went to run a tool using it - since
// librustc_codegen_llvm was effectively a standalone artifact,
// other crates were completely oblivious to its dependency
// on `libLLVM.so` during build time.
//
// However, librustc_codegen_llvm is now built as an ordinary
// crate during the same step as the rest of the compiler crates.
// This means that any crates depending on it will see the fact
// that it uses `libLLVM.so` as a native library, and will
// cause us to pass `-llibLLVM.so` to the linker when we link
// a binary.
//
// For `rustc` itself, this works out fine.
// During the `Assemble` step, we call `dist::maybe_install_llvm_dylib`
// to copy libLLVM.so into the `stage` directory. We then link
// the compiler binary, which will find `libLLVM.so` in the correct place.
//
// However, this is insufficient for tools that are build against stage0
// (e.g. stage1 rustdoc). Since `Assemble` for stage0 doesn't actually do anything,
// we won't have `libLLVM.so` in the stage0 sysroot. In the past, this wasn't
// a problem - we would copy the tool binary into its correct stage directory
// (e.g. stage1 for a stage1 rustdoc built against a stage0 compiler).
// Since libLLVM.so wasn't resolved until runtime, it was fine for it to
// not exist while we were building it.
//
// To ensure that we can still build stage1 tools against a stage0 compiler,
// we explicitly copy libLLVM.so into the stage0 sysroot when building
// the stage0 compiler. This ensures that tools built against stage0
// will see libLLVM.so at build time, making the linker happy.
if compiler.stage == 0 {
builder.info(&format!("Installing libLLVM.so to stage 0 ({})", compiler.host));
let sysroot = builder.sysroot(compiler);
dist::maybe_install_llvm_dylib(builder, compiler.host, &sysroot);
}

builder.ensure(RustcLink {
compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
Expand Down
6 changes: 3 additions & 3 deletions src/bootstrap/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::channel;
use crate::channel::GitInfo;
use crate::compile;
use crate::toolstate::ToolState;
use crate::util::{add_lib_path, exe, CiEnv};
use crate::util::{add_dylib_path, exe, CiEnv};
use crate::Compiler;
use crate::Mode;

Expand Down Expand Up @@ -388,7 +388,7 @@ pub struct ErrorIndex {
impl ErrorIndex {
pub fn command(builder: &Builder<'_>, compiler: Compiler) -> Command {
let mut cmd = Command::new(builder.ensure(ErrorIndex { compiler }));
add_lib_path(
add_dylib_path(
vec![PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))],
&mut cmd,
);
Expand Down Expand Up @@ -689,7 +689,7 @@ impl<'a> Builder<'a> {
}
}

add_lib_path(lib_paths, &mut cmd);
add_dylib_path(lib_paths, &mut cmd);
cmd
}
}
27 changes: 26 additions & 1 deletion src/bootstrap/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub fn libdir(target: &str) -> &'static str {
}

/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
pub fn add_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
let mut list = dylib_path();
for path in path {
list.insert(0, path);
Expand Down Expand Up @@ -72,6 +72,31 @@ pub fn dylib_path() -> Vec<PathBuf> {
env::split_paths(&var).collect()
}

/// Adds a list of lookup paths to `cmd`'s link library lookup path.
pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
let mut list = link_lib_path();
for path in path {
list.insert(0, path);
}
cmd.env(link_lib_path_var(), t!(env::join_paths(list)));
}

/// Returns the environment variable which the link library lookup path
/// resides in for this platform.
fn link_lib_path_var() -> &'static str {
if cfg!(target_env = "msvc") { "LIB" } else { "LIBRARY_PATH" }
}

/// Parses the `link_lib_path_var()` environment variable, returning a list of
/// paths that are members of this lookup path.
fn link_lib_path() -> Vec<PathBuf> {
let var = match env::var_os(link_lib_path_var()) {
Some(v) => v,
None => return vec![],
};
env::split_paths(&var).collect()
}

/// `push` all components to `buf`. On windows, append `.exe` to the last component.
pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf {
let (&file, components) = components.split_last().expect("at least one component required");
Expand Down