Skip to content

Commit

Permalink
Allow dynamically linking against libLLVM on macOS
Browse files Browse the repository at this point in the history
Create symlinks to workaround file missing error in llvm-config
  • Loading branch information
topjohnwu committed Jun 24, 2022
1 parent fdca237 commit b6e28b5
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 16 deletions.
16 changes: 10 additions & 6 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,11 @@ use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::{self, File};
use std::io;
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::str;

#[cfg(unix)]
use std::os::unix::fs::symlink as symlink_file;
#[cfg(windows)]
use std::os::windows::fs::symlink_file;

use filetime::FileTime;
use once_cell::sync::OnceCell;

Expand Down Expand Up @@ -1446,7 +1442,7 @@ impl Build {
src = t!(fs::canonicalize(src));
} else {
let link = t!(fs::read_link(src));
t!(symlink_file(link, dst));
t!(self.symlink_file(link, dst));
return;
}
}
Expand Down Expand Up @@ -1571,6 +1567,14 @@ impl Build {
iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
}

fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(&self, src: P, link: Q) -> io::Result<()> {
#[cfg(unix)]
use std::os::unix::fs::symlink as symlink_file;
#[cfg(windows)]
use std::os::windows::fs::symlink_file;
if !self.config.dry_run { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) }
}

fn remove(&self, f: &Path) {
if self.config.dry_run {
return;
Expand Down
41 changes: 31 additions & 10 deletions src/bootstrap/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,7 @@ impl Step for Llvm {
};

builder.update_submodule(&Path::new("src").join("llvm-project"));
if builder.llvm_link_shared()
&& (target.contains("windows") || target.contains("apple-darwin"))
{
if builder.llvm_link_shared() && target.contains("windows") {
panic!("shared linking to LLVM is not currently supported on {}", target.triple);
}

Expand Down Expand Up @@ -346,7 +344,9 @@ impl Step for Llvm {
//
// If we're not linking rustc to a dynamic LLVM, though, then don't link
// tools to it.
if builder.llvm_link_tools_dynamically(target) && builder.llvm_link_shared() {
let llvm_link_shared =
builder.llvm_link_tools_dynamically(target) && builder.llvm_link_shared();
if llvm_link_shared {
cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
}

Expand Down Expand Up @@ -425,18 +425,18 @@ impl Step for Llvm {
);
}

if let Some(ref suffix) = builder.config.llvm_version_suffix {
let llvm_version_suffix = if let Some(ref suffix) = builder.config.llvm_version_suffix {
// Allow version-suffix="" to not define a version suffix at all.
if !suffix.is_empty() {
cfg.define("LLVM_VERSION_SUFFIX", suffix);
}
if !suffix.is_empty() { Some(suffix.to_string()) } else { None }
} else if builder.config.channel == "dev" {
// Changes to a version suffix require a complete rebuild of the LLVM.
// To avoid rebuilds during a time of version bump, don't include rustc
// release number on the dev channel.
cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev");
Some("-rust-dev".to_string())
} else {
let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel);
Some(format!("-rust-{}-{}", builder.version, builder.config.channel))
};
if let Some(ref suffix) = llvm_version_suffix {
cfg.define("LLVM_VERSION_SUFFIX", suffix);
}

Expand Down Expand Up @@ -465,6 +465,27 @@ impl Step for Llvm {

cfg.build();

// When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
// libLLVM.dylib will be built. However, llvm-config will still look
// for a versioned path like libLLVM-14.dylib. Manually create a symbolic
// link to make llvm-config happy.
if llvm_link_shared && target.contains("apple-darwin") {
let mut cmd = Command::new(&build_llvm_config);
let version = output(cmd.arg("--version"));
let major = version.split('.').next().unwrap();
let lib_name = match llvm_version_suffix {
Some(s) => format!("lib/libLLVM-{}{}.dylib", major, s),
None => format!("lib/libLLVM-{}.dylib", major),
};

// The reason why we build the library path from llvm-config is because
// the output of llvm-config depends on its location in the file system.
// Make sure we create the symlink exactly where it's needed.
let llvm_base = build_llvm_config.parent().unwrap().parent().unwrap();
let lib_llvm = llvm_base.join(lib_name);
t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
}

t!(stamp.write());

build_llvm_config
Expand Down

0 comments on commit b6e28b5

Please sign in to comment.