use std::{fs, path::Path};
use anyhow::Context;
use ostool::build::config::LogLevel;
use super::features::{c_config_features, c_define_name, c_defines, has_feature};
pub(super) struct CFlagsInput<'a> {
pub(super) workspace_root: &'a Path,
pub(super) arch: &'a str,
pub(super) mode: &'a str,
pub(super) generated_include_dir: &'a Path,
pub(super) include_dir: &'a Path,
pub(super) features: &'a [String],
pub(super) log: Option<LogLevel>,
pub(super) dynamic_pie: bool,
}
pub(super) fn cflags(input: CFlagsInput<'_>) -> Vec<String> {
let mut flags = vec![
"-nostdinc".to_string(),
"-fno-builtin".to_string(),
"-ffreestanding".to_string(),
"-Wall".to_string(),
format!("-I{}", input.generated_include_dir.display()),
format!("-I{}", input.include_dir.display()),
];
for feature in c_config_features(input.features) {
flags.push(format!("-DAX_CONFIG_{}", c_define_name(&feature)));
}
for define in c_defines(input.features) {
flags.push(format!("-D{define}=1"));
}
flags.push(format!(
"-DAX_LOG_{}",
format!("{:?}", input.log.unwrap_or(LogLevel::Warn)).to_uppercase()
));
if input.mode == "release" {
flags.push("-O3".to_string());
}
if input.dynamic_pie {
flags.push("-fPIE".to_string());
}
match input.arch {
"riscv64" => flags.extend([
"-march=rv64gc".to_string(),
"-mabi=lp64d".to_string(),
"-mcmodel=medany".to_string(),
]),
"loongarch64" => flags.push("-msoft-float".to_string()),
"x86_64" if !has_feature(input.features, "fp-simd") => flags.push("-mno-sse".to_string()),
"aarch64" if !has_feature(input.features, "fp-simd") => {
flags.push("-mgeneral-regs-only".to_string())
}
_ => {}
}
flags.push(format!(
"-I{}",
input.workspace_root.join("include").display()
));
flags
}
pub(super) fn write_pthread_mutex_header(
include_dir: &Path,
features: &[String],
) -> anyhow::Result<()> {
fs::create_dir_all(include_dir)
.with_context(|| format!("failed to create {}", include_dir.display()))?;
let path = include_dir.join("ax_pthread_mutex.h");
fs::write(&path, pthread_mutex_header_contents(features))
.with_context(|| format!("failed to write {}", path.display()))
}
pub(super) fn pthread_mutex_header_contents(features: &[String]) -> String {
let (mutex_size, mutex_init) = pthread_mutex_layout(features);
format!(
r#"// Generated by axbuild for this C app build - DO NOT edit!
typedef struct {{
long __l[{mutex_size}];
}} pthread_mutex_t;
#define PTHREAD_MUTEX_INITIALIZER {{ .__l = {mutex_init} }}
"#
)
}
fn pthread_mutex_layout(features: &[String]) -> (usize, &'static str) {
if !has_feature(features, "multitask") {
return (1, "{0}");
}
if has_feature(features, "lockdep") {
if has_effective_smp(features) {
return (10, "{-1, 0, 0, 0, 0, 0, 0, 0, 0, 0}");
}
return (9, "{-1, 0, 0, 0, 0, 0, 0, 0, 0}");
}
if has_effective_smp(features) {
(6, "{0, 0, 8, 0, 0, 0}")
} else {
(5, "{0, 8, 0, 0, 0}")
}
}
fn has_effective_smp(features: &[String]) -> bool {
has_feature(features, "smp") || has_feature(features, "plat-dyn")
}