use camino::Utf8PathBuf;
use clap::Parser;
use color_eyre::{
eyre::{eyre, Context, ContextCompat, Report},
Section, SectionExt,
};
use std::env;
#[allow(unused_imports)]
use tracing::{debug, error, info, trace, warn};
use cargo_xcode_build_rs::prelude::*;
fn main() -> Result<(), color_eyre::Report> {
let args = TopLevel::parse();
{
install_tracing(args.options().colour);
color_eyre::install().expect("Error reporting couldn't be installed (lol)");
}
let config = Config::retrieve_from_toml_config(&args.options().manifest_path())?;
run_script(args, config)
}
fn run_script(args: TopLevel, config: Config) -> Result<(), Report> {
{
let vars = env::vars().collect::<std::collections::HashMap<_, _>>();
info!("Environment variables: {:?}", vars);
}
let is_release_build = release_profile()?;
append_useful_paths()?;
append_library_paths()?;
let is_simulator = is_simulator()?;
if let Mode::Test = args.mode() {
info!("Skipping actual compilation, running a test rustc build for M1 iOS simulator");
rustc(
"aarch64-apple-ios-sim",
is_release_build,
config.ios_feature_flags(),
&args.options().manifest_path(),
)?;
return Ok(());
}
match parse_archs()? {
Archs::X86_64 => {
if is_simulator {
warn!(
message = "Building for x86_64 simulators is not yet fully supported",
note = "IDK why",
);
rustc(
"x86_64-apple-ios-sim",
is_release_build,
config.ios_feature_flags(),
&args.options().manifest_path(),
)?;
} else {
env::set_var("CFLAGS_x86_64_apple_ios", "-targetx86_64-apple-ios");
rustc(
"x86_64-apple-ios",
is_release_build,
config.ios_feature_flags(),
&args.options().manifest_path(),
)?;
}
}
Archs::Arm64 => {
if is_simulator {
rustc(
"aarch64-apple-ios-sim",
is_release_build,
config.ios_feature_flags(),
&args.options().manifest_path(),
)?;
} else {
rustc(
"aarch64-apple-ios",
is_release_build,
config.ios_feature_flags(),
&args.options().manifest_path(),
)?;
}
}
}
Ok(())
}
pub fn install_tracing(ansi: bool) {
use tracing_error::ErrorLayer;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{fmt, EnvFilter};
let mut fmt_layer = fmt::Layer::default().with_target(false);
fmt_layer.set_ansi(ansi);
let filter_layer = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("info"))
.unwrap();
tracing_subscriber::registry()
.with(filter_layer)
.with(fmt_layer)
.with(ErrorLayer::default())
.init();
}
fn append_useful_paths() -> Result<(), Report> {
if let Ok(path) = env::var("PATH") {
let mut paths = env::split_paths(&path).collect::<Vec<_>>();
let home_dir = dirs::home_dir().wrap_err("Could not find home dir")?;
let home_dir = Utf8PathBuf::try_from(home_dir).wrap_err("Home dir not UTF8")?;
paths.push(home_dir.clone().into());
let cargo_bin_dir = home_dir.join(".cargo").join("bin");
paths.push(cargo_bin_dir.clone().into());
let homebrew_dir = Utf8PathBuf::from("/opt/homebrew/bin");
paths.push(homebrew_dir.clone().into());
if !debug_confirm_on_path(&paths, "cc")? {
info!("`cc` compiler not found on $PATH");
}
let new_path = env::join_paths(paths.clone())
.wrap_err("Unable to add path to PATH env variable")
.note(format!("Original PATH: {:?}", paths.clone()))
.note(format!("+Cargo bin dir: {:?}", cargo_bin_dir))
.note(format!("+Home path: {:?}", home_dir))
.note(format!("+Homebrew path: {:?}", homebrew_dir))?;
env::set_var("PATH", new_path.clone());
info!(
message = "Updated PATH env variable",
note = "To add cargo_bin_dir, home_dir and homebrew_dir",
?cargo_bin_dir,
?home_dir,
?homebrew_dir,
);
debug!(message = "Path env variable updated", from = ?path, to = ?new_path);
} else {
info!("No PATH env variable to update");
}
Ok(())
}
fn append_library_paths() -> Result<(), Report> {
if let Ok(developer_sdk_dir) = env::var("DEVELOPER_SDK_DIR") {
let developer_sdk_dir = Utf8PathBuf::from(developer_sdk_dir);
let exists = developer_sdk_dir.try_exists();
match exists {
Ok(true) => {
let library_path = env::var("LIBRARY_PATH").unwrap_or_default();
let mut library_paths = env::split_paths(&library_path).collect::<Vec<_>>();
library_paths.push(Utf8PathBuf::from(format!(
"{}/MacOSX.sdk/usr/lib",
developer_sdk_dir
)).into());
let new_library_path =
env::join_paths(library_paths).wrap_err("Cannot join paths for DEVELOPER_SDK_DIR")?;
env::set_var("LIBRARY_PATH", &new_library_path);
info!(message = "Updated LIBRARY_PATH env variable with a subpath of DEVELOPER_SDK_DIR env variable", ?developer_sdk_dir, from = ?library_path, to = ?new_library_path);
}
_ => {
return Err(
eyre!("DEVELOPER_SDK_DIR does not exist or not UTF8")
.note("The env variable DEVELOPER_SDK_DIR was found, but the path it pointed to doesn't exist")
.with_section(|| developer_sdk_dir.header("DEVELOPER_SDK_DIR:")),
)
}
}
} else {
info!(
message = "No DEVELOPER_SDK_DIR env variable found in environment",
note = "Not updating LIBRARY_PATH env variable"
);
}
Ok(())
}