Skip to content

Commit 748d516

Browse files
committed
Use builtin ranlib instead of running external ranlib
This makes it possible to create rlibs for any target without installing a toolchain for the target Fixes #763
1 parent 3e67eb1 commit 748d516

File tree

3 files changed

+79
-65
lines changed

3 files changed

+79
-65
lines changed

Cargo.lock

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

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ target-lexicon = "0.10.0"
1818
gimli = { version = "0.21.0", default-features = false, features = ["write"]}
1919
object = { version = "0.20.0", default-features = false, features = ["read", "std", "write"] }
2020

21-
ar = "0.8.0"
21+
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
2222
byteorder = "1.2.7"
2323
indexmap = "1.0.2"
2424
cfg-if = "0.1.10"

src/archive.rs

+77-62
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1+
use std::collections::BTreeMap;
12
use std::fs::File;
23
use std::path::{Path, PathBuf};
34

45
use rustc_session::Session;
56
use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
67
use rustc_codegen_ssa::METADATA_FILENAME;
78

9+
use object::{Object, SymbolKind};
10+
811
struct ArchiveConfig<'a> {
912
sess: &'a Session,
1013
dst: PathBuf,
1114
lib_search_paths: Vec<PathBuf>,
12-
use_native_ar: bool,
1315
use_gnu_style_archive: bool,
16+
no_builtin_ranlib: bool,
1417
}
1518

1619
#[derive(Debug)]
@@ -38,9 +41,9 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
3841
sess,
3942
dst: output.to_path_buf(),
4043
lib_search_paths: archive_search_paths(sess),
41-
use_native_ar: false,
42-
// FIXME test for linux and System V derivatives instead
4344
use_gnu_style_archive: sess.target.target.options.archive_format == "gnu",
45+
// FIXME fix builtin ranlib on macOS
46+
no_builtin_ranlib: sess.target.target.options.is_like_osx,
4447
};
4548

4649
let (src_archives, entries) = if let Some(input) = input {
@@ -141,85 +144,97 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
141144
}
142145

