Skip to content

Commit b6e28b5

Browse files
committed
Allow dynamically linking against libLLVM on macOS
Create symlinks to workaround file missing error in llvm-config
1 parent fdca237 commit b6e28b5

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

src/bootstrap/lib.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,11 @@ use std::cell::{Cell, RefCell};
107107
use std::collections::{HashMap, HashSet};
108108
use std::env;
109109
use std::fs::{self, File};
110+
use std::io;
110111
use std::path::{Path, PathBuf};
111112
use std::process::{self, Command};
112113
use std::str;
113114

114-
#[cfg(unix)]
115-
use std::os::unix::fs::symlink as symlink_file;
116-
#[cfg(windows)]
117-
use std::os::windows::fs::symlink_file;
118-
119115
use filetime::FileTime;
120116
use once_cell::sync::OnceCell;
121117

@@ -1446,7 +1442,7 @@ impl Build {
14461442
src = t!(fs::canonicalize(src));
14471443
} else {
14481444
let link = t!(fs::read_link(src));
1449-
t!(symlink_file(link, dst));
1445+
t!(self.symlink_file(link, dst));
14501446
return;
14511447
}
14521448
}
@@ -1571,6 +1567,14 @@ impl Build {
15711567
iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
15721568
}
15731569

1570+
fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(&self, src: P, link: Q) -> io::Result<()> {
1571+
#[cfg(unix)]
1572+
use std::os::unix::fs::symlink as symlink_file;
1573+
#[cfg(windows)]
1574+
use std::os::windows::fs::symlink_file;
1575+
if !self.config.dry_run { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) }
1576+
}
1577+
15741578
fn remove(&self, f: &Path) {
15751579
if self.config.dry_run {
15761580
return;

src/bootstrap/native.rs

+31-10
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,7 @@ impl Step for Llvm {
238238
};
239239

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

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

@@ -425,18 +425,18 @@ impl Step for Llvm {
425425
);
426426
}
427427

428-
if let Some(ref suffix) = builder.config.llvm_version_suffix {
428+
let llvm_version_suffix = if let Some(ref suffix) = builder.config.llvm_version_suffix {
429429
// Allow version-suffix="" to not define a version suffix at all.
430-
if !suffix.is_empty() {
431-
cfg.define("LLVM_VERSION_SUFFIX", suffix);
432-
}
430+
if !suffix.is_empty() { Some(suffix.to_string()) } else { None }
433431
} else if builder.config.channel == "dev" {
434432
// Changes to a version suffix require a complete rebuild of the LLVM.
435433
// To avoid rebuilds during a time of version bump, don't include rustc
436434
// release number on the dev channel.
437-
cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev");
435+
Some("-rust-dev".to_string())
438436
} else {
439-
let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel);
437+
Some(format!("-rust-{}-{}", builder.version, builder.config.channel))
438+
};
439+
if let Some(ref suffix) = llvm_version_suffix {
440440
cfg.define("LLVM_VERSION_SUFFIX", suffix);
441441
}
442442

@@ -465,6 +465,27 @@ impl Step for Llvm {
465465

466466
cfg.build();
467467

468+
// When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
469+
// libLLVM.dylib will be built. However, llvm-config will still look
470+
// for a versioned path like libLLVM-14.dylib. Manually create a symbolic
471+
// link to make llvm-config happy.
472+
if llvm_link_shared && target.contains("apple-darwin") {
473+
let mut cmd = Command::new(&build_llvm_config);
474+
let version = output(cmd.arg("--version"));
475+
let major = version.split('.').next().unwrap();
476+
let lib_name = match llvm_version_suffix {
477+
Some(s) => format!("lib/libLLVM-{}{}.dylib", major, s),
478+
None => format!("lib/libLLVM-{}.dylib", major),
479+
};
480+
481+
// The reason why we build the library path from llvm-config is because
482+
// the output of llvm-config depends on its location in the file system.
483+
// Make sure we create the symlink exactly where it's needed.
484+
let llvm_base = build_llvm_config.parent().unwrap().parent().unwrap();
485+
let lib_llvm = llvm_base.join(lib_name);
486+
t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
487+
}
488+
468489
t!(stamp.write());
469490

470491
build_llvm_config

0 commit comments

Comments
 (0)