1
Fork 0

Handle new LLVM soname

LLVM now includes the minor version in the soname, and also changed
the names of shared object files. libLLVM-18.so is now a symlink to
libLLVM.so.18.1. We need to make some changes to support this:

First, we need to run the installed llvm-config binary, rather
than the one from the build directory. This is because the symlink
does not exist in the build directory, but llvm-config requires it.
This looks like an LLVM bug to me, but it's probably a good idea to
use the installed version anyway.

Second, when installing LLVM into the libdir, we need to install
the target of the symlink, ans this is what will get loaded at
runtime.

However, the rust-dev component in particular also needs to
distribute the symlink itself, as download-ci-llvm will end up
invoking llvm-config, which requires the symlink to exist. The
symlink is not shipped in other components.
This commit is contained in:
Nikita Popov 2024-02-22 11:55:09 +01:00
parent 4b55e17efd
commit 1a652fa869
3 changed files with 32 additions and 11 deletions

View file

@ -2021,18 +2021,39 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
}
}
fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
fn install_llvm_file(
builder: &Builder<'_>,
source: &Path,
destination: &Path,
install_symlink: bool,
) {
if builder.config.dry_run() {
return;
}
builder.install(source, destination, 0o644);
if source.is_symlink() {
// If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the
// symlink, which is what will actually get loaded at runtime.
builder.install(&t!(fs::canonicalize(source)), destination, 0o644);
if install_symlink {
// If requested, also install the symlink. This is used by download-ci-llvm.
let full_dest = destination.join(source.file_name().unwrap());
builder.copy(&source, &full_dest);
}
} else {
builder.install(&source, destination, 0o644);
}
}
/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
///
/// Returns whether the files were actually copied.
fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
fn maybe_install_llvm(
builder: &Builder<'_>,
target: TargetSelection,
dst_libdir: &Path,
install_symlink: bool,
) -> bool {
// If the LLVM was externally provided, then we don't currently copy
// artifacts into the sysroot. This is not necessarily the right
// choice (in particular, it will require the LLVM dylib to be in
@ -2081,7 +2102,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
} else {
PathBuf::from(file)
};
install_llvm_file(builder, &file, dst_libdir);
install_llvm_file(builder, &file, dst_libdir, install_symlink);
}
!builder.config.dry_run()
} else {
@ -2096,7 +2117,7 @@ pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection,
// dynamically linked; it is already included into librustc_llvm
// statically.
if builder.llvm_link_shared() {
maybe_install_llvm(builder, target, &dst_libdir);
maybe_install_llvm(builder, target, &dst_libdir, false);
}
}
@ -2108,7 +2129,7 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
// dynamically linked; it is already included into librustc_llvm
// statically.
if builder.llvm_link_shared() {
maybe_install_llvm(builder, target, &dst_libdir);
maybe_install_llvm(builder, target, &dst_libdir, false);
}
}
@ -2203,6 +2224,8 @@ impl Step for RustDev {
let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
tarball.set_overlay(OverlayKind::LLVM);
// LLVM requires a shared object symlink to exist on some platforms.
tarball.permit_symlinks(true);
builder.ensure(crate::core::build_steps::llvm::Llvm { target });
@ -2243,7 +2266,7 @@ impl Step for RustDev {
// of `rustc-dev` to support the inherited `-lLLVM` when using the
// compiler libraries.
let dst_libdir = tarball.image_dir().join("lib");
maybe_install_llvm(builder, target, &dst_libdir);
maybe_install_llvm(builder, target, &dst_libdir, true);
let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);

View file

@ -98,9 +98,6 @@ pub fn prebuilt_llvm_config(
let out_dir = builder.llvm_out(target);
let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build);
if (!builder.config.build.is_msvc() || builder.ninja()) && !builder.config.llvm_from_ci {
llvm_config_ret_dir.push("build");
}
llvm_config_ret_dir.push("bin");
let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", builder.config.build));
let llvm_cmake_dir = out_dir.join("lib/cmake/llvm");

View file

@ -270,7 +270,8 @@ fn execute_pipeline(
})?;
let libdir = env.build_artifacts().join("stage2").join("lib");
let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM", ".so")?;
// The actual name will be something like libLLVM.so.18.1-rust-dev.
let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM.so", "")?;
log::info!("Optimizing {llvm_lib} with BOLT");