]> git.lizzy.rs Git - rust.git/commitdiff
Allow dynamically linking against libLLVM on macOS
authortopjohnwu <topjohnwu@google.com>
Fri, 24 Jun 2022 21:27:37 +0000 (14:27 -0700)
committertopjohnwu <topjohnwu@google.com>
Fri, 24 Jun 2022 21:28:08 +0000 (14:28 -0700)
Create symlinks to workaround file missing error in llvm-config

src/bootstrap/lib.rs
src/bootstrap/native.rs

index 4ac857b470e806b772c3d598d01892456cc65b02..d30f69ffc5190e85c16ef0dd44b2d5871305962d 100644 (file)
 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;
 
@@ -1446,7 +1442,7 @@ fn copy_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) {
                 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;
             }
         }
@@ -1571,6 +1567,14 @@ fn read_dir(&self, dir: &Path) -> impl Iterator<Item = fs::DirEntry> {
         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;
index 329bb68672ee64bf24dad0acd98f9a0b6e26d0d3..e1ca8b487babfc72ccc77be7e4ed23e5f92bf78a 100644 (file)
@@ -238,9 +238,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             };
 
         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);
         }
 
@@ -346,7 +344,9 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         //
         // 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");
         }
 
@@ -425,18 +425,18 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             );
         }
 
-        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);
         }
 
@@ -465,6 +465,27 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         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