diff --git a/psm/Cargo.toml b/psm/Cargo.toml index af561b3..30dc745 100644 --- a/psm/Cargo.toml +++ b/psm/Cargo.toml @@ -15,3 +15,4 @@ readme = "README.mkd" [build-dependencies] cc = "1.1.22" +ar_archive_writer = "0.2.0" diff --git a/psm/build.rs b/psm/build.rs index 1747466..1a5c7e7 100644 --- a/psm/build.rs +++ b/psm/build.rs @@ -110,10 +110,61 @@ fn main() { // directly to `ar` to assemble an archive. Otherwise we're actually // compiling the source assembly file. if asm.ends_with(".o") { - cfg.object(asm); + use ar_archive_writer::{write_archive_to_stream, NewArchiveMember, ArchiveKind}; + use std::fs::{read, metadata}; + use std::path::PathBuf; + use std::io::Cursor; + + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR environment variable not set"); + let output_path = PathBuf::from(&out_dir).join("libpsm_s.a"); + + let object_data = read(asm).expect("Failed to read object file"); + let file_metadata = metadata(asm).expect("Failed to read file metadata"); + + // Extract file metadata + let mtime = file_metadata.modified().ok() + .and_then(|time| time.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|duration| duration.as_secs()) + .unwrap_or(0); + + #[cfg(unix)] + let (uid, gid, perms) = { + use std::os::unix::fs::MetadataExt; + (file_metadata.uid(), file_metadata.gid(), file_metadata.mode()) + }; + + #[cfg(not(unix))] + let (uid, gid, perms) = (0, 0, 0o644); + + let filename = asm.rsplit('/').next().unwrap_or(asm); + let member = NewArchiveMember { + buf: Box::new(object_data), + get_symbols: |_data: &[u8], _callback: &mut dyn FnMut(&[u8]) -> Result<(), std::io::Error>| Ok(true), + member_name: filename.to_string(), + mtime, + uid, + gid, + perms, + }; + + let mut output_bytes = Cursor::new(Vec::new()); + write_archive_to_stream( + &mut output_bytes, + &[member], + // Unfortunately, getDefaultKind() is not available in ar_archive_writer + // however looking at the llvm-ar source it looks like for wasm32-any-any + // it falls through to Gnu https://llvm.org/doxygen/Object_2Archive_8cpp_source.html + ArchiveKind::Gnu, + false, + ).expect("Failed to write archive"); + + std::fs::write(&output_path, output_bytes.into_inner()).expect("Failed to write archive file"); + + println!("cargo:rustc-link-search=native={}", out_dir); + println!("cargo:rustc-link-lib=static=psm_s"); } else { cfg.file(asm); + cfg.compile("libpsm_s.a"); } - cfg.compile("libpsm_s.a"); -} +} \ No newline at end of file