|
| 1 | +use std::collections::BTreeMap; |
1 | 2 | use std::fs::File;
|
2 | 3 | use std::path::{Path, PathBuf};
|
3 | 4 |
|
4 | 5 | use rustc_session::Session;
|
5 | 6 | use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
|
6 | 7 | use rustc_codegen_ssa::METADATA_FILENAME;
|
7 | 8 |
|
| 9 | +use object::{Object, SymbolKind}; |
| 10 | + |
8 | 11 | struct ArchiveConfig<'a> {
|
9 | 12 | sess: &'a Session,
|
10 | 13 | dst: PathBuf,
|
11 | 14 | lib_search_paths: Vec<PathBuf>,
|
12 |
| - use_native_ar: bool, |
13 | 15 | use_gnu_style_archive: bool,
|
| 16 | + no_builtin_ranlib: bool, |
14 | 17 | }
|
15 | 18 |
|
16 | 19 | #[derive(Debug)]
|
@@ -38,9 +41,9 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
|
38 | 41 | sess,
|
39 | 42 | dst: output.to_path_buf(),
|
40 | 43 | lib_search_paths: archive_search_paths(sess),
|
41 |
| - use_native_ar: false, |
42 |
| - // FIXME test for linux and System V derivatives instead |
43 | 44 | 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, |
44 | 47 | };
|
45 | 48 |
|
46 | 49 | let (src_archives, entries) = if let Some(input) = input {
|
@@ -141,85 +144,97 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
|
141 | 144 | }
|
142 | 145 |
|
143 | 146 | 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 { |
157 | 148 | Bsd(ar::Builder<File>),
|
158 | 149 | Gnu(ar::GnuBuilder<File>),
|
159 |
| - NativeAr(&'a Path), |
160 | 150 | }
|
161 | 151 |
|
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(); |
175 | 153 |
|
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 { |
179 | 160 | ArchiveEntry::FromArchive {
|
180 | 161 | archive_index,
|
181 | 162 | entry_index,
|
182 | 163 | } => {
|
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) = |
184 | 167 | 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 |
187 | 172 |
|
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)); |
204 | 196 | }
|
205 | 197 | }
|
206 | 198 | }
|
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(), |
216 | 231 | }
|
217 | 232 | }
|
218 | 233 |
|
219 | 234 | // Finalize archive
|
220 | 235 | std::mem::drop(builder);
|
221 | 236 |
|
222 |
| - if self.update_symbols { |
| 237 | + if self.config.no_builtin_ranlib { |
223 | 238 | let ranlib = crate::toolchain::get_toolchain_binary(self.config.sess, "ranlib");
|
224 | 239 |
|
225 | 240 | // Run ranlib to be able to link the archive
|
|
0 commit comments