Skip to content

Separate library from CLI #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
390 changes: 101 additions & 289 deletions Cargo.lock

Large diffs are not rendered by default.

44 changes: 9 additions & 35 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,36 +1,10 @@
[package]
name = "armerge"
version = "2.2.0"
authors = ["tux3 <[email protected]>"]
edition = "2021"
rust-version = "1.74"
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/tux3/armerge/"
categories = ["command-line-utilities", "development-tools::build-utils"]
description = "Tool to merge and control visibility of static libraries"
[workspace]
resolver = "2"
members = [
"armerge",
"armerge-cli",
]

[dependencies]
objpoke = "0.3"
clap = { version = "4.5.30", features = ["derive"] }
ar = "0.9"
tempfile = "3.3.0"
rand = "0.8"
object = "0.36.5"
goblin = "0.9.2"
regex = "1.3.9"
rayon = "1.4.0"
thiserror = "2.0.8"
tracing = "0.1.35"
tracing-subscriber = { version = "0.3.14", features = ["env-filter", "local-time"], optional = true }
time = { version = "0.3.11", optional = true }

[[bin]]
name = "armerge"
required-features = ["log_subscriber"]

[features]
default = ["log_subscriber"]
# EXPERIMENTAL. Uses objpoke instead of objcopy for localizing ELF symbols in-place. Very fast, but not stable for production use.
objpoke_symbols = []
log_subscriber = ["dep:tracing-subscriber", "dep:time"]
[workspace.dependencies]
tracing = "0.1.41"
regex = "1.11.1"
25 changes: 25 additions & 0 deletions armerge-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "armerge-cli"
version = "2.2.0"
authors = ["tux3 <[email protected]>"]
edition = "2021"
rust-version = "1.74"
license = "MIT OR Apache-2.0"
readme = "../README.md"
repository = "https://github.com/tux3/armerge/"
categories = ["command-line-utilities", "development-tools::build-utils"]
description = "Tool to merge and control visibility of static libraries"

[[bin]]
name = "armerge"
path = "src/main.rs"

[dependencies]
armerge = { path = "../armerge" }

tracing = { workspace = true }
regex = { workspace = true }

clap = { version = "4.5.31", features = ["derive"] }
tracing-subscriber = { version = "0.3.19", features = ["env-filter", "time"] }
time = { version = "0.3.39", features = ["formatting"] }
44 changes: 21 additions & 23 deletions src/main.rs → armerge-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use armerge::{ArmergeKeepOrRemove, ArMerger};
use regex::Regex;
use std::error::Error;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use armerge::{ArMerger, ArmergeKeepOrRemove};
use clap::Parser;
use regex::Regex;
use std::{
error::Error,
fs::File,
io::{BufRead, BufReader},
path::{Path, PathBuf},
};
use tracing::{error, Level};
use tracing_subscriber::filter::Directive;
use tracing_subscriber::fmt::time::UtcTime;
use tracing_subscriber::{filter::Directive, fmt::time::UtcTime};

#[derive(Parser, Debug)]
#[command(version, about)]
Expand Down Expand Up @@ -37,20 +38,13 @@ struct Opt {
}

fn main() {
if std::env::var("RUST_LIB_BACKTRACE").is_err() {
std::env::set_var("RUST_LIB_BACKTRACE", "1")
}
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "warn")
}

let opt = Opt::parse();
let mut filter = tracing_subscriber::EnvFilter::from_default_env();
if opt.verbose {
filter = filter.add_directive(Directive::from(Level::INFO));
}
let filter = tracing_subscriber::EnvFilter::builder()
.with_default_directive(Directive::from(if opt.verbose { Level::INFO } else { Level::WARN }))
.from_env_lossy();

let time_format = time::format_description::parse("[hour]:[minute]:[second]").unwrap();
tracing_subscriber::fmt::fmt()
tracing_subscriber::fmt()
.with_timer(UtcTime::new(time_format))
.with_env_filter(filter)
.init();
Expand Down Expand Up @@ -96,8 +90,12 @@ fn err_main(opt: Opt) -> Result<(), Box<dyn Error>> {
merger.merge_and_localize_ordered(ArmergeKeepOrRemove::RemoveSymbols, remove_symbols, object_order)?;
},
(false, false) => {
return Err("Can't have both keep-symbols and remove-symbols options at the same time".to_string().into());
}
return Err(
"Can't have both keep-symbols and remove-symbols options at the same time"
.to_string()
.into(),
);
},
}

