main.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. use std::fs;
  2. use std::path::PathBuf;
  3. use std::process::Command;
  4. use std::result::Result;
  5. use structopt::StructOpt;
  6. use ar::Archive;
  7. use std::fs::File;
  8. use std::io;
  9. #[derive(Debug, StructOpt)]
  10. #[structopt(name = "Localize", about = "Localize a static library into a single object archive")]
  11. struct LocalizeArgs
  12. {
  13. /// list of file to merge
  14. #[structopt(name = "FILE LIST", short = "i", long = "inputs")]
  15. input_files: Vec<PathBuf>,
  16. /// filename of the final library archive
  17. #[structopt(name = "OUT FILE", short = "o", long = "output")]
  18. output_file: PathBuf,
  19. }
  20. fn extract(input: PathBuf, output_directory: PathBuf)
  21. -> Result<Vec<PathBuf>, ()>
  22. {
  23. println!("Extracting {:?} into {:?}", input, output_directory);
  24. let input_file = File::open(input)
  25. .map_err(|_| ())?;
  26. let mut file_list : Vec<PathBuf> = vec![];
  27. let mut archive = Archive::new(input_file);
  28. while let Some(entry_result) = archive.next_entry()
  29. {
  30. let mut entry = entry_result.unwrap();
  31. let identifier = std::str::from_utf8(
  32. entry.header().identifier()).unwrap();
  33. let mut output_filename = output_directory.clone();
  34. output_filename.push(identifier);
  35. println!(" - {:?}", output_filename);
  36. let mut file = File::create(&output_filename)
  37. .unwrap();
  38. file_list.push(output_filename);
  39. io::copy(&mut entry, &mut file)
  40. .map_err(|_| ())?;
  41. }
  42. Ok(file_list)
  43. }
  44. fn link_partial(inputs: Vec<PathBuf>, output: &PathBuf)
  45. -> Result<(), ()>
  46. {
  47. Command::new("ld")
  48. // Enable partial linking
  49. .arg("-r")
  50. .arg("-o")
  51. .arg(&output)
  52. .args(&inputs)
  53. .output()
  54. .unwrap();
  55. Ok(())
  56. }
  57. fn localize_hidden(input: &PathBuf)
  58. {
  59. /* On MacOSX, check
  60. * -[un|re]exported_symbols_list
  61. * -[un]exported_symbol
  62. * See
  63. * https://developer.apple.com/library/archive/technotes/tn2185/_index.html#//apple_ref/doc/uid/DTS10004200-CH1-SUBSECTION5
  64. * */
  65. Command::new("objcopy")
  66. .arg("--localize-hidden")
  67. .arg("--strip-unneeded")
  68. .arg(&input)
  69. .output()
  70. .unwrap();
  71. }
  72. fn link(args: LocalizeArgs)
  73. {
  74. let output_dir = "./output_dir/";
  75. // TODO: the output directory might already exist
  76. fs::create_dir(output_dir)
  77. .expect("Cannot create output directory");
  78. let input = fs::canonicalize(args.input_files[0].clone())
  79. .expect("Input path is invalid");
  80. extract(input, PathBuf::from(&output_dir))
  81. .expect("Cannot extract library archive");
  82. println!("Archive objects successfully extracted");
  83. // TODO list files
  84. let files = vec![
  85. fs::canonicalize("./output_dir/lib1.o").unwrap(),
  86. fs::canonicalize("./output_dir/lib2.o").unwrap() ];
  87. let output = args.output_file; //fs::canonicalize(args.output_file).unwrap();
  88. link_partial(files, &output);
  89. localize_hidden(&output);
  90. }
  91. fn main() {
  92. let opt = LocalizeArgs::from_args();
  93. println!("{:?}", opt);
  94. link(opt);
  95. }