1 //! Creation of ar archives like for the lib and staticlib crate type
3 use std
::collections
::BTreeMap
;
5 use std
::io
::{self, Read, Seek}
;
6 use std
::path
::{Path, PathBuf}
;
8 use rustc_codegen_ssa
::back
::archive
::ArchiveBuilder
;
9 use rustc_session
::Session
;
11 use object
::read
::archive
::ArchiveFile
;
12 use object
::{Object, ObjectSymbol, ReadCache}
;
16 FromArchive { archive_index: usize, file_range: (u64, u64) }
,
20 pub(crate) struct ArArchiveBuilder
<'a
> {
23 use_gnu_style_archive
: bool
,
24 no_builtin_ranlib
: bool
,
26 src_archives
: Vec
<File
>,
27 // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
28 // the end of an archive for linkers to not get confused.
29 entries
: Vec
<(Vec
<u8>, ArchiveEntry
)>,
32 impl<'a
> ArchiveBuilder
<'a
> for ArArchiveBuilder
<'a
> {
33 fn new(sess
: &'a Session
, output
: &Path
, input
: Option
<&Path
>) -> Self {
34 let (src_archives
, entries
) = if let Some(input
) = input
{
35 let read_cache
= ReadCache
::new(File
::open(input
).unwrap());
36 let archive
= ArchiveFile
::parse(&read_cache
).unwrap();
37 let mut entries
= Vec
::new();
39 for entry
in archive
.members() {
40 let entry
= entry
.unwrap();
42 entry
.name().to_vec(),
43 ArchiveEntry
::FromArchive { archive_index: 0, file_range: entry.file_range() }
,
47 (vec
![read_cache
.into_inner()], entries
)
54 dst
: output
.to_path_buf(),
55 use_gnu_style_archive
: sess
.target
.archive_format
== "gnu",
56 // FIXME fix builtin ranlib on macOS
57 no_builtin_ranlib
: sess
.target
.is_like_osx
,
64 fn src_files(&mut self) -> Vec
<String
> {
65 self.entries
.iter().map(|(name
, _
)| String
::from_utf8(name
.clone()).unwrap()).collect()
68 fn remove_file(&mut self, name
: &str) {
72 .position(|(entry_name
, _
)| entry_name
== name
.as_bytes())
73 .expect("Tried to remove file not existing in src archive");
74 self.entries
.remove(index
);
77 fn add_file(&mut self, file
: &Path
) {
79 file
.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
80 ArchiveEntry
::File(file
.to_owned()),
84 fn add_archive
<F
>(&mut self, archive_path
: &Path
, mut skip
: F
) -> std
::io
::Result
<()>
86 F
: FnMut(&str) -> bool
+ '
static,
88 let read_cache
= ReadCache
::new(std
::fs
::File
::open(&archive_path
)?
);
89 let archive
= ArchiveFile
::parse(&read_cache
).unwrap();
90 let archive_index
= self.src_archives
.len();
92 for entry
in archive
.members() {
93 let entry
= entry
.map_err(|err
| io
::Error
::new(io
::ErrorKind
::InvalidData
, err
))?
;
94 let file_name
= String
::from_utf8(entry
.name().to_vec())
95 .map_err(|err
| io
::Error
::new(io
::ErrorKind
::InvalidData
, err
))?
;
96 if !skip(&file_name
) {
98 file_name
.into_bytes(),
99 ArchiveEntry
::FromArchive { archive_index, file_range: entry.file_range() }
,
104 self.src_archives
.push(read_cache
.into_inner());
110 Bsd(ar
::Builder
<File
>),
111 Gnu(ar
::GnuBuilder
<File
>),
114 let sess
= self.sess
;
116 let mut symbol_table
= BTreeMap
::new();
118 let mut entries
= Vec
::new();
120 for (entry_name
, entry
) in self.entries
{
121 // FIXME only read the symbol table of the object files to avoid having to keep all
122 // object files in memory at once, or read them twice.
123 let data
= match entry
{
124 ArchiveEntry
::FromArchive { archive_index, file_range }
=> {
125 // FIXME read symbols from symtab
126 let src_read_cache
= &mut self.src_archives
[archive_index
];
128 src_read_cache
.seek(io
::SeekFrom
::Start(file_range
.0)).unwrap();
129 let mut data
= std
::vec
::from_elem(0, usize::try_from(file_range
.1).unwrap());
130 src_read_cache
.read_exact(&mut data
).unwrap();
134 ArchiveEntry
::File(file
) => std
::fs
::read(file
).unwrap_or_else(|err
| {
136 "error while reading object file during archive building: {}",
142 if !self.no_builtin_ranlib
{
143 match object
::File
::parse(&*data
) {
149 .filter_map(|symbol
| {
150 if symbol
.is_undefined() || symbol
.is_local() {
153 symbol
.name().map(|name
| name
.as_bytes().to_vec()).ok()
156 .collect
::<Vec
<_
>>(),
160 let err
= err
.to_string();
161 if err
== "Unknown file magic" {
162 // Not an object file; skip it.
165 "error parsing `{}` during archive creation: {}",
166 String
::from_utf8_lossy(&entry_name
),
174 entries
.push((entry_name
, data
));
177 let mut builder
= if self.use_gnu_style_archive
{
180 File
::create(&self.dst
).unwrap_or_else(|err
| {
182 "error opening destination during archive building: {}",
186 entries
.iter().map(|(name
, _
)| name
.clone()).collect(),
187 ar
::GnuSymbolTableFormat
::Size32
,
195 File
::create(&self.dst
).unwrap_or_else(|err
| {
197 "error opening destination during archive building: {}",
208 for (entry_name
, data
) in entries
.into_iter() {
209 let header
= ar
::Header
::new(entry_name
, data
.len() as u64);
211 BuilderKind
::Bsd(ref mut builder
) => builder
.append(&header
, &mut &*data
).unwrap(),
212 BuilderKind
::Gnu(ref mut builder
) => builder
.append(&header
, &mut &*data
).unwrap(),
217 std
::mem
::drop(builder
);
219 if self.no_builtin_ranlib
{
220 let ranlib
= crate::toolchain
::get_toolchain_binary(self.sess
, "ranlib");
222 // Run ranlib to be able to link the archive
223 let status
= std
::process
::Command
::new(ranlib
)
226 .expect("Couldn't run ranlib");
228 if !status
.success() {
229 self.sess
.fatal(&format
!("Ranlib exited with code {:?}", status
.code()));
234 fn inject_dll_import_lib(
237 _dll_imports
: &[rustc_session
::cstore
::DllImport
],
238 _tmpdir
: &rustc_data_structures
::temp_dir
::MaybeTempDir
,
240 bug
!("injecting dll imports is not supported");