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