Ok(())
Expand All @@ -109,4 +107,4 @@ fn parse_order_file(path: &Path) -> Vec<String> {
.map(|line| line.unwrap().trim().to_string())
.filter(|line| !line.is_empty() && !line.starts_with('#'))
.collect()
}
}
29 changes: 29 additions & 0 deletions armerge/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "armerge"
version = "2.2.0"
authors = ["tux3 <[email protected]>"]
edition = "2021"
rust-version = "1.74"
license = "MIT OR Apache-2.0"
readme = "../README.md"
repository = "https://github.com/tux3/armerge/"
categories = ["command-line-utilities", "development-tools::build-utils"]
description = "Tool to merge and control visibility of static libraries"

[dependencies]
objpoke = { git = "https://github.com/dice-group/objpoke", rev = "c43ab668dafcb4bfbd7c16a0dd654ee759d7fbb3" }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not supposed to stay this way. Here I would like to point to a new objpoke release


tracing = { workspace = true }
regex = { workspace = true }

ar = "0.9"
tempfile = "3.18.0"
rand = "0.9"
object = "0.36.5"
goblin = "0.9.2"
rayon = "1.10.0"
thiserror = "2.0.12"

[features]
# EXPERIMENTAL. Uses objpoke instead of objcopy for localizing ELF symbols in-place. Very fast, but not stable for production use.
objpoke_symbols = []
3 changes: 1 addition & 2 deletions src/arbuilder.rs → armerge/src/arbuilder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::MergeError;
use std::fmt::Debug;
use std::path::Path;
use std::{fmt::Debug, path::Path};

pub mod common;
pub mod mac;
Expand Down
15 changes: 7 additions & 8 deletions src/arbuilder/common.rs → armerge/src/arbuilder/common.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::arbuilder::ArBuilder;
use crate::{archives, MergeError};
use crate::{arbuilder::ArBuilder, archives, MergeError};
use ar::Builder;
use std::fmt::{Debug, Formatter};
use std::fs::File;
use std::path::{Path, PathBuf};
use std::{
fmt::{Debug, Formatter},
fs::File,
path::{Path, PathBuf},
};

