aix: fix archive format

fmt

fix cfg for windows

remove unused imports

address comments

update libc to 0.2.164

fmt

remove unused imports
This commit is contained in:
Henry Jiang 2024-11-17 21:59:43 -05:00
parent 3fee0f12e4
commit 0db9059726
10 changed files with 127 additions and 22 deletions

View file

@ -1965,9 +1965,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.161" version = "0.2.164"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
[[package]] [[package]]
name = "libdbus-sys" name = "libdbus-sys"
@ -3988,6 +3988,7 @@ name = "rustc_metadata"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"libc",
"libloading", "libloading",
"odht", "odht",
"rustc_abi", "rustc_abi",

View file

@ -777,6 +777,16 @@ fn link_natively(
info!("preparing {:?} to {:?}", crate_type, out_filename); info!("preparing {:?} to {:?}", crate_type, out_filename);
let (linker_path, flavor) = linker_and_flavor(sess); let (linker_path, flavor) = linker_and_flavor(sess);
let self_contained_components = self_contained_components(sess, crate_type); let self_contained_components = self_contained_components(sess, crate_type);
// On AIX, we ship all libraries as .a big_af archive
// the expected format is lib<name>.a(libname.so) for the actual
// dynamic library. So we link to a temporary .so file to be archived
// at the final out_filename location
let should_archive = crate_type != CrateType::Executable && sess.target.is_like_aix;
let archive_member =
should_archive.then(|| tmpdir.join(out_filename.file_name().unwrap()).with_extension("so"));
let temp_filename = archive_member.as_deref().unwrap_or(out_filename);
let mut cmd = linker_with_args( let mut cmd = linker_with_args(
&linker_path, &linker_path,
flavor, flavor,
@ -784,7 +794,7 @@ fn link_natively(
archive_builder_builder, archive_builder_builder,
crate_type, crate_type,
tmpdir, tmpdir,
out_filename, temp_filename,
codegen_results, codegen_results,
self_contained_components, self_contained_components,
)?; )?;
@ -1158,6 +1168,12 @@ fn link_natively(
} }
} }
if should_archive {
let mut ab = archive_builder_builder.new_archive_builder(sess);
ab.add_file(temp_filename);
ab.build(out_filename);
}
Ok(()) Ok(())
} }

View file

