about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2022-07-01 23:39:07 +0200
committerGitHub <noreply@github.com>2022-07-01 23:39:07 +0200
commit01aa10c2ffd49238d0aef83253190c8df0d77c87 (patch)
treea6b1e1e54a7f726afb79df01a37b89a51c7c9fb2 /src
parent194764fdc070d95ce2200548a2e6267d701068bd (diff)
parentb6e28b59679e3e4ee47b20090035ef33889b3f3b (diff)
downloadrust-01aa10c2ffd49238d0aef83253190c8df0d77c87.tar.gz
rust-01aa10c2ffd49238d0aef83253190c8df0d77c87.zip
Rollup merge of #98418 - topjohnwu:macos-dylib, r=jyn514
Allow macOS to build LLVM as shared library

Inspired by how [homebrew](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/llvm.rb) builds and distributes llvm, here we manually create a symlink with a versioned dylib path to make `llvm-config` work properly. Note, the resulting `rustc` executable and `librustc_driver-<hash>.dylib` still links to the un-versioned `libLLVM.dylib` as expected when distributed in the final output. I have confirmed this by checking `otool -L` on both binaries.

After the change, enabling `llvm.link-shared` and `llvm.thin-lto` will be possible on macOS.
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/lib.rs16
-rw-r--r--src/bootstrap/native.rs41
2 files changed, 41 insertions, 16 deletions
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 859d35b7d7b..40ff0381c8b 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -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;
 
@@ -1460,7 +1456,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;
             }
         }
@@ -1585,6 +1581,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;
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 9cd8b6d1455..8395be40f9b 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -251,9 +251,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);
         }
 
@@ -359,7 +357,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");
         }
 
@@ -438,18 +438,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);
         }
 
@@ -478,6 +478,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