143146
fn build(mut self) {
144-
use std::process::Command;
145-
146-
fn add_file_using_ar(archive: &Path, file: &Path) {
147-
Command::new("ar")
148-
.arg("r") // add or replace file
149-
.arg("-c") // silence created file message
150-
.arg(archive)
151-
.arg(&file)
152-
.status()
153-
.unwrap();
154-
}
155-
156-
enum BuilderKind<'a> {
147+
enum BuilderKind {
157148
Bsd(ar::Builder<File>),
158149
Gnu(ar::GnuBuilder<File>),
159-
NativeAr(&'a Path),
160150
}
161151

162-
let mut builder = if self.config.use_native_ar {
163-
BuilderKind::NativeAr(&self.config.dst)
164-
} else if self.config.use_gnu_style_archive {
165-
BuilderKind::Gnu(ar::GnuBuilder::new(
166-
File::create(&self.config.dst).unwrap(),
167-
self.entries
168-
.iter()
169-
.map(|(name, _)| name.as_bytes().to_vec())
170-
.collect(),
171-
))
172-
} else {
173-
BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
174-
};
152+
let mut symbol_table = BTreeMap::new();
175153

176-
// Add all files
177-
for (entry_name, entry) in self.entries.into_iter() {
178-
match entry {
154+
let mut entries = Vec::new();
155+
156+
for (entry_name, entry) in self.entries {
157+
// FIXME only read the symbol table of the object files to avoid having to keep all
158+
// object files in memory at once, or read them twice.
159+
let data = match entry {
179160
ArchiveEntry::FromArchive {
180161
archive_index,
181162
entry_index,
182163
} => {
183-
let (ref src_archive_path, ref mut src_archive) =
164+
// FIXME read symbols from symtab
165+
use std::io::Read;
166+
let (ref _src_archive_path, ref mut src_archive) =
184167
self.src_archives[archive_index];
185-
let entry = src_archive.jump_to_entry(entry_index).unwrap();
186-
let header = entry.header().clone();
168+
let mut entry = src_archive.jump_to_entry(entry_index).unwrap();
169+
let mut data = Vec::new();
170+
entry.read_to_end(&mut data).unwrap();
171+
data
187172

188-
match builder {
189-
BuilderKind::Bsd(ref mut builder) => {
190-
builder.append(&header, entry).unwrap()
191-
}
192-
BuilderKind::Gnu(ref mut builder) => {
193-
builder.append(&header, entry).unwrap()
194-
}
195-
BuilderKind::NativeAr(archive_file) => {
196-
Command::new("ar")
197-
.arg("x")
198-
.arg(src_archive_path)
199-
.arg(&entry_name)
200-
.status()
201-
.unwrap();
202-
add_file_using_ar(archive_file, Path::new(&entry_name));
203-
std::fs::remove_file(entry_name).unwrap();
173+
}
174+
ArchiveEntry::File(file) => {
175+
std::fs::read(file).unwrap()
176+
}
177+
};
178+
179+
if !self.config.no_builtin_ranlib {
180+
match object::File::parse(&data) {
181+
Ok(object) => {
182+
symbol_table.insert(entry_name.as_bytes().to_vec(), object.symbols().filter_map(|(_index, symbol)| {
183+
if symbol.is_undefined() || symbol.is_local() || symbol.kind() != SymbolKind::Data && symbol.kind() != SymbolKind::Text && symbol.kind() != SymbolKind::Tls {
184+
None
185+
} else {
186+
symbol.name().map(|name| name.as_bytes().to_vec())
187+
}
188+
}).collect::<Vec<_>>());
189+
}
190+
Err(err) => {
191+
let err = err.to_string();
192+
if err == "Unknown file magic" {
193+
// Not an object file; skip it.
194+
} else {
195+
self.config.sess.fatal(&format!("Error parsing `{}` during archive creation: {}", entry_name, err));
204196
}
205197
}
206198
}
207-
ArchiveEntry::File(file) => match builder {
208-
BuilderKind::Bsd(ref mut builder) => builder
209-
.append_file(entry_name.as_bytes(), &mut File::open(file).unwrap())
210-
.unwrap(),
211-
BuilderKind::Gnu(ref mut builder) => builder
212-
.append_file(entry_name.as_bytes(), &mut File::open(file).unwrap())
213-
.unwrap(),
214-
BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file),
215-
},
199+
}
200+
201+
entries.push((entry_name, data));
202+
}
203+
204+
let mut builder = if self.config.use_gnu_style_archive {
205+
BuilderKind::Gnu(ar::GnuBuilder::new(
206+
File::create(&self.config.dst).unwrap(),
207+
entries
208+
.iter()
209+
.map(|(name, _)| name.as_bytes().to_vec())
210+
.collect(),
211+
ar::GnuSymbolTableFormat::Size32,
212+
symbol_table,
213+
).unwrap())
214+
} else {
215+
BuilderKind::Bsd(ar::Builder::new(
216+
File::create(&self.config.dst).unwrap(),
217+
symbol_table,
218+
).unwrap())
219+
};
220+
221+
// Add all files
222+
for (entry_name, data) in entries.into_iter() {
223+
let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
224+
match builder {
225+
BuilderKind::Bsd(ref mut builder) => builder
226+
.append(&header, &mut &*data)
227+
.unwrap(),
228+
BuilderKind::Gnu(ref mut builder) => builder
229+
.append(&header, &mut &*data)
230+
.unwrap(),
216231
}
217232
}
218233

219234
// Finalize archive
220235
std::mem::drop(builder);
221236

222-
if self.update_symbols {
237+
if self.config.no_builtin_ranlib {
223238
let ranlib = crate::toolchain::get_toolchain_binary(self.config.sess, "ranlib");
224239

225240
// Run ranlib to be able to link the archive

0 commit comments

Comments
 (0)