axbuild 0.4.19

An OS build lib toolkit used by arceos
Documentation
mod config;
mod features;
mod load;
mod metadata;
mod x86;

#[cfg(test)]
mod tests;

pub type AxvisorBuildInfo = config::AxvisorBuildInfo;
use std::path::{Path, PathBuf};

use anyhow::{Context, anyhow};
pub(crate) use config::AxvisorBoardFile;
pub use config::{AXVISOR_PACKAGE, AxvisorBoardConfig};
pub(crate) use load::{
    default_build_info_path, load_board_file, load_target_from_build_config,
    resolve_build_info_path,
};
use ostool::build::config::Cargo;

use self::{
    config::LoadedAxvisorBuildConfig,
    features::{
        normalize_axvisor_feature_surface, reject_unsupported_nested_platform_features,
        remove_dynamic_platform_features,
    },
    load::load_build_config,
    metadata::platform_feature_names,
};
pub use crate::build::LogLevel;
use crate::context::ResolvedAxvisorRequest;

pub(crate) fn default_axvisor_build_info() -> AxvisorBuildInfo {
    config::default_axvisor_build_info()
}

pub(crate) fn workspace_root_from_axvisor_dir(axvisor_dir: &Path) -> PathBuf {
    load::workspace_root_from_axvisor_dir(axvisor_dir)
}

pub(crate) fn load_cargo_config(request: &ResolvedAxvisorRequest) -> anyhow::Result<Cargo> {
    let metadata =
        crate::build::cached_workspace_metadata().context("failed to load workspace metadata")?;
    to_cargo_config(load_build_config(request)?, request, metadata)
}

fn to_cargo_config(
    mut config: LoadedAxvisorBuildConfig,
    request: &ResolvedAxvisorRequest,
    metadata: &cargo_metadata::Metadata,
) -> anyhow::Result<Cargo> {
    config.target = request.target.clone();
    let makefile_features = crate::build::makefile_features_from_env();
    crate::build::apply_makefile_features_with_metadata(
        &mut config.build_info,
        &request.package,
        &makefile_features,
        metadata,
    );
    let known_platforms = platform_feature_names(metadata);
    reject_unsupported_nested_platform_features(&config.build_info.features, &known_platforms)?;
    normalize_axvisor_feature_surface(&mut config.build_info.features, &config.target, metadata)?;
    let mut cargo = config
        .build_info
        .into_prepared_base_cargo_config_with_metadata(
            &request.package,
            &config.target,
            metadata,
        )?;
    remove_dynamic_platform_features(&mut cargo.features);
    patch_axvisor_cargo_config(&mut cargo, request, metadata, &config.vm_configs)?;
    Ok(cargo)
}

fn patch_axvisor_cargo_config(
    cargo: &mut Cargo,
    request: &ResolvedAxvisorRequest,
    metadata: &cargo_metadata::Metadata,
    config_vmconfigs: &[PathBuf],
) -> anyhow::Result<()> {
    cargo.package = request.package.clone();
    cargo.to_bin = default_axvisor_to_bin(&request.arch);
    ensure_axvisor_bin_arg(&mut cargo.args);
    cargo
        .env
        .insert("AX_ARCH".to_string(), request.arch.clone());
    cargo
        .env
        .insert("AX_TARGET".to_string(), request.target.clone());
    normalize_axvisor_feature_surface(&mut cargo.features, &request.target, metadata)?;
    remove_dynamic_platform_features(&mut cargo.features);

    let vmconfigs = if request.vmconfigs.is_empty() {
        config_vmconfigs
            .iter()
            .map(|path| resolve_build_config_vmconfig_path(request, path))
            .collect::<Vec<_>>()
    } else {
        request.vmconfigs.clone()
    };
    if !vmconfigs.is_empty() {
        let joined = std::env::join_paths(&vmconfigs)
            .map_err(|e| anyhow!("failed to join vmconfig paths: {e}"))?;
        cargo.env.insert(
            "AXVISOR_VM_CONFIGS".to_string(),
            joined.to_string_lossy().into_owned(),
        );
    }

    if request.arch == "x86_64" {
        x86::normalize_backend_features(&mut cargo.features)?;
    }
    cargo.features.sort();
    cargo.features.dedup();
    Ok(())
}

fn resolve_build_config_vmconfig_path(request: &ResolvedAxvisorRequest, path: &Path) -> PathBuf {
    if path.is_absolute() {
        return path.to_path_buf();
    }
    let workspace_root = request
        .axvisor_dir
        .parent()
        .and_then(Path::parent)
        .unwrap_or(&request.axvisor_dir);
    workspace_root.join(path)
}

fn default_axvisor_to_bin(arch: &str) -> bool {
    !matches!(arch, "x86_64" | "loongarch64")
}

fn ensure_axvisor_bin_arg(args: &mut Vec<String>) {
    if args.iter().any(|arg| arg == "--bin") {
        return;
    }

    args.push("--bin".to_string());
    args.push(AXVISOR_PACKAGE.to_string());
}