Auto merge of #104091 - BelovDV:issue-103044, r=petrochenkov

Wrap bundled static libraries into object files

Fixes #103044 (not sure, couldn't test locally)

Bundled static libraries should be wrapped into object files as it's done for metadata file.

r? `@petrochenkov`
This commit is contained in:
bors 2022-11-15 00:38:08 +00:00
commit dedfb9c214
7 changed files with 51 additions and 19 deletions

View File

@ -4,8 +4,11 @@ use rustc_session::cstore::DllImport;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use super::metadata::search_for_section;
use object::read::archive::ArchiveFile; use object::read::archive::ArchiveFile;
use std::error::Error;
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -56,6 +59,9 @@ pub trait ArchiveBuilderBuilder {
if !bundled_lib_file_names.contains(&Symbol::intern(name)) { if !bundled_lib_file_names.contains(&Symbol::intern(name)) {
continue; // We need to extract only native libraries. continue; // We need to extract only native libraries.
} }
let data = search_for_section(rlib, data, ".bundled_lib").map_err(|e| {
ExtractBundledLibsError::ExtractSection { rlib, error: Box::<dyn Error>::from(e) }
})?;
std::fs::write(&outdir.join(&name), data) std::fs::write(&outdir.join(&name), data)
.map_err(|e| ExtractBundledLibsError::WriteFile { rlib, error: Box::new(e) })?; .map_err(|e| ExtractBundledLibsError::WriteFile { rlib, error: Box::new(e) })?;
} }

View File

