feat: enhance build configuration with C++ standard support and variable substitution

- Added `cxx_standard` field to the build configuration for specifying C++ standards.
- Updated documentation to reflect new `cxx_standard` and variable substitution capabilities in `cflags`, `ldflags`, and `include`.
- Implemented logic to handle C++ standard flags in the build process.
- Modified object file naming to include source file extensions.
- Updated various builder modules to support new language parsing logic.
- Introduced issue and feature request templates for better community engagement.
This commit is contained in:
2026-05-27 20:04:01 +08:00
parent b5bbdb929b
commit acdd1cc175
18 changed files with 602 additions and 328 deletions

View File

@@ -230,11 +230,18 @@ fn get_list_with_profile_and_target(
// Custom from target/profile
if let Some(val) = get_config_value_raw(config, "build", field, profile, target) {
if let Some(_arr) = val.as_array() {
let custom = parse_string_array(&val, &format!("build.{field}"))?;
if inherit {
out.extend(custom);
} else {
out = custom;
let is_base = inherit
&& config
.get(&format!("build.{field}"))
.map(|v| v == &val)
.unwrap_or(false);
if !is_base {
let custom = parse_string_array(&val, &format!("build.{field}"))?;
if inherit {
out.extend(custom);
} else {
out = custom;
}
}
}
} else if inherit {
@@ -513,6 +520,8 @@ fn build_project_at(
let build_language = get_language_with_profile(&config, profile)?;
let build_standard =
get_string_with_profile_and_target(&config, "standard", profile, build_target);
let build_cxx_standard =
get_string_with_profile_and_target(&config, "cxx_standard", profile, build_target);
let build_kind = get_string_with_profile_and_target(&config, "kind", profile, build_target);
let build_platform =
get_string_with_profile_and_target(&config, "platform", profile, build_target);
@@ -716,12 +725,29 @@ fn build_project_at(
}
let target_dir_binding = normalize_target(build_target.unwrap_or(""), profile);
let version_info = parse_version_info(&project_version);
let substitute = |s: &str| -> String {
s.replace("{profile}", profile)
.replace("{name}", &project_name)
.replace("{version}", &version_info.full)
.replace("{version_major}", &version_info.major)
.replace("{version_minor}", &version_info.minor)
.replace("{version_patch}", &version_info.patch)
.replace("{version_suffix}", &version_info.suffix)
.replace("{version_suffix_dash}", &version_info.suffix_dash)
};
let resolved_cflags: Vec<String> = resolved_cflags.iter().map(|f| substitute(f)).collect();
let modified_ldflags: Vec<String> =
resolved_ldflags.iter().map(|f| substitute(f)).collect();
let merged_include_dirs: Vec<String> =
merged_include_dirs.iter().map(|f| substitute(f)).collect();
let ctx = BuildContext {
profile,
project_name: &project_name,
compiler: &resolved_compiler,
language: &build_language,
standard: &build_standard,
cxx_standard: &build_cxx_standard,
target: build_target,
target_dir: target_dir_binding.as_deref(),
kind: normalize_kind(&build_kind),
@@ -740,7 +766,7 @@ fn build_project_at(
lib_dirs: &resolved.lib_dirs,
libs: &resolved.libs,
cflags: &resolved_cflags,
ldflags: &resolved_ldflags,
ldflags: &modified_ldflags,
output_filename: if output_filename.is_empty() {
None
} else {
@@ -763,7 +789,6 @@ fn build_project_at(
let tool_execs = resolve_toolchain_execs(&tc_uic, &tc_moc, &tc_rcc, &pkg_configs);
let step_flags =
build_step_flags(&resolved_cflags, &resolved.include_dirs, &resolved_compiler);
let version_info = parse_version_info(&project_version);
let step_vars = StepVars {
profile,
version: &version_info.full,

View File

@@ -171,6 +171,7 @@ pub struct ProjectInfo {
pub profile: String,
pub language: String,
pub standard: String,
pub cxx_standard: String,
pub compiler: String,
pub kind: String,
pub sources: Vec<String>,
@@ -228,6 +229,7 @@ fn collect_project_info_inner(root: &Path, profile: &str) -> Result<ProjectInfo,
let version = get_config_str(&config, "package.version");
let language = get_language_with_profile_or_default(&config, profile);
let standard = get_string_with_profile(&config, "standard", profile);
let cxx_standard = get_string_with_profile(&config, "cxx_standard", profile);
let compiler_s = get_string_with_profile(&config, "compiler", profile);
let kind = get_string_with_profile(&config, "kind", profile);
let build_target = get_string_with_profile(&config, "target", profile);
@@ -339,6 +341,7 @@ fn collect_project_info_inner(root: &Path, profile: &str) -> Result<ProjectInfo,
compiler: &resolved_compiler,
language: &language,
standard: &standard,
cxx_standard: &cxx_standard,
target: Some(build_target.as_str()),
target_dir: target_dir_binding.as_deref(),
kind: normalize_kind(&kind),
@@ -381,6 +384,7 @@ fn collect_project_info_inner(root: &Path, profile: &str) -> Result<ProjectInfo,
profile: profile.to_string(),
language,
standard,
cxx_standard,
compiler: resolved_compiler,
kind: normalize_kind(&kind).to_string(),
sources: abs_sources,
@@ -471,6 +475,10 @@ fn project_info_to_json(info: &ProjectInfo) -> String {
" \"standard\": {},\n",
json_str(&info.standard)
));
out.push_str(&format!(
" \"cxx_standard\": {},\n",
json_str(&info.cxx_standard)
));
out.push_str(&format!(
" \"compiler\": {},\n",
json_str(&info.compiler)
@@ -575,6 +583,13 @@ fn build_compile_command(info: &ProjectInfo, source: &str, profile: &str) -> Vec
};
cmd.push(compiler.to_string());
cmd.push("-c".to_string());
// ASM x flag — must be before source file
if let Some(flag) = asm_lang_flag(source) {
cmd.push("-x".to_string());
cmd.push(flag.to_string());
}
cmd.push(source.to_string());
// Object path (for -o, approximate — not critical for IntelliSense)
@@ -595,15 +610,18 @@ fn build_compile_command(info: &ProjectInfo, source: &str, profile: &str) -> Vec
cmd.push("-fPIC".to_string());
}
// ASM x flag
if let Some(flag) = asm_lang_flag(source) {
cmd.push("-x".to_string());
cmd.push(flag.to_string());
}
// -std=
if !info.standard.is_empty() && info.language.to_lowercase() != "asm" {
cmd.push(format!("-std={}", info.standard));
let ext = Path::new(source)
.extension()
.and_then(|e| e.to_str())
.unwrap_or("");
let is_cpp = matches!(ext, "cpp" | "cxx" | "cc");
if is_cpp && !info.cxx_standard.is_empty() {
cmd.push(format!("-std={}", info.cxx_standard));
} else if !is_cpp {
cmd.push(format!("-std={}", info.standard));
}
}
// Default profile flags (mirrors unix_cc.rs defaults)