Skip to content

Commit 80b6f47

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 Fixes #869
1 parent 3e67eb1 commit 80b6f47

File tree

3 files changed

+69
-77
lines changed

3 files changed

+69
-77
lines changed

Diff for: Cargo.lock

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

Diff for: 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"

Diff for: src/archive.rs

+67-74
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
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,
1416
}
1517

@@ -38,8 +40,6 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
3840
sess,
3941
dst: output.to_path_buf(),
4042
lib_search_paths: archive_search_paths(sess),
41-
use_native_ar: false,
42-
// FIXME test for linux and System V derivatives instead
4343
use_gnu_style_archive: sess.target.target.options.archive_format == "gnu",
4444
};
4545

@@ -141,95 +141,88 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
141141
}
142142

143143
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> {
144+
enum BuilderKind {
157145
Bsd(ar::Builder<File>),
158146
Gnu(ar::GnuBuilder<File>),
159-
NativeAr(&'a Path),
160147
}
161148

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-
};
149+
let mut symbol_table = BTreeMap::new();
175150

176-
// Add all files
177-
for (entry_name, entry) in self.entries.into_iter() {
178-
match entry {
151+
let mut entries = Vec::new();
152+
153+
for (entry_name, entry) in self.entries {
154+
// FIXME only read the symbol table of the object files to avoid having to keep all
155+
// object files in memory at once, or read them twice.
156+
let data = match entry {
179157
ArchiveEntry::FromArchive {
180158
archive_index,
181159
entry_index,
182160
} => {
183-
let (ref src_archive_path, ref mut src_archive) =
161+
// FIXME read symbols from symtab
162+
use std::io::Read;
163+
let (ref _src_archive_path, ref mut src_archive) =
184164
self.src_archives[archive_index];
185-
let entry = src_archive.jump_to_entry(entry_index).unwrap();
186-
let header = entry.header().clone();
165+
let mut entry = src_archive.jump_to_entry(entry_index).unwrap();
166+
let mut data = Vec::new();
167+
entry.read_to_end(&mut data).unwrap();
168+
data
187169

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();
170+
}
171+
ArchiveEntry::File(file) => {
172+
std::fs::read(file).unwrap()
173+
}
174+
};
175+
176+
match object::File::parse(&data) {
177+
Ok(object) => {
178+
symbol_table.insert(entry_name.as_bytes().to_vec(), object.symbols().filter_map(|(_index, symbol)| {
179+
if symbol.is_undefined() || symbol.is_local() || symbol.kind() != SymbolKind::Data && symbol.kind() != SymbolKind::Text && symbol.kind() != SymbolKind::Tls {
180+
None
181+
} else {
182+
symbol.name().map(|name| name.as_bytes().to_vec())
204183
}
184+
}).collect::<Vec<_>>());
185+
}
186+
Err(err) => {
187+
let err = err.to_string();
188+
if err == "Unknown file magic" {
189+
// Not an object file; skip it.
190+
} else {
191+
self.config.sess.fatal(&format!("Error parsing `{}` during archive creation: {}", entry_name, err));
205192
}
206193
}
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-
},
216194
}
217-
}
218-
219-
// Finalize archive
220-
std::mem::drop(builder);
221195

222-
if self.update_symbols {
223-
let ranlib = crate::toolchain::get_toolchain_binary(self.config.sess, "ranlib");
196+
entries.push((entry_name, data));
197+
}
224198

225-
// Run ranlib to be able to link the archive
226-
let status = std::process::Command::new(ranlib)
227-
.arg(self.config.dst)
228-
.status()
229-
.expect("Couldn't run ranlib");
199+
let mut builder = if self.config.use_gnu_style_archive {
200+
BuilderKind::Gnu(ar::GnuBuilder::new(
201+
File::create(&self.config.dst).unwrap(),
202+
entries
203+
.iter()
204+
.map(|(name, _)| name.as_bytes().to_vec())
205+
.collect(),
206+
ar::GnuSymbolTableFormat::Size32,
207+
symbol_table,
208+
).unwrap())
209+
} else {
210+
BuilderKind::Bsd(ar::Builder::new(
211+
File::create(&self.config.dst).unwrap(),
212+
symbol_table,
213+
).unwrap())
214+
};
230215

231-
if !status.success() {
232-
self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
216+
// Add all files
217+
for (entry_name, data) in entries.into_iter() {
218+
let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
219+
match builder {
220+
BuilderKind::Bsd(ref mut builder) => builder
221+
.append(&header, &mut &*data)
222+
.unwrap(),
223+
BuilderKind::Gnu(ref mut builder) => builder
224+
.append(&header, &mut &*data)
225+
.unwrap(),
233226
}
234227
}
235228
}

0 commit comments

Comments
 (0)