Skip to content

Commit be67084

Browse files
committed
Rewrite LLVM's archive writer in Rust
This allows it to be used by other codegen backends
1 parent c3a1c02 commit be67084

File tree

24 files changed

+445
-527
lines changed

24 files changed

+445
-527
lines changed

Cargo.lock

+10
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ version = "1.0.65"
9292
source = "registry+https://github.com/rust-lang/crates.io-index"
9393
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
9494

95+
[[package]]
96+
name = "ar_archive_writer"
97+
version = "0.1.1"
98+
source = "registry+https://github.com/rust-lang/crates.io-index"
99+
checksum = "276881980556fdadeb88aa1ffc667e4d2e8fe72531dfabcb7a82bb3c9ea9ba31"
100+
dependencies = [
101+
"object",
102+
]
103+
95104
[[package]]
96105
name = "array_tool"
97106
version = "1.0.3"
@@ -3413,6 +3422,7 @@ dependencies = [
34133422
name = "rustc_codegen_ssa"
34143423
version = "0.0.0"
34153424
dependencies = [
3425+
"ar_archive_writer",
34163426
"bitflags",
34173427
"cc",
34183428
"itertools",

LICENSES/LLVM-exception.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---- LLVM Exceptions to the Apache 2.0 License ----
2+
3+
As an exception, if, as a result of your compiling your source code, portions
4+
of this Software are embedded into an Object form of such source code, you
5+
may redistribute such embedded portions in such Object form without complying
6+
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
7+
8+
In addition, if you combine or link compiled forms of this Software with
9+
software that is licensed under the GPLv2 ("Combined Software") and if a
10+
court of competent jurisdiction determines that the patent provision (Section
11+
3), the indemnity provision (Section 9) or other Section of the License
12+
conflicts with the conditions of the GPLv2, you may retroactively and
13+
prospectively choose to deem waived or otherwise exclude such Section(s) of
14+
the License, but only in their entirety and only with respect to the Combined
15+
Software.

compiler/rustc_codegen_cranelift/Cargo.lock

-6
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@ version = "1.0.60"
1919
source = "registry+https://github.com/rust-lang/crates.io-index"
2020
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
2121

22-
[[package]]
23-
name = "ar"
24-
version = "0.8.0"
25-
source = "git+https://github.com/bjorn3/rust-ar.git?branch=do_not_remove_cg_clif_ranlib#de9ab0e56bf3a208381d342aa5b60f9ff2891648"
26-
2722
[[package]]
2823
name = "arrayvec"
2924
version = "0.7.2"
@@ -324,7 +319,6 @@ dependencies = [
324319
name = "rustc_codegen_cranelift"
325320
version = "0.1.0"
326321
dependencies = [
327-
"ar",
328322
"cranelift-codegen",
329323
"cranelift-frontend",
330324
"cranelift-jit",

compiler/rustc_codegen_cranelift/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"
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
}

compiler/rustc_codegen_gcc/Cargo.lock

-14
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ dependencies = [
1111
"memchr",
1212
]
1313

14-
[[package]]
15-
name = "ar"
16-
version = "0.8.0"
17-
source = "registry+https://github.com/rust-lang/crates.io-index"
18-
checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1"
19-
2014
[[package]]
2115
name = "bitflags"
2216
version = "1.3.2"
@@ -212,10 +206,8 @@ dependencies = [
212206
name = "rustc_codegen_gcc"
213207
version = "0.1.0"
214208
dependencies = [
215-
"ar",
216209
"gccjit",
217210
"lang_tester",
218-
"target-lexicon",
219211
"tempfile",
220212
]
221213

@@ -228,12 +220,6 @@ dependencies = [
228220
"winapi-util",
229221
]
230222

231-
[[package]]
232-
name = "target-lexicon"
233-
version = "0.10.0"
234-
source = "registry+https://github.com/rust-lang/crates.io-index"
235-
checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
236-
237223
[[package]]
238224
name = "tempfile"
239225
version = "3.2.0"

compiler/rustc_codegen_gcc/Cargo.toml

-4
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
2727
# Local copy.
2828
#gccjit = { path = "../gccjit.rs" }
2929

30-
target-lexicon = "0.10.0"
31-
32-
ar = "0.8.0"
33-
3430
[dev-dependencies]
3531
lang_tester = "0.3.9"
3632
tempfile = "3.1.0"

0 commit comments

Comments
 (0)