|
| 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,
|
14 | 16 | }
|
15 | 17 |
|
@@ -38,8 +40,6 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
|
38 | 40 | sess,
|
39 | 41 | dst: output.to_path_buf(),
|
40 | 42 | lib_search_paths: archive_search_paths(sess),
|
41 |
| - use_native_ar: false, |
42 |
| - // FIXME test for linux and System V derivatives instead |
43 | 43 | use_gnu_style_archive: sess.target.target.options.archive_format == "gnu",
|
44 | 44 | };
|
45 | 45 |
|
@@ -141,95 +141,88 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
|
141 | 141 | }
|
142 | 142 |
|
143 | 143 | 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 { |
157 | 145 | Bsd(ar::Builder<File>),
|
158 | 146 | Gnu(ar::GnuBuilder<File>),
|
159 |
| - NativeAr(&'a Path), |
160 | 147 | }
|
161 | 148 |
|
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(); |
175 | 150 |
|
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 { |
179 | 157 | ArchiveEntry::FromArchive {
|
180 | 158 | archive_index,
|
181 | 159 | entry_index,
|
182 | 160 | } => {
|
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) = |
184 | 164 | 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 |
187 | 169 |
|
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()) |
204 | 183 | }
|
| 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)); |
205 | 192 | }
|
206 | 193 | }
|
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 |
| - }, |
216 | 194 | }
|
217 |
| - } |
218 |
| - |
219 |
| - // Finalize archive |
220 |
| - std::mem::drop(builder); |
221 | 195 |
|
222 |
| - if self.update_symbols { |
223 |
| - let ranlib = crate::toolchain::get_toolchain_binary(self.config.sess, "ranlib"); |
| 196 | + entries.push((entry_name, data)); |
| 197 | + } |
224 | 198 |
|
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 | + }; |
230 | 215 |
|
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(), |
233 | 226 | }
|
234 | 227 | }
|
235 | 228 | }
|
|
0 commit comments