]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
1 | use std::fs::File; |
2 | use std::path::{Path, PathBuf}; | |
3 | ||
2b03887a FG |
4 | use crate::errors::RanlibFailure; |
5 | ||
064997fb | 6 | use rustc_codegen_ssa::back::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; |
c295e0f8 XL |
7 | use rustc_session::Session; |
8 | ||
c295e0f8 XL |
9 | use rustc_session::cstore::DllImport; |
10 | ||
11 | struct ArchiveConfig<'a> { | |
12 | sess: &'a Session, | |
c295e0f8 XL |
13 | use_native_ar: bool, |
14 | use_gnu_style_archive: bool, | |
15 | } | |
16 | ||
17 | #[derive(Debug)] | |
18 | enum ArchiveEntry { | |
19 | FromArchive { | |
20 | archive_index: usize, | |
21 | entry_index: usize, | |
22 | }, | |
23 | File(PathBuf), | |
24 | } | |
25 | ||
064997fb | 26 | pub struct ArArchiveBuilderBuilder; |
c295e0f8 | 27 | |
064997fb FG |
28 | impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { |
29 | fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a> { | |
c295e0f8 XL |
30 | let config = ArchiveConfig { |
31 | sess, | |
c295e0f8 XL |
32 | use_native_ar: false, |
33 | // FIXME test for linux and System V derivatives instead | |
34 | use_gnu_style_archive: sess.target.options.archive_format == "gnu", | |
35 | }; | |
36 | ||
064997fb | 37 | Box::new(ArArchiveBuilder { |
c295e0f8 | 38 | config, |
923072b8 FG |
39 | src_archives: vec![], |
40 | entries: vec![], | |
064997fb FG |
41 | }) |
42 | } | |
43 | ||
44 | fn create_dll_import_lib( | |
45 | &self, | |
46 | _sess: &Session, | |
47 | _lib_name: &str, | |
48 | _dll_imports: &[DllImport], | |
49 | _tmpdir: &Path, | |
f2b60f7d | 50 | _is_direct_dependency: bool, |
064997fb FG |
51 | ) -> PathBuf { |
52 | unimplemented!(); | |
c295e0f8 | 53 | } |
064997fb | 54 | } |
c295e0f8 | 55 | |
064997fb FG |
56 | pub struct ArArchiveBuilder<'a> { |
57 | config: ArchiveConfig<'a>, | |
58 | src_archives: Vec<(PathBuf, ar::Archive<File>)>, | |
59 | // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at | |
60 | // the end of an archive for linkers to not get confused. | |
61 | entries: Vec<(String, ArchiveEntry)>, | |
62 | } | |
63 | ||
64 | impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { | |
c295e0f8 XL |
65 | fn add_file(&mut self, file: &Path) { |
66 | self.entries.push(( | |
67 | file.file_name().unwrap().to_str().unwrap().to_string(), | |
68 | ArchiveEntry::File(file.to_owned()), | |
69 | )); | |
70 | } | |
71 | ||
064997fb FG |
72 | fn add_archive( |
73 | &mut self, | |
74 | archive_path: &Path, | |
75 | mut skip: Box<dyn FnMut(&str) -> bool + 'static>, | |
76 | ) -> std::io::Result<()> { | |
c295e0f8 XL |
77 | let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); |
78 | let archive_index = self.src_archives.len(); | |
79 | ||
80 | let mut i = 0; | |
81 | while let Some(entry) = archive.next_entry() { | |
82 | let entry = entry?; | |
83 | let file_name = String::from_utf8(entry.header().identifier().to_vec()) | |
84 | .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; | |
85 | if !skip(&file_name) { | |
86 | self.entries | |
87 | .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); | |
88 | } | |
89 | i += 1; | |
90 | } | |
91 | ||
92 | self.src_archives.push((archive_path.to_owned(), archive)); | |
93 | Ok(()) | |
94 | } | |
95 | ||
064997fb | 96 | fn build(mut self: Box<Self>, output: &Path) -> bool { |
c295e0f8 XL |
97 | use std::process::Command; |
98 | ||
99 | fn add_file_using_ar(archive: &Path, file: &Path) { | |
100 | Command::new("ar") | |
101 | .arg("r") // add or replace file | |
102 | .arg("-c") // silence created file message | |
103 | .arg(archive) | |
104 | .arg(&file) | |
105 | .status() | |
106 | .unwrap(); | |
107 | } | |
108 | ||
109 | enum BuilderKind<'a> { | |
110 | Bsd(ar::Builder<File>), | |
111 | Gnu(ar::GnuBuilder<File>), | |
112 | NativeAr(&'a Path), | |
113 | } | |
114 | ||
115 | let mut builder = if self.config.use_native_ar { | |
064997fb | 116 | BuilderKind::NativeAr(output) |
c295e0f8 XL |
117 | } else if self.config.use_gnu_style_archive { |
118 | BuilderKind::Gnu(ar::GnuBuilder::new( | |
064997fb | 119 | File::create(output).unwrap(), |
c295e0f8 XL |
120 | self.entries |
121 | .iter() | |
122 | .map(|(name, _)| name.as_bytes().to_vec()) | |
123 | .collect(), | |
124 | )) | |
125 | } else { | |
064997fb | 126 | BuilderKind::Bsd(ar::Builder::new(File::create(output).unwrap())) |
c295e0f8 XL |
127 | }; |
128 | ||
923072b8 FG |
129 | let any_members = !self.entries.is_empty(); |
130 | ||
c295e0f8 XL |
131 | // Add all files |
132 | for (entry_name, entry) in self.entries.into_iter() { | |
133 | match entry { | |
134 | ArchiveEntry::FromArchive { | |
135 | archive_index, | |
136 | entry_index, | |
137 | } => { | |
138 | let (ref src_archive_path, ref mut src_archive) = | |
139 | self.src_archives[archive_index]; | |
140 | let entry = src_archive.jump_to_entry(entry_index).unwrap(); | |
141 | let header = entry.header().clone(); | |
142 | ||
143 | match builder { | |
144 | BuilderKind::Bsd(ref mut builder) => { | |
145 | builder.append(&header, entry).unwrap() | |
146 | } | |
147 | BuilderKind::Gnu(ref mut builder) => { | |
148 | builder.append(&header, entry).unwrap() | |
149 | } | |
150 | BuilderKind::NativeAr(archive_file) => { | |
151 | Command::new("ar") | |
152 | .arg("x") | |
153 | .arg(src_archive_path) | |
154 | .arg(&entry_name) | |
155 | .status() | |
156 | .unwrap(); | |
157 | add_file_using_ar(archive_file, Path::new(&entry_name)); | |
158 | std::fs::remove_file(entry_name).unwrap(); | |
159 | } | |
160 | } | |
161 | } | |
162 | ArchiveEntry::File(file) => | |
163 | match builder { | |
164 | BuilderKind::Bsd(ref mut builder) => { | |
165 | builder | |
166 | .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder")) | |
167 | .unwrap() | |
168 | }, | |
169 | BuilderKind::Gnu(ref mut builder) => { | |
170 | builder | |
171 | .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file))) | |
172 | .unwrap() | |
173 | }, | |
174 | BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file), | |
175 | }, | |
176 | } | |
177 | } | |
178 | ||
179 | // Finalize archive | |
180 | std::mem::drop(builder); | |
181 | ||
182 | // Run ranlib to be able to link the archive | |
064997fb FG |
183 | let status = |
184 | std::process::Command::new("ranlib").arg(output).status().expect("Couldn't run ranlib"); | |
c295e0f8 XL |
185 | |
186 | if !status.success() { | |
2b03887a | 187 | self.config.sess.emit_fatal(RanlibFailure::new(status.code())); |
c295e0f8 | 188 | } |
923072b8 FG |
189 | |
190 | any_members | |
c295e0f8 | 191 | } |
c295e0f8 | 192 | } |