axbuild 0.4.15

An OS build lib toolkit used by arceos
Documentation
use std::collections::BTreeSet;

const C_DEFINE_FEATURE_PREFIX: &str = "c-define:";

pub(super) fn dynamic_pie_for_c_app(features: &[String]) -> bool {
    has_feature(features, "plat-dyn")
}

pub(super) fn c_config_features(features: &[String]) -> BTreeSet<String> {
    let mut config_features: BTreeSet<_> = features
        .iter()
        .filter_map(|feature| {
            if feature.starts_with(C_DEFINE_FEATURE_PREFIX) {
                return None;
            }
            if feature.starts_with("ax-hal/") || feature.starts_with("ax-driver/") {
                return None;
            }
            feature
                .strip_prefix("ax-libc/")
                .or_else(|| feature.strip_prefix("ax-feat/"))
                .or_else(|| feature.strip_prefix("ax-std/"))
                .or(Some(feature.as_str()))
        })
        .filter(|feature| {
            !matches!(
                *feature,
                "ax-libc" | "ax-feat" | "ax-std" | "defplat" | "myplat" | "plat-dyn"
            ) && !feature.contains('/')
        })
        .map(str::to_string)
        .collect();
    if has_feature(features, "plat-dyn") {
        config_features.insert("smp".to_string());
    }
    config_features
}

pub(super) fn c_defines(features: &[String]) -> BTreeSet<String> {
    features
        .iter()
        .filter_map(|feature| feature.strip_prefix(C_DEFINE_FEATURE_PREFIX))
        .map(str::to_string)
        .collect()
}

pub(super) fn c_compiler_features(
    cargo_features: &[String],
    case_features: &[String],
) -> Vec<String> {
    let mut features = cargo_features.to_vec();
    features.extend(
        case_features
            .iter()
            .filter(|feature| feature.starts_with(C_DEFINE_FEATURE_PREFIX))
            .cloned(),
    );
    features
}

pub(super) fn has_feature(features: &[String], name: &str) -> bool {
    features.iter().any(|feature| {
        feature == name
            || feature.strip_prefix("ax-libc/") == Some(name)
            || feature.strip_prefix("ax-feat/") == Some(name)
            || feature.strip_prefix("ax-std/") == Some(name)
    })
}

pub(super) fn c_define_name(feature: &str) -> String {
    feature.replace('-', "_").to_uppercase()
}

pub(super) fn map_c_app_features(
    case_features: &[String],
    base_features: &[String],
) -> Vec<String> {
    const LIB_FEATURES: &[&str] = &[
        "fp-simd",
        "irq",
        "alloc",
        "multitask",
        "lockdep",
        "fs",
        "net",
        "fd",
        "pipe",
        "select",
        "epoll",
    ];

    let mut features = BTreeSet::new();
    for feature in base_features {
        let normalized = feature
            .strip_prefix("ax-feat/")
            .or_else(|| feature.strip_prefix("ax-std/"))
            .or_else(|| feature.strip_prefix("ax-libc/"))
            .unwrap_or(feature);
        if feature.starts_with("ax-hal/") || feature.starts_with("ax-driver/") {
            features.insert(feature.clone());
            continue;
        }
        match normalized {
            "ax-std" | "ax-feat" | "ax-libc" => {}
            "defplat" | "myplat" | "plat-dyn" => {
                features.insert(normalized.to_string());
            }
            "smp" => {
                features.insert("smp".to_string());
            }
            feature if LIB_FEATURES.contains(&feature) => {
                features.insert(feature.to_string());
            }
            feature => {
                features.insert(format!("ax-feat/{feature}"));
            }
        }
    }
    for feature in case_features {
        if feature.starts_with(C_DEFINE_FEATURE_PREFIX) {
            continue;
        }
        let normalized = feature
            .strip_prefix("ax-feat/")
            .or_else(|| feature.strip_prefix("ax-std/"))
            .or_else(|| feature.strip_prefix("ax-libc/"))
            .unwrap_or(feature);
        if feature.starts_with("ax-hal/") || feature.starts_with("ax-driver/") {
            features.insert(feature.clone());
            continue;
        }
        if LIB_FEATURES.contains(&normalized)
            || matches!(normalized, "defplat" | "myplat" | "plat-dyn" | "smp")
        {
            features.insert(normalized.to_string());
        } else {
            features.insert(format!("ax-feat/{normalized}"));
        }
    }
    if features
        .iter()
        .any(|feature| matches!(feature.as_str(), "fs" | "net" | "pipe" | "select" | "epoll"))
    {
        features.insert("fd".to_string());
    }
    if features.contains("plat-dyn") {
        features.insert("smp".to_string());
    }
    features.into_iter().collect()
}