feat(build): add freestanding, lto, strip, panic-abort, and codegen-units support in dcr.toml

This commit is contained in:
2026-06-16 16:42:56 +08:00
parent 3d596d7280
commit 21932ac94a
18 changed files with 242 additions and 73 deletions

View File

@@ -24,8 +24,9 @@ use crate::core::deps::{register, resolve_deps};
use crate::core::workspace::parse_workspace;
use crate::utils::build::{
default_target_triple, get_bool_with_profile, get_config_opt, get_config_str,
get_language_with_profile, normalize_target_os, parse_version_info, prepend_clang_target_flag,
profile_table, resolve_compiler, resolve_pkg_config_flags, resolve_tool,
get_language_with_profile, is_bare_metal_target, normalize_target_os, parse_version_info,
prepend_clang_target_flag, profile_table, resolve_compiler, resolve_pkg_config_flags,
resolve_tool,
};
use crate::utils::fs::{check_dir, find_project_root, with_dir};
use crate::utils::log::error;
@@ -682,6 +683,63 @@ fn build_project_at(
let build_roots =
get_list_with_profile_and_target(&config, "roots", profile, build_target)?;
let src_disable = get_bool_with_profile(&config, "src_disable", profile, false);
let freestanding = get_bool_with_profile(&config, "freestanding", profile, false);
let lto = get_bool_with_profile(&config, "lto", profile, false);
let strip = get_bool_with_profile(&config, "strip", profile, false);
let opt_level =
get_string_with_profile_and_target(&config, "opt_level", profile, build_target);
let debug = get_bool_with_profile(&config, "debug", profile, profile != "release");
let warnings =
get_list_with_profile_and_target(&config, "warnings", profile, build_target)?;
let panic_val = get_string_with_profile_and_target(&config, "panic", profile, build_target);
let panic_abort = panic_val == "abort";
let codegen_units: usize =
get_string_with_profile_and_target(&config, "codegen-units", profile, build_target)
.parse()
.unwrap_or(0);
if build_cflags.is_empty() && !freestanding && !is_bare_metal_target(build_target) {
if !opt_level.is_empty() {
build_cflags.push(format!("-O{opt_level}"));
} else {
build_cflags.push(match profile {
"release" => "-O3".to_string(),
_ => "-O0".to_string(),
});
}
if debug {
build_cflags.push("-g".to_string());
}
if warnings.is_empty() {
if profile == "debug" {
build_cflags.push("-Wall".to_string());
build_cflags.push("-Wextra".to_string());
}
} else {
for w in &warnings {
build_cflags.push(format!("-W{w}"));
}
}
match profile {
"debug" => {
build_cflags.push("-fno-omit-frame-pointer".to_string());
build_cflags.push("-DDCR_DEBUG".to_string());
}
"release" => {
build_cflags.push("-DNDEBUG".to_string());
}
_ => {}
}
}
if lto {
build_cflags.push("-flto".to_string());
build_ldflags.push("-flto".to_string());
}
if strip {
build_ldflags.push("-s".to_string());
}
let build_expects =
get_list_with_profile_and_target(&config, "expect", profile, build_target)?;
let pkg_configs =
@@ -909,6 +967,9 @@ fn build_project_at(
} else {
Some(build_type.as_str())
},
freestanding,
panic_abort,
codegen_units,
source_roots: &source_roots,
exclude_dirs: &combined_excludes,
include_paths: &combined_includes,

View File

@@ -367,6 +367,9 @@ fn collect_project_info_inner(root: &Path, profile: &str) -> Result<ProjectInfo,
linker: resolved_linker.as_deref(),
archiver: resolved_archiver.as_deref(),
package_type: None,
freestanding: false,
panic_abort: false,
codegen_units: 0,
source_roots: &source_roots,
exclude_dirs: &combined_excludes,
include_paths: &combined_includes,

View File

@@ -164,13 +164,18 @@ pub fn has_glob_magic(value: &str) -> bool {
value.chars().any(|c| matches!(c, '*' | '?' | '['))
}
pub fn parallel_build<F>(total_tasks: usize, task_fn: F) -> Result<(), String>
pub fn parallel_build<F>(total_tasks: usize, task_fn: F, max_jobs: usize) -> Result<(), String>
where
F: Fn(usize) -> Result<(), String> + Sync + Send,
{
let num_threads = std::thread::available_parallelism()
let available = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1);
let num_threads = if max_jobs > 0 {
max_jobs.min(available)
} else {
available
};
let counter = std::sync::atomic::AtomicUsize::new(0);
let err_msg = std::sync::Mutex::new(None);

View File

@@ -151,9 +151,11 @@ fn build_objects(
.map(|s| common::object_path(obj_dir, s, obj_ext))
.collect();
common::parallel_build(sources.len(), |i| {
build_object(assembler, &sources[i], &objects[i], ctx)
})?;
common::parallel_build(
sources.len(),
|i| build_object(assembler, &sources[i], &objects[i], ctx),
ctx.codegen_units,
)?;
Ok(objects)
}

View File

@@ -35,6 +35,9 @@ pub struct BuildContext<'a> {
pub linker: Option<&'a str>,
pub archiver: Option<&'a str>,
pub package_type: Option<&'a str>,
pub freestanding: bool,
pub panic_abort: bool,
pub codegen_units: usize,
pub source_roots: &'a [std::path::PathBuf],
pub exclude_dirs: &'a [std::path::PathBuf],
pub include_paths: &'a [String],

View File

@@ -228,9 +228,11 @@ fn build_objects(
.map(|s| common::object_path(obj_dir, s, obj_ext))
.collect();
common::parallel_build(sources.len(), |i| {
build_object(compiler, &sources[i], &objects[i], ctx)
})?;
common::parallel_build(
sources.len(),
|i| build_object(compiler, &sources[i], &objects[i], ctx),
ctx.codegen_units,
)?;
Ok(objects)
}

View File

@@ -153,9 +153,11 @@ fn build_objects(
let format = nasm_format(ctx.platform);
common::parallel_build(sources.len(), |i| {
build_object(assembler, &sources[i], &objects[i], format, ctx)
})?;
common::parallel_build(
sources.len(),
|i| build_object(assembler, &sources[i], &objects[i], format, ctx),
ctx.codegen_units,
)?;
Ok(objects)
}

View File

@@ -18,6 +18,7 @@
use crate::core::builder::BuildContext;
use crate::core::builder::common;
use crate::platform;
use crate::utils::build::is_bare_metal_target;
use std::fs;
use std::path::Path;
use std::process::Command;
@@ -80,6 +81,9 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
cmd.arg("-nostdlib");
cmd.arg("-Wl,-dll");
cmd.arg("-Wl,--subsystem,10");
} else if ctx.freestanding || is_bare_metal_target(ctx.target) {
cmd.arg("-nostdlib");
cmd.arg("-static");
}
for obj in &objects {
cmd.arg(obj);
@@ -172,19 +176,6 @@ fn default_flags(profile: &str) -> &'static [&'static str] {
}
}
fn is_bare_metal_target(target: Option<&str>) -> bool {
if let Some(t) = target {
let lower = t.to_lowercase();
lower.contains("none")
|| lower.contains("-elf")
|| lower.contains("eabi")
|| lower.contains("baremetal")
|| lower.contains("bare-metal")
} else {
false
}
}
fn build_objects(
compiler: &str,
sources: &[String],
@@ -197,9 +188,11 @@ fn build_objects(
.map(|s| common::object_path(obj_dir, s, obj_ext))
.collect();
common::parallel_build(sources.len(), |i| {
build_object(compiler, &sources[i], &objects[i], ctx)
})?;
common::parallel_build(
sources.len(),
|i| build_object(compiler, &sources[i], &objects[i], ctx),
ctx.codegen_units,
)?;
Ok(objects)
}
@@ -231,6 +224,23 @@ fn build_object(
cmd.arg("-fPIC");
}
if (ctx.freestanding || is_bare_metal_target(ctx.target))
&& ctx.language.to_lowercase() != "asm"
{
cmd.arg("-ffreestanding");
}
if ctx.panic_abort && ctx.language.to_lowercase() != "asm" {
if ctx.language.contains("++")
|| ctx.language.contains("cpp")
|| ctx.language.contains("cxx")
{
cmd.arg("-fno-exceptions");
}
cmd.arg("-fno-unwind-tables");
cmd.arg("-fno-asynchronous-unwind-tables");
}
if let Some(platform) = ctx.platform
&& !platform.trim().is_empty()
{
@@ -250,7 +260,8 @@ fn build_object(
}
}
let use_dcr_defaults = ctx.cflags.is_empty() && !is_bare_metal_target(ctx.target);
let use_dcr_defaults =
ctx.cflags.is_empty() && !(ctx.freestanding || is_bare_metal_target(ctx.target));
if use_dcr_defaults {
for flag in default_flags(ctx.profile) {
cmd.arg(flag);

View File

@@ -187,6 +187,19 @@ pub fn get_list_with_profile(config: &Config, field: &str, profile: &str) -> Vec
out
}
pub fn is_bare_metal_target(target: Option<&str>) -> bool {
if let Some(t) = target {
let lower = t.to_lowercase();
lower.contains("none")
|| lower.contains("-elf")
|| lower.contains("eabi")
|| lower.contains("baremetal")
|| lower.contains("bare-metal")
} else {
false
}
}
pub fn get_bool_with_profile(config: &Config, field: &str, profile: &str, default: bool) -> bool {
let base = config
.get(&format!("build.{field}"))