axbuild 0.4.15

An OS build lib toolkit used by arceos
Documentation
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")
}