@ -8,7 +8,7 @@ use rustc_errors::{ErrorGuaranteed, Handler};
use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_metadata::find_native_static_library; use rustc_metadata::find_native_static_library;
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME}; use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip}; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Lto, Strip};
@ -29,7 +29,7 @@ use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
use super::command::Command; use super::command::Command;
use super::linker::{self, Linker}; use super::linker::{self, Linker};
use super::metadata::{create_rmeta_file, MetadataPosition}; use super::metadata::{create_wrapper_file, MetadataPosition};
use super::rpath::{self, RPathConfig}; use super::rpath::{self, RPathConfig};
use crate::{ use crate::{
errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
@ -44,7 +44,7 @@ use std::borrow::Borrow;
use std::cell::OnceCell; use std::cell::OnceCell;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::ffi::OsString; use std::ffi::OsString;
use std::fs::{File, OpenOptions}; use std::fs::{read, File, OpenOptions};
use std::io::{BufWriter, Write}; use std::io::{BufWriter, Write};
use std::ops::Deref; use std::ops::Deref;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -292,8 +292,8 @@ fn link_rlib<'a>(
let trailing_metadata = match flavor { let trailing_metadata = match flavor {
RlibFlavor::Normal => { RlibFlavor::Normal => {
let (metadata, metadata_position) = let (metadata, metadata_position) =
create_rmeta_file(sess, codegen_results.metadata.raw_data()); create_wrapper_file(sess, b".rmeta".to_vec(), codegen_results.metadata.raw_data());
let metadata = emit_metadata(sess, &metadata, tmpdir); let metadata = emit_wrapper_file(sess, &metadata, tmpdir, METADATA_FILENAME);
match metadata_position { match metadata_position {
MetadataPosition::First => { MetadataPosition::First => {
// Most of the time metadata in rlib files is wrapped in a "dummy" object // Most of the time metadata in rlib files is wrapped in a "dummy" object
@ -376,12 +376,18 @@ fn link_rlib<'a>(
let location = let location =
find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess); find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess);
if sess.opts.unstable_opts.packed_bundled_libs && flavor == RlibFlavor::Normal { if sess.opts.unstable_opts.packed_bundled_libs && flavor == RlibFlavor::Normal {
packed_bundled_libs.push(find_native_static_library( let filename = lib.filename.unwrap();
lib.filename.unwrap().as_str(), let lib_path = find_native_static_library(
filename.as_str(),
Some(true), Some(true),
&lib_search_paths, &lib_search_paths,
sess, sess,
)); );
let src = read(lib_path)
.map_err(|e| sess.emit_fatal(errors::ReadFileError { message: e }))?;
let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
packed_bundled_libs.push(wrapper_file);
continue; continue;
} }
ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| { ab.add_archive(&location, Box::new(|_| false)).unwrap_or_else(|error| {

View File

@ -60,7 +60,7 @@ impl MetadataLoader for DefaultMetadataLoader {
let data = entry let data = entry
.data(data) .data(data)
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
return search_for_metadata(path, data, ".rmeta"); return search_for_section(path, data, ".rmeta");
} }
} }
@ -69,11 +69,11 @@ impl MetadataLoader for DefaultMetadataLoader {
} }
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
load_metadata_with(path, |data| search_for_metadata(path, data, ".rustc")) load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
} }
} }
fn search_for_metadata<'a>( pub(super) fn search_for_section<'a>(
path: &Path, path: &Path,
bytes: &'a [u8], bytes: &'a [u8],
section: &str, section: &str,
@ -223,7 +223,11 @@ pub enum MetadataPosition {
// * ELF - All other targets are similar to Windows in that there's a // * ELF - All other targets are similar to Windows in that there's a
// `SHF_EXCLUDE` flag we can set on sections in an object file to get // `SHF_EXCLUDE` flag we can set on sections in an object file to get
// automatically removed from the final output. // automatically removed from the final output.
pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> (Vec<u8>, MetadataPosition) { pub fn create_wrapper_file(
sess: &Session,
section_name: Vec<u8>,
data: &[u8],
) -> (Vec<u8>, MetadataPosition) {
let Some(mut file) = create_object_file(sess) else { let Some(mut file) = create_object_file(sess) else {
// This is used to handle all "other" targets. This includes targets // This is used to handle all "other" targets. This includes targets
// in two categories: // in two categories:
@ -241,11 +245,11 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> (Vec<u8>, MetadataP
// WebAssembly and for targets not supported by the `object` crate // WebAssembly and for targets not supported by the `object` crate
// yet it means that work will need to be done in the `object` crate // yet it means that work will need to be done in the `object` crate
// to add a case above. // to add a case above.
return (metadata.to_vec(), MetadataPosition::Last); return (data.to_vec(), MetadataPosition::Last);
}; };
let section = file.add_section( let section = file.add_section(
file.segment_name(StandardSegment::Debug).to_vec(), file.segment_name(StandardSegment::Debug).to_vec(),
b".rmeta".to_vec(), section_name,
SectionKind::Debug, SectionKind::Debug,
); );
match file.format() { match file.format() {
@ -259,7 +263,7 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> (Vec<u8>, MetadataP
} }
_ => {} _ => {}
}; };
file.append_section_data(section, metadata, 1); file.append_section_data(section, data, 1);
(file.write().unwrap(), MetadataPosition::First) (file.write().unwrap(), MetadataPosition::First)
} }

View File

@ -507,6 +507,9 @@ pub enum ExtractBundledLibsError<'a> {
#[diag(codegen_ssa_extract_bundled_libs_write_file)] #[diag(codegen_ssa_extract_bundled_libs_write_file)]
WriteFile { rlib: &'a Path, error: Box<dyn std::error::Error> }, WriteFile { rlib: &'a Path, error: Box<dyn std::error::Error> },
#[diag(codegen_ssa_extract_bundled_libs_write_file)]
ExtractSection { rlib: &'a Path, error: Box<dyn std::error::Error> },
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -521,3 +524,9 @@ pub enum AppleSdkRootError<'a> {
#[diag(codegen_ssa_apple_sdk_error_sdk_path)] #[diag(codegen_ssa_apple_sdk_error_sdk_path)]
SdkPath { sdk_name: &'a str, error: Error }, SdkPath { sdk_name: &'a str, error: Error },
} }
#[derive(Diagnostic)]
#[diag(codegen_ssa_read_file)]
pub struct ReadFileError {
pub message: std::io::Error,
}

View File

@ -182,3 +182,5 @@ codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$
codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {error} codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {error}
codegen_ssa_read_file = failed to read file: {message}

View File

@ -22,9 +22,14 @@ pub const METADATA_FILENAME: &str = "lib.rmeta";
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
/// directory being searched for `extern crate` (observing an incomplete file). /// directory being searched for `extern crate` (observing an incomplete file).
/// The returned path is the temporary file containing the complete metadata. /// The returned path is the temporary file containing the complete metadata.
pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf { pub fn emit_wrapper_file(
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME); sess: &Session,
let result = fs::write(&out_filename, metadata); data: &[u8],
tmpdir: &MaybeTempDir,
name: &str,
) -> PathBuf {
let out_filename = tmpdir.as_ref().join(name);
let result = fs::write(&out_filename, data);
if let Err(err) = result { if let Err(err) = result {
sess.emit_fatal(FailedWriteError { filename: out_filename, err }); sess.emit_fatal(FailedWriteError { filename: out_filename, err });

View File

@ -41,6 +41,6 @@ pub mod errors;
pub mod fs; pub mod fs;
pub mod locator; pub mod locator;
pub use fs::{emit_metadata, METADATA_FILENAME}; pub use fs::{emit_wrapper_file, METADATA_FILENAME};
pub use native_libs::find_native_static_library; pub use native_libs::find_native_static_library;
pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER}; pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER};