Skip to content

Commit f1dc349

Browse files
committed
Auto merge of rust-lang#97485 - bjorn3:new_archive_writer, r=wesleywiser
Rewrite LLVM's archive writer in Rust This allows it to be used by other codegen backends. Fixes https://github.com/bjorn3/rustc_codegen_cranelift/issues/1155
2 parents a085a2a + 5399526 commit f1dc349

File tree

3 files changed

+5
-226
lines changed

3 files changed

+5
-226
lines changed

Cargo.lock

-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ target-lexicon = "0.12.0"
1818
gimli = { version = "0.26.0", default-features = false, features = ["write"]}
1919
object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
2020

21-
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
2221
indexmap = "1.9.1"
2322
libloading = { version = "0.7.3", optional = true }
2423
once_cell = "1.10.0"

src/archive.rs

+5-219
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,15 @@
1-
//! Creation of ar archives like for the lib and staticlib crate type
2-
3-
use std::collections::BTreeMap;
4-
use std::fs::File;
5-
use std::io::{self, Read, Seek};
61
use std::path::{Path, PathBuf};
72

8-
use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
3+
use rustc_codegen_ssa::back::archive::{
4+
get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
5+
};
96
use rustc_session::Session;
107

11-
use object::read::archive::ArchiveFile;
12-
use object::{Object, ObjectSymbol, ReadCache};
13-
14-
#[derive(Debug)]
15-
enum ArchiveEntry {
16-
FromArchive { archive_index: usize, file_range: (u64, u64) },
17-
File(PathBuf),
18-
}
19-
208
pub(crate) struct ArArchiveBuilderBuilder;
219

2210
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
2311
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> {
24-
Box::new(ArArchiveBuilder {
25-
sess,
26-
use_gnu_style_archive: sess.target.archive_format == "gnu",
27-
// FIXME fix builtin ranlib on macOS
28-
no_builtin_ranlib: sess.target.is_like_osx,
29-
30-
src_archives: vec![],
31-
entries: vec![],
32-
})
12+
Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
3313
}
3414

3515
fn create_dll_import_lib(
@@ -40,200 +20,6 @@ impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
4020
_tmpdir: &Path,
4121
_is_direct_dependency: bool,
4222
) -> PathBuf {
43-
bug!("creating dll imports is not supported");
44-
}
45-
}
46-
47-
pub(crate) struct ArArchiveBuilder<'a> {
48-
sess: &'a Session,
49-
use_gnu_style_archive: bool,
50-
no_builtin_ranlib: bool,
51-
52-
src_archives: Vec<File>,
53-
// Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
54-
// the end of an archive for linkers to not get confused.
55-
entries: Vec<(Vec<u8>, ArchiveEntry)>,
56-
}
57-
58-
impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
59-
fn add_file(&mut self, file: &Path) {
60-
self.entries.push((
61-
file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
62-
ArchiveEntry::File(file.to_owned()),
63-
));
64-
}
65-
66-
fn add_archive(
67-
&mut self,
68-
archive_path: &Path,
69-
mut skip: Box<dyn FnMut(&str) -> bool + 'static>,
70-
) -> std::io::Result<()> {
71-
let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?);
72-
let archive = ArchiveFile::parse(&read_cache).unwrap();
73-
let archive_index = self.src_archives.len();
74-
75-
for entry in archive.members() {
76-
let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
77-
let file_name = String::from_utf8(entry.name().to_vec())
78-
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
79-
if !skip(&file_name) {
80-
self.entries.push((
81-
file_name.into_bytes(),
82-
ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
83-
));
84-
}
85-
}
86-
87-
self.src_archives.push(read_cache.into_inner());
88-
Ok(())
89-
}
90-
91-
fn build(mut self: Box<Self>, output: &Path) -> bool {
92-
enum BuilderKind {
93-
Bsd(ar::Builder<File>),
94-
Gnu(ar::GnuBuilder<File>),
95-
}
96-
97-
let sess = self.sess;
98-
99-
let mut symbol_table = BTreeMap::new();
100-
101-
let mut entries = Vec::new();
102-
103-
for (mut entry_name, entry) in self.entries {
104-
// FIXME only read the symbol table of the object files to avoid having to keep all
105-
// object files in memory at once, or read them twice.
106-
let data = match entry {
107-
ArchiveEntry::FromArchive { archive_index, file_range } => {
108-
// FIXME read symbols from symtab
109-
let src_read_cache = &mut self.src_archives[archive_index];
110-
111-
src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap();
112-
let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap());
113-
src_read_cache.read_exact(&mut data).unwrap();
114-
115-
data
116-
}
117-
ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
118-
sess.fatal(&format!(
119-
"error while reading object file during archive building: {}",
120-
err
121-
));
122-
}),
123-
};
124-
125-
if !self.no_builtin_ranlib {
126-
if symbol_table.contains_key(&entry_name) {
127-
// The ar crate can't handle creating a symbol table in case of multiple archive
128-
// members with the same name. Work around this by prepending a number until we
129-
// get a unique name.
130-
for i in 1.. {
131-
let new_name = format!("{}_", i)
132-
.into_bytes()
133-
.into_iter()
134-
.chain(entry_name.iter().copied())
135-
.collect::<Vec<_>>();
136-
if !symbol_table.contains_key(&new_name) {
137-
entry_name = new_name;
138-
break;
139-
}
140-
}
141-
}
142-
143-
match object::File::parse(&*data) {
144-
Ok(object) => {
145-
symbol_table.insert(
146-
entry_name.to_vec(),
147-
object
148-
.symbols()
149-
.filter_map(|symbol| {
150-
if symbol.is_undefined() || symbol.is_local() {
151-
None
152-
} else {
153-
symbol.name().map(|name| name.as_bytes().to_vec()).ok()
154-
}
155-
})
156-
.collect::<Vec<_>>(),
157-
);
158-
}
159-
Err(err) => {
160-
let err = err.to_string();
161-
if err == "Unknown file magic" {
162-
// Not an object file; skip it.
163-
} else if object::read::archive::ArchiveFile::parse(&*data).is_ok() {
164-
// Nested archive file; skip it.
165-
} else {
166-
sess.fatal(&format!(
167-
"error parsing `{}` during archive creation: {}",
168-
String::from_utf8_lossy(&entry_name),
169-
err
170-
));
171-
}
172-
}
173-
}
174-
}
175-
176-
entries.push((entry_name, data));
177-
}
178-
179-
let mut builder = if self.use_gnu_style_archive {
180-
BuilderKind::Gnu(
181-
ar::GnuBuilder::new(
182-
File::create(output).unwrap_or_else(|err| {
183-
sess.fatal(&format!(
184-
"error opening destination during archive building: {}",
185-
err
186-
));
187-
}),
188-
entries.iter().map(|(name, _)| name.clone()).collect(),
189-
ar::GnuSymbolTableFormat::Size32,
190-
symbol_table,
191-
)
192-
.unwrap(),
193-
)
194-
} else {
195-
BuilderKind::Bsd(
196-
ar::Builder::new(
197-
File::create(output).unwrap_or_else(|err| {
198-
sess.fatal(&format!(
199-
"error opening destination during archive building: {}",
200-
err
201-
));
202-
}),
203-
symbol_table,
204-
)
205-
.unwrap(),
206-
)
207-
};
208-
209-
let any_members = !entries.is_empty();
210-
211-
// Add all files
212-
for (entry_name, data) in entries.into_iter() {
213-
let header = ar::Header::new(entry_name, data.len() as u64);
214-
match builder {
215-
BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
216-
BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
217-
}
218-
}
219-
220-
// Finalize archive
221-
std::mem::drop(builder);
222-
223-
if self.no_builtin_ranlib {
224-
let ranlib = crate::toolchain::get_toolchain_binary(self.sess, "ranlib");
225-
226-
// Run ranlib to be able to link the archive
227-
let status = std::process::Command::new(ranlib)
228-
.arg(output)
229-
.status()
230-
.expect("Couldn't run ranlib");
231-
232-
if !status.success() {
233-
self.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
234-
}
235-
}
236-
237-
any_members
23+
unimplemented!("creating dll imports is not yet supported");
23824
}
23925
}

0 commit comments

Comments
 (0)