- `sharedlib` build kind (shared library output)
- ASM projects (`build.language = "asm"`)
- NASM and GAS backends
- `build.platform` architecture hint for `-march` / `/arch`
- Basic CLI integration tests
This commit is contained in:
2026-03-01 19:47:38 +08:00
parent d1e3b0c384
commit a247e33555
8 changed files with 41 additions and 28 deletions

View File

@@ -32,7 +32,6 @@ pub fn build(args: &[String]) -> i32 {
let build_standard = get_config_str(&config, "build.standard"); let build_standard = get_config_str(&config, "build.standard");
let build_target = get_config_str(&config, "build.target"); let build_target = get_config_str(&config, "build.target");
let build_kind = get_config_str(&config, "build.kind"); let build_kind = get_config_str(&config, "build.kind");
let build_platform = get_config_str(&config, "build.platform");
let build_cflags = match get_config_list(&config, "build.cflags") { let build_cflags = match get_config_list(&config, "build.cflags") {
Ok(v) => v, Ok(v) => v,
Err(msg) => { Err(msg) => {
@@ -79,7 +78,6 @@ pub fn build(args: &[String]) -> i32 {
standard: &build_standard, standard: &build_standard,
target_dir: normalize_target(&build_target), target_dir: normalize_target(&build_target),
kind: normalize_kind(&build_kind), kind: normalize_kind(&build_kind),
platform: normalize_platform(&build_platform),
include_dirs: &resolved.include_dirs, include_dirs: &resolved.include_dirs,
lib_dirs: &resolved.lib_dirs, lib_dirs: &resolved.lib_dirs,
libs: &resolved.libs, libs: &resolved.libs,
@@ -186,8 +184,3 @@ fn normalize_kind(kind: &str) -> &str {
let trimmed = kind.trim(); let trimmed = kind.trim();
if trimmed.is_empty() { "bin" } else { trimmed } if trimmed.is_empty() { "bin" } else { trimmed }
} }
fn normalize_platform(platform: &str) -> Option<&str> {
let trimmed = platform.trim();
if trimmed.is_empty() { None } else { Some(trimmed) }
}

View File

@@ -150,10 +150,10 @@ fn build_objects(
if ctx.kind == "sharedlib" { if ctx.kind == "sharedlib" {
cmd.arg("-fPIC"); cmd.arg("-fPIC");
} }
if let Some(platform) = ctx.platform { if let Some(platform) = ctx.platform
if !platform.trim().is_empty() { && !platform.trim().is_empty()
cmd.arg(format!("-march={}", platform)); {
} cmd.arg(format!("-march={}", platform));
} }
if !ctx.standard.is_empty() && ctx.language.to_lowercase() != "asm" { if !ctx.standard.is_empty() && ctx.language.to_lowercase() != "asm" {
cmd.arg(format!("-std={}", ctx.standard)); cmd.arg(format!("-std={}", ctx.standard));

View File

@@ -9,7 +9,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
if ctx.language.to_lowercase().as_str() != "asm" { if ctx.language.to_lowercase().as_str() != "asm" {
return Err("GAS backend requires build.language = \"asm\"".to_string()); return Err("GAS backend requires build.language = \"asm\"".to_string());
} }
let assembler = if ctx.compiler.is_empty() { "as" } else { ctx.compiler }; let assembler = if ctx.compiler.is_empty() {
"as"
} else {
ctx.compiler
};
let start_time = Instant::now(); let start_time = Instant::now();
let sources = collect_sources(ctx.language)?; let sources = collect_sources(ctx.language)?;
let obj_dir = Path::new("./target").join(ctx.profile).join("obj"); let obj_dir = Path::new("./target").join(ctx.profile).join("obj");
@@ -17,7 +21,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
if ctx.kind == "staticlib" { if ctx.kind == "staticlib" {
let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir); let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir);
let mut cmd = Command::new(if cfg!(target_os = "windows") { "lib" } else { "ar" }); let mut cmd = Command::new(if cfg!(target_os = "windows") {
"lib"
} else {
"ar"
});
if cfg!(target_os = "windows") { if cfg!(target_os = "windows") {
cmd.arg("/nologo").arg(format!("/OUT:{lib_path}")); cmd.arg("/nologo").arg(format!("/OUT:{lib_path}"));
} else { } else {

View File

@@ -150,10 +150,10 @@ fn build_objects(
if ctx.kind == "sharedlib" { if ctx.kind == "sharedlib" {
cmd.arg("-fPIC"); cmd.arg("-fPIC");
} }
if let Some(platform) = ctx.platform { if let Some(platform) = ctx.platform
if !platform.trim().is_empty() { && !platform.trim().is_empty()
cmd.arg(format!("-march={}", platform)); {
} cmd.arg(format!("-march={}", platform));
} }
if !ctx.standard.is_empty() && ctx.language.to_lowercase() != "asm" { if !ctx.standard.is_empty() && ctx.language.to_lowercase() != "asm" {
cmd.arg(format!("-std={}", ctx.standard)); cmd.arg(format!("-std={}", ctx.standard));

View File

@@ -1,4 +1,5 @@
pub mod clang; pub mod clang;
pub mod gas;
pub mod gcc; pub mod gcc;
pub mod gas; pub mod gas;
pub mod msvc; pub mod msvc;

View File

@@ -21,7 +21,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
if ctx.kind == "staticlib" { if ctx.kind == "staticlib" {
let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir); let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir);
let mut cmd = Command::new(if cfg!(target_os = "windows") { "lib" } else { "ar" }); let mut cmd = Command::new(if cfg!(target_os = "windows") {
"lib"
} else {
"ar"
});
if cfg!(target_os = "windows") { if cfg!(target_os = "windows") {
cmd.arg("/nologo").arg(format!("/OUT:{lib_path}")); cmd.arg("/nologo").arg(format!("/OUT:{lib_path}"));
} else { } else {
@@ -40,7 +44,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
} }
} }
let linker = if cfg!(target_os = "windows") { "cc" } else { "cc" }; let linker = "cc";
let mut cmd = Command::new(linker); let mut cmd = Command::new(linker);
if ctx.kind == "sharedlib" { if ctx.kind == "sharedlib" {
if cfg!(target_os = "macos") { if cfg!(target_os = "macos") {
@@ -128,7 +132,11 @@ fn build_objects(
} }
if needs_rebuild(source, &obj_path) { if needs_rebuild(source, &obj_path) {
let mut cmd = Command::new(assembler); let mut cmd = Command::new(assembler);
cmd.arg("-f").arg(format).arg(source).arg("-o").arg(&obj_path); cmd.arg("-f")
.arg(format)
.arg(source)
.arg("-o")
.arg(&obj_path);
for flag in ctx.cflags { for flag in ctx.cflags {
cmd.arg(flag); cmd.arg(flag);
} }
@@ -163,15 +171,15 @@ fn nasm_format(platform: Option<&str>) -> &'static str {
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
return "elf64"; "elf64"
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
return "macho64"; "macho64"
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {
return "win64"; "win64"
} }
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
{ {

View File

@@ -121,10 +121,13 @@ impl Config {
return Err(ConfigError::Invalid(format!("build.{key} is empty"))); return Err(ConfigError::Invalid(format!("build.{key} is empty")));
} }
} }
if let Some(platform) = build.get("platform") { if let Some(platform) = build.get("platform")
if !platform.as_str().map(|v| !v.trim().is_empty()).unwrap_or(false) { && !platform
return Err(ConfigError::Invalid("build.platform is empty".into())); .as_str()
} .map(|v| !v.trim().is_empty())
.unwrap_or(false)
{
return Err(ConfigError::Invalid("build.platform is empty".into()));
} }
if let Some(kind) = build.get("kind").and_then(|v| v.as_str()) { if let Some(kind) = build.get("kind").and_then(|v| v.as_str()) {
let kind = kind.trim(); let kind = kind.trim();

View File

@@ -1,7 +1,7 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Once; use std::sync::Once;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
static COUNTER: AtomicUsize = AtomicUsize::new(0); static COUNTER: AtomicUsize = AtomicUsize::new(0);