@ -5,6 +5,7 @@ use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use itertools::Itertools;
use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::write::{self, StandardSegment, Symbol, SymbolSection};
use object::{ use object::{
Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, ObjectSymbol, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, ObjectSymbol,
@ -21,6 +22,7 @@ use rustc_middle::bug;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::sym; use rustc_span::sym;
use rustc_target::spec::{RelocModel, Target, ef_avr_arch}; use rustc_target::spec::{RelocModel, Target, ef_avr_arch};
use tracing::debug;
use super::apple; use super::apple;
@ -53,6 +55,7 @@ fn load_metadata_with(
impl MetadataLoader for DefaultMetadataLoader { impl MetadataLoader for DefaultMetadataLoader {
fn get_rlib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> { fn get_rlib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
debug!("getting rlib metadata for {}", path.display());
load_metadata_with(path, |data| { load_metadata_with(path, |data| {
let archive = object::read::archive::ArchiveFile::parse(&*data) let archive = object::read::archive::ArchiveFile::parse(&*data)
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
@ -77,8 +80,26 @@ impl MetadataLoader for DefaultMetadataLoader {
} }
fn get_dylib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> { fn get_dylib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
debug!("getting dylib metadata for {}", path.display());
if target.is_like_aix { if target.is_like_aix {
load_metadata_with(path, |data| get_metadata_xcoff(path, data)) load_metadata_with(path, |data| {
let archive = object::read::archive::ArchiveFile::parse(&*data).map_err(|e| {
format!("failed to parse aix dylib '{}': {}", path.display(), e)
})?;
match archive.members().exactly_one() {
Ok(lib) => {
let lib = lib.map_err(|e| {
format!("failed to parse aix dylib '{}': {}", path.display(), e)
})?;
let data = lib.data(data).map_err(|e| {
format!("failed to parse aix dylib '{}': {}", path.display(), e)
})?;
get_metadata_xcoff(path, data)
}
Err(e) => Err(format!("failed to parse aix dylib '{}': {}", path.display(), e)),
}
})
} else { } else {
load_metadata_with(path, |data| search_for_section(path, data, ".rustc")) load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
} }

View file

@ -6,6 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
# tidy-alphabetical-start # tidy-alphabetical-start
bitflags = "2.4.1" bitflags = "2.4.1"
libc = "0.2"
libloading = "0.8.0" libloading = "0.8.0"
odht = { version = "0.3.1", features = ["nightly"] } odht = { version = "0.3.1", features = ["nightly"] }
rustc_abi = { path = "../rustc_abi" } rustc_abi = { path = "../rustc_abi" }

View file

@ -540,6 +540,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
Some(cnum) Some(cnum)
} }
Err(err) => { Err(err) => {
debug!("failed to resolve crate {} {:?}", name, dep_kind);
let missing_core = let missing_core =
self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
err.report(self.sess, span, missing_core); err.report(self.sess, span, missing_core);
@ -588,6 +589,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
match self.load(&mut locator)? { match self.load(&mut locator)? {
Some(res) => (res, None), Some(res) => (res, None),
None => { None => {
info!("falling back to loading proc_macro");
dep_kind = CrateDepKind::MacrosOnly; dep_kind = CrateDepKind::MacrosOnly;
match self.load_proc_macro(&mut locator, path_kind, host_hash)? { match self.load_proc_macro(&mut locator, path_kind, host_hash)? {
Some(res) => res, Some(res) => res,
@ -599,6 +601,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
match result { match result {
(LoadResult::Previous(cnum), None) => { (LoadResult::Previous(cnum), None) => {
info!("library for `{}` was loaded previously", name);
// When `private_dep` is none, it indicates the directly dependent crate. If it is // When `private_dep` is none, it indicates the directly dependent crate. If it is
// not specified by `--extern` on command line parameters, it may be // not specified by `--extern` on command line parameters, it may be
// `private-dependency` when `register_crate` is called for the first time. Then it must be updated to // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
@ -613,6 +616,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
Ok(cnum) Ok(cnum)
} }
(LoadResult::Loaded(library), host_library) => { (LoadResult::Loaded(library), host_library) => {
info!("register newly loaded library for `{}`", name);
self.register_crate(host_library, root, library, dep_kind, name, private_dep) self.register_crate(host_library, root, library, dep_kind, name, private_dep)
} }
_ => panic!(), _ => panic!(),
@ -696,7 +700,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
stable_crate_id: StableCrateId, stable_crate_id: StableCrateId,
) -> Result<&'static [ProcMacro], CrateError> { ) -> Result<&'static [ProcMacro], CrateError> {
let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id); let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
Ok(unsafe { *load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name)? }) debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
unsafe {
let result = load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name);
match result {
Ok(result) => {
debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
Ok(*result)
}
Err(err) => {
debug!(
"failed to dlsym proc_macros {} for symbol `{}`",
path.display(),
sym_name
);
Err(err.into())
}
}
}
} }
fn inject_panic_runtime(&mut self, krate: &ast::Crate) { fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
@ -1141,6 +1163,29 @@ fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
e.sources().map(|e| format!(": {e}")).collect() e.sources().map(|e| format!(": {e}")).collect()
} }
fn attempt_load_dylib(path: &Path) -> Result<libloading::Library, libloading::Error> {
#[cfg(target_os = "aix")]
if let Some(ext) = path.extension()
&& ext.eq("a")
{
// On AIX, we ship all libraries as .a big_af archive
// the expected format is lib<name>.a(libname.so) for the actual
// dynamic library
let library_name = path.file_stem().expect("expect a library name");
let mut archive_member = OsString::from("a(");
archive_member.push(library_name);
archive_member.push(".so)");
let new_path = path.with_extension(archive_member);
// On AIX, we need RTLD_MEMBER to dlopen an archived shared
let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER;
return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) }
.map(|lib| lib.into());
}
unsafe { libloading::Library::new(&path) }
}
// On Windows the compiler would sometimes intermittently fail to open the // On Windows the compiler would sometimes intermittently fail to open the
// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the // proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
// system still holds a lock on the file, so we retry a few times before calling it // system still holds a lock on the file, so we retry a few times before calling it
@ -1151,7 +1196,8 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, S
let mut last_error = None; let mut last_error = None;
for attempt in 0..max_attempts { for attempt in 0..max_attempts {
match unsafe { libloading::Library::new(&path) } { debug!("Attempt to load proc-macro `{}`.", path.display());
match attempt_load_dylib(path) {
Ok(lib) => { Ok(lib) => {
if attempt > 0 { if attempt > 0 {
debug!( debug!(
@ -1165,6 +1211,7 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, S
Err(err) => { Err(err) => {
// Only try to recover from this specific error. // Only try to recover from this specific error.
if !matches!(err, libloading::Error::LoadLibraryExW { .. }) { if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
debug!("Failed to load proc-macro `{}`. Not retrying", path.display());
let err = format_dlopen_err(&err); let err = format_dlopen_err(&err);
// We include the path of the dylib in the error ourselves, so // We include the path of the dylib in the error ourselves, so
// if it's in the error, we strip it. // if it's in the error, we strip it.

View file

@ -847,7 +847,10 @@ fn get_metadata_section<'p>(
))); )));
}; };
match blob.check_compatibility(cfg_version) { match blob.check_compatibility(cfg_version) {
Ok(()) => Ok(blob), Ok(()) => {
debug!("metadata blob read okay");
Ok(blob)
}
Err(None) => Err(MetadataError::LoadFailure(format!( Err(None) => Err(MetadataError::LoadFailure(format!(
"invalid metadata version found: {}", "invalid metadata version found: {}",
filename.display() filename.display()

View file

@ -1457,7 +1457,7 @@ impl Step for CodegenBackend {
} }
let mut files = files.into_iter().filter(|f| { let mut files = files.into_iter().filter(|f| {
let filename = f.file_name().unwrap().to_str().unwrap(); let filename = f.file_name().unwrap().to_str().unwrap();
is_dylib(filename) && filename.contains("rustc_codegen_") is_dylib(f) && filename.contains("rustc_codegen_")
}); });
let codegen_backend = match files.next() { let codegen_backend = match files.next() {
Some(f) => f, Some(f) => f,
@ -1936,7 +1936,7 @@ impl Step for Assemble {
let filename = f.file_name().into_string().unwrap(); let filename = f.file_name().into_string().unwrap();
let is_proc_macro = proc_macros.contains(&filename); let is_proc_macro = proc_macros.contains(&filename);
let is_dylib_or_debug = is_dylib(&filename) || is_debug_info(&filename); let is_dylib_or_debug = is_dylib(&f.path()) || is_debug_info(&filename);
// If we link statically to stdlib, do not copy the libstd dynamic library file // If we link statically to stdlib, do not copy the libstd dynamic library file
// FIXME: Also do this for Windows once incremental post-optimization stage0 tests // FIXME: Also do this for Windows once incremental post-optimization stage0 tests
@ -2089,7 +2089,7 @@ pub fn run_cargo(
if filename.ends_with(".lib") if filename.ends_with(".lib")
|| filename.ends_with(".a") || filename.ends_with(".a")
|| is_debug_info(&filename) || is_debug_info(&filename)
|| is_dylib(&filename) || is_dylib(Path::new(&*filename))
{ {
// Always keep native libraries, rust dylibs and debuginfo // Always keep native libraries, rust dylibs and debuginfo
keep = true; keep = true;
@ -2189,7 +2189,7 @@ pub fn run_cargo(
Some(triple) => triple.0.to_str().unwrap(), Some(triple) => triple.0.to_str().unwrap(),
None => panic!("no output generated for {prefix:?} {extension:?}"), None => panic!("no output generated for {prefix:?} {extension:?}"),
}; };
if is_dylib(path_to_add) { if is_dylib(Path::new(path_to_add)) {
let candidate = format!("{path_to_add}.lib"); let candidate = format!("{path_to_add}.lib");
let candidate = PathBuf::from(candidate); let candidate = PathBuf::from(candidate);
if candidate.exists() { if candidate.exists() {

View file

@ -436,13 +436,10 @@ impl Step for Rustc {
if libdir_relative.to_str() != Some("bin") { if libdir_relative.to_str() != Some("bin") {
let libdir = builder.rustc_libdir(compiler); let libdir = builder.rustc_libdir(compiler);
for entry in builder.read_dir(&libdir) { for entry in builder.read_dir(&libdir) {
let name = entry.file_name(); if is_dylib(&entry.path()) {
if let Some(s) = name.to_str() { // Don't use custom libdir here because ^lib/ will be resolved again
if is_dylib(s) { // with installer
// Don't use custom libdir here because ^lib/ will be resolved again builder.install(&entry.path(), &image.join("lib"), 0o644);
// with installer
builder.install(&entry.path(), &image.join("lib"), 0o644);
}
} }
} }
} }

View file

@ -2949,8 +2949,7 @@ impl Step for RemoteCopyLibs {
// Push all our dylibs to the emulator // Push all our dylibs to the emulator
for f in t!(builder.sysroot_target_libdir(compiler, target).read_dir()) { for f in t!(builder.sysroot_target_libdir(compiler, target).read_dir()) {
let f = t!(f); let f = t!(f);
let name = f.file_name().into_string().unwrap(); if helpers::is_dylib(&f.path()) {
if helpers::is_dylib(&name) {
command(&tool).arg("push").arg(f.path()).run(builder); command(&tool).arg("push").arg(f.path()).run(builder);
} }
} }

View file

@ -11,6 +11,7 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH};
use std::{env, fs, io, str}; use std::{env, fs, io, str};
use build_helper::util::fail; use build_helper::util::fail;
use object::read::archive::ArchiveFile;
use crate::LldMode; use crate::LldMode;
use crate::core::builder::Builder; use crate::core::builder::Builder;
@ -53,8 +54,27 @@ pub fn exe(name: &str, target: TargetSelection) -> String {
} }
/// Returns `true` if the file name given looks like a dynamic library. /// Returns `true` if the file name given looks like a dynamic library.
pub fn is_dylib(name: &str) -> bool { pub fn is_dylib(path: &Path) -> bool {
name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll") path.extension().and_then(|ext| ext.to_str()).map_or(false, |ext| {
ext == "dylib" || ext == "so" || ext == "dll" || (ext == "a" && is_aix_shared_archive(path))
})
}
fn is_aix_shared_archive(path: &Path) -> bool {
// FIXME(#133268): reading the entire file as &[u8] into memory seems excessive
// look into either mmap it or use the ReadCache
let data = match fs::read(path) {
Ok(data) => data,
Err(_) => return false,
};
let file = match ArchiveFile::parse(&*data) {
Ok(file) => file,
Err(_) => return false,
};
file.members()
.filter_map(Result::ok)
.any(|entry| String::from_utf8_lossy(entry.name()).contains(".so"))
} }
/// Returns `true` if the file name given looks like a debug info file /// Returns `true` if the file name given looks like a debug info file