use std::fs;
use std::path::{Path, PathBuf};
use ver_shim::SECTION_NAME;
use crate::LinkSection;
use crate::cargo_helpers::{self, cargo_rerun_if, cargo_warning};
use crate::llvm_tools::LlvmTools;
#[must_use]
pub struct UpdateSectionCommand {
pub(crate) link_section: LinkSection,
pub(crate) bin_path: PathBuf,
pub(crate) new_name: Option<String>,
}
impl UpdateSectionCommand {
pub fn with_filename(mut self, name: &str) -> Self {
self.new_name = Some(name.to_string());
self
}
pub fn write_to(self, path: impl AsRef<Path>) {
eprintln!("ver-shim-build: input binary = {}", self.bin_path.display());
cargo_rerun_if(&format!("changed={}", self.bin_path.display()));
let path = path.as_ref();
let output_path = if path.is_dir() {
let original_name = self
.bin_path
.file_name()
.and_then(|s| s.to_str())
.unwrap_or("output");
let default_name = format!("{}.bin", original_name);
let output_name = self.new_name.as_deref().unwrap_or(&default_name);
path.join(output_name)
} else {
if self.new_name.is_some() {
panic!(
"ver-shim-build: with_filename() cannot be used when write_to() \
is called with a file path (not a directory): {}",
path.display()
);
}
path.to_path_buf()
};
let llvm = LlvmTools::new().unwrap_or_else(|e| {
panic!(
"ver-shim-build: could not find LLVM tools directory: {}\n\
Please install llvm-tools: rustup component add llvm-tools",
e
)
});
let section_size = llvm
.get_section_size(&self.bin_path, SECTION_NAME)
.unwrap_or_else(|e| {
panic!(
"ver-shim-build: failed to read section info from {}: {}",
self.bin_path.display(),
e
)
});
match section_size {
Some(size) => {
let section_bytes = self
.link_section
.with_buffer_size(size)
.build_section_bytes();
llvm.update_section_with_bytes(
&self.bin_path,
&output_path,
SECTION_NAME,
§ion_bytes,
)
.unwrap_or_else(|e| {
panic!(
"ver-shim-build: failed to update section in {}: {}",
self.bin_path.display(),
e
)
});
eprintln!(
"ver-shim-build: wrote patched binary to {}",
output_path.display()
);
}
None => {
cargo_warning(&format!(
"section '{}' not found in {}, copying without modification",
SECTION_NAME,
self.bin_path.display()
));
fs::copy(&self.bin_path, &output_path).unwrap_or_else(|e| {
panic!(
"ver-shim-build: failed to copy {} to {}: {}",
self.bin_path.display(),
output_path.display(),
e
)
});
eprintln!("ver-shim-build: copied to {}", output_path.display());
}
}
}
pub fn write_to_target_profile_dir(self) {
let target_dir = cargo_helpers::target_profile_dir();
self.write_to(target_dir);
}
}