pub struct CommonArBuilder {
builder: Builder<File>,
Expand All @@ -22,9 +23,7 @@ impl Debug for CommonArBuilder {

impl ArBuilder for CommonArBuilder {
fn append_obj(&mut self, path: &Path) -> Result<(), MergeError> {
self.builder
.append_path(path)
.map_err(MergeError::WritingArchive)?;
self.builder.append_path(path).map_err(MergeError::WritingArchive)?;
Ok(())
}

Expand Down
35 changes: 12 additions & 23 deletions src/arbuilder/mac.rs → armerge/src/arbuilder/mac.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::arbuilder::ArBuilder;
use crate::MergeError;
use crate::MergeError::ExternalToolLaunchError;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::Command;
use crate::{arbuilder::ArBuilder, MergeError, MergeError::ExternalToolLaunchError};
use std::{
ffi::OsString,
path::{Path, PathBuf},
process::Command,
};
use tracing::info;

#[derive(Debug)]
Expand All @@ -26,11 +26,7 @@ impl ArBuilder for MacArBuilder {

impl MacArBuilder {
pub fn new(path: &Path) -> Self {
Self {
output_path: path.to_owned(),
obj_paths: vec![],
closed: false,
}
Self { output_path: path.to_owned(), obj_paths: vec![], closed: false }
}

fn write_obj(&mut self) -> Result<(), MergeError> {
Expand All @@ -56,20 +52,13 @@ impl MacArBuilder {
info!(
"Merging {} objects: libtool {}",
count,
args.iter()
.map(|s| s.to_string_lossy())
.collect::<Vec<_>>()
.join(" ")
args.iter().map(|s| s.to_string_lossy()).collect::<Vec<_>>().join(" ")
);

let output =
Command::new("libtool")
.args(&args)
.output()
.map_err(|e| ExternalToolLaunchError {
tool: "libtool".to_string(),
inner: e,
})?;
let output = Command::new("libtool")
.args(&args)
.output()
.map_err(|e| ExternalToolLaunchError { tool: "libtool".to_string(), inner: e })?;
if output.status.success() {
Ok(())
} else {
Expand Down
78 changes: 26 additions & 52 deletions src/archives.rs → armerge/src/archives.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use crate::arbuilder::ArBuilder;
use crate::input_library::InputLibrary;
use crate::objects::ObjectTempDir;
use crate::MergeError::ExternalToolLaunchError;
use crate::{MergeError, ProcessInputError};
use crate::{
arbuilder::ArBuilder, input_library::InputLibrary, objects::ObjectTempDir, MergeError,
MergeError::ExternalToolLaunchError, ProcessInputError,
};
use ar::Archive;
use goblin::{peek_bytes, Hint};
use rand::distributions::{Alphanumeric, DistString};
use rand::thread_rng;
use rand::distr::{Alphanumeric, SampleString};
use rayon::prelude::*;
use std::ffi::OsString;
use std::fmt::{Debug, Formatter};
use std::fs::File;
use std::io::{Read, Write};
use std::str::FromStr;
use tracing::info;
use std::{
ffi::OsString,
fmt::{Debug, Formatter},
fs::File,
io::{Read, Write},
str::FromStr,
};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ArchiveContents {
Expand Down Expand Up @@ -85,13 +84,10 @@ pub fn extract_objects<I: IntoParallelIterator<Item = InputLibrary<R>>, R: Read>
|(mut objects, mut archive_contents), input_lib| {
let mut archive = Archive::new(input_lib.reader);
while let Some(entry_result) = archive.next_entry() {
let mut entry =
entry_result.map_err(|e| ProcessInputError::ReadingArchive {
name: input_lib.name.clone(),
inner: e,
})?;
let mut entry = entry_result
.map_err(|e| ProcessInputError::ReadingArchive { name: input_lib.name.clone(), inner: e })?;

let rnd: String = Alphanumeric.sample_string(&mut thread_rng(), 8);
let rnd: String = Alphanumeric.sample_string(&mut rand::rng(), 8);
let mut obj_path = dir.path().to_owned();
obj_path.push(format!(
"{}@{}.{}.o",
Expand All @@ -101,33 +97,18 @@ pub fn extract_objects<I: IntoParallelIterator<Item = InputLibrary<R>>, R: Read>
));

let hint_bytes = &mut [0u8; 16];
entry.read_exact(hint_bytes).map_err(|e| {
ProcessInputError::ReadingArchive {
name: input_lib.name.clone(),
inner: e,
}
})?;
entry
.read_exact(hint_bytes)
.map_err(|e| ProcessInputError::ReadingArchive { name: input_lib.name.clone(), inner: e })?;
let obj_type = archive_object_type(hint_bytes);
archive_contents = ArchiveContents::merge(archive_contents, obj_type);

let mut file = File::create(&obj_path).map_err(|e| {
ProcessInputError::ExtractingObject {
path: obj_path.to_owned(),
inner: e,
}
})?;
file.write_all(hint_bytes).map_err(|e| {
ProcessInputError::ExtractingObject {
path: obj_path.to_owned(),
inner: e,
}
})?;
std::io::copy(&mut entry, &mut file).map_err(|e| {
ProcessInputError::ExtractingObject {
path: obj_path.to_owned(),
inner: e,
}
})?;
let mut file = File::create(&obj_path)
.map_err(|e| ProcessInputError::ExtractingObject { path: obj_path.to_owned(), inner: e })?;
file.write_all(hint_bytes)
.map_err(|e| ProcessInputError::ExtractingObject { path: obj_path.to_owned(), inner: e })?;
std::io::copy(&mut entry, &mut file)
.map_err(|e| ProcessInputError::ExtractingObject { path: obj_path.to_owned(), inner: e })?;
objects.push(obj_path);
}

Expand Down Expand Up @@ -163,19 +144,12 @@ pub fn create_index(archive_path: &std::path::Path) -> Result<(), MergeError> {
OsString::from_str("ranlib").unwrap()
};

info!(
"{} {}",
ranlib_path.to_string_lossy(),
archive_path.to_string_lossy()
);
tracing::info!("{} {}", ranlib_path.to_string_lossy(), archive_path.to_string_lossy());

let output = Command::new(&ranlib_path)
.args(vec![archive_path])
.output()
.map_err(|e| ExternalToolLaunchError {
tool: ranlib_path.to_string_lossy().to_string(),
inner: e,
})?;
.map_err(|e| ExternalToolLaunchError { tool: ranlib_path.to_string_lossy().to_string(), inner: e })?;
if output.status.success() {
Ok(())
} else {
Expand Down
5 changes: 1 addition & 4 deletions src/input_library.rs → armerge/src/input_library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ impl<R: Read> InputLibrary<R> {
/// The library's name is used to get more meaningful messages in case of errors.
/// The reader reads the binary data of the static library file.
pub fn new<IntoString: Into<String>>(name: IntoString, reader: R) -> Self {
Self {
name: name.into(),
reader,
}
Self { name: name.into(), reader }
}
}

Expand Down
Loading