diff --git a/CHANGELOG.md b/CHANGELOG.md index 0487067..44aea70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## [0.7.2] - 2026-06-07 "Исправление Таргетов и Линковки / Target & Linker Fixes" + +### RU + +**Добавлено:** +- Учтён `target_env` в `default_target_triple()` — Linux (gnu/musl) и Windows (msvc/gnu) теперь используют правильное окружение, а не хардкод. + +**Исправлено:** +- **Сборка на macOS Apple Silicon падала с `_main` undefined** — `--target=` теперь передаётся и в ldflags, не только в cflags. `default_target_triple()` на macOS использует `std::env::consts::ARCH` вместо хардкода `x86_64`. +- **Бейджи GitHub Stars и GPL-3.0 не рендерились в README** — блок бейджей переведён на чистый HTML. + +**Изменено:** +- Вычисление таргета по умолчанию вынесено в общую функцию `default_target_triple()` — устранено дублирование в build, run, clean. + +### EN + +**Added:** +- `default_target_triple()` now respects `target_env` — Linux (gnu/musl) and Windows (msvc/gnu) use the correct environment instead of hardcoded values. + +**Fixed:** +- **macOS Apple Silicon builds failed with `_main` undefined** — `--target=` is now passed to ldflags, not just cflags. `default_target_triple()` uses `std::env::consts::ARCH` on macOS instead of hardcoded `x86_64`. +- **GitHub Stars and GPL-3.0 badges not rendering in README** — badge block converted to pure HTML. + +**Changed:** +- Default target resolution extracted into shared `default_target_triple()` — removed duplication across build, run, clean. + ## [0.7.1] - 2026-06-02 "Мультиархитектурное расширение / The Multi-Arch Expansion" ### RU diff --git a/Cargo.lock b/Cargo.lock index 91c07d8..4429d44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,7 @@ dependencies = [ [[package]] name = "dcr" -version = "0.7.1" +version = "0.7.2" dependencies = [ "ctrlc", "git2", diff --git a/Cargo.toml b/Cargo.toml index 9a06bcc..85c448e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dcr" -version = "0.7.1" +version = "0.7.2" edition = "2024" build = "build.rs" description = "DCR is a utility for managing C/C++ projects in a Cargo-like style." diff --git a/src/cli/build.rs b/src/cli/build.rs index 5bf8223..ed39098 100644 --- a/src/cli/build.rs +++ b/src/cli/build.rs @@ -23,9 +23,9 @@ use crate::core::config::Config; use crate::core::deps::{register, resolve_deps}; use crate::core::workspace::parse_workspace; use crate::utils::build::{ - get_bool_with_profile, get_config_opt, get_config_str, get_language_with_profile, - normalize_target_os, parse_version_info, profile_table, resolve_compiler, - resolve_pkg_config_flags, resolve_tool, + 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, }; use crate::utils::fs::{check_dir, find_project_root, with_dir}; use crate::utils::log::error; @@ -100,27 +100,7 @@ pub fn build(args: &[String]) -> i32 { } } if flags.target.is_none() { - let default_target = if cfg!(target_os = "linux") { - format!("{}-unknown-linux-gnu", std::env::consts::ARCH) - } else if cfg!(target_os = "macos") { - "x86_64-apple-darwin".to_string() - } else if cfg!(target_os = "windows") { - "x86_64-pc-windows-msvc".to_string() - } else if cfg!(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly" - )) { - format!( - "{}-unknown-{}", - std::env::consts::ARCH, - std::env::consts::OS - ) - } else { - "unknown".to_string() - }; - flags.target = Some(default_target); + flags.target = Some(default_target_triple()); } if flags.clean { let mut clean_args = Vec::new(); @@ -718,19 +698,13 @@ fn build_project_at( tc_cxx.as_deref(), tc_as.as_deref(), ); - if let Some(t) = build_target - && !t.trim().is_empty() - && resolved_compiler.to_lowercase().contains("clang") - { - let target_flag = format!("--target={}", t.trim()); - if !build_cflags - .iter() - .any(|f| f == &target_flag || f.starts_with("--target=")) - { - build_cflags.insert(0, target_flag); - } - } let resolved_linker = resolve_tool("DCR_LD", tc_ld.as_deref()); + prepend_clang_target_flag(&mut build_cflags, build_target, &resolved_compiler); + prepend_clang_target_flag( + &mut build_ldflags, + build_target, + resolved_linker.as_deref().unwrap_or(&resolved_compiler), + ); let resolved_archiver = resolve_tool("DCR_AR", tc_ar.as_deref()); let out_dir_config = get_build_string_with_profile(&config, "out_dir", profile); diff --git a/src/cli/clean.rs b/src/cli/clean.rs index 931b1ed..151f6bb 100644 --- a/src/cli/clean.rs +++ b/src/cli/clean.rs @@ -18,7 +18,7 @@ use crate::config::flags; use crate::core::config::Config; use crate::core::workspace::parse_workspace; -use crate::utils::build::parse_version_info; +use crate::utils::build::{default_target_triple, parse_version_info}; use crate::utils::fs::{check_dir, find_project_root, with_dir}; use crate::utils::log::{error, warn}; use crate::utils::text::{BOLD_CYAN, BOLD_GREEN, colored, printc}; @@ -136,28 +136,7 @@ fn clean_from_root(root: &Path, flags: &CleanFlags) -> Result<(), String> { .map(|s| s.trim().to_string()) .filter(|s| !s.is_empty()) }) - .or_else(|| { - Some(if cfg!(target_os = "linux") { - format!("{}-unknown-linux-gnu", std::env::consts::ARCH) - } else if cfg!(target_os = "macos") { - "x86_64-apple-darwin".to_string() - } else if cfg!(target_os = "windows") { - "x86_64-pc-windows-msvc".to_string() - } else if cfg!(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly" - )) { - format!( - "{}-unknown-{}", - std::env::consts::ARCH, - std::env::consts::OS - ) - } else { - "unknown".to_string() - }) - }); + .or_else(|| Some(default_target_triple())); if flags.all && let Some(workspace) = parse_workspace( diff --git a/src/cli/run.rs b/src/cli/run.rs index 70c2218..942e0c1 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -19,7 +19,7 @@ use crate::cli::build::build; use crate::cli::flags::parse_build_run_flags; use crate::core::config::Config; use crate::core::runner::run_binary; -use crate::utils::build::{normalize_target_os, parse_version_info}; +use crate::utils::build::{default_target_triple, normalize_target_os, parse_version_info}; use crate::utils::fs::find_project_root; use crate::utils::fs::with_dir; use crate::utils::log::error; @@ -178,27 +178,7 @@ fn run_project( // If no target specified, use default host target for target-specific config let mut target = flags.target.clone(); if target.is_none() { - let default_target = if cfg!(target_os = "linux") { - format!("{}-unknown-linux-gnu", std::env::consts::ARCH) - } else if cfg!(target_os = "macos") { - "x86_64-apple-darwin".to_string() - } else if cfg!(target_os = "windows") { - "x86_64-pc-windows-msvc".to_string() - } else if cfg!(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly" - )) { - format!( - "{}-unknown-{}", - std::env::consts::ARCH, - std::env::consts::OS - ) - } else { - "unknown".to_string() - }; - target = Some(default_target); + target = Some(default_target_triple()); } let build_kind = config diff --git a/src/utils/build.rs b/src/utils/build.rs index 6f21ed4..83e99bf 100644 --- a/src/utils/build.rs +++ b/src/utils/build.rs @@ -72,6 +72,53 @@ pub fn normalize_target_os(target: &str) -> &str { } } +pub fn default_target_triple() -> String { + let arch = std::env::consts::ARCH; + if cfg!(target_os = "linux") { + let env = if cfg!(target_env = "musl") { + "musl" + } else { + "gnu" + }; + format!("{arch}-unknown-linux-{env}") + } else if cfg!(target_os = "macos") { + format!("{arch}-apple-darwin") + } else if cfg!(target_os = "windows") { + let env = if cfg!(target_env = "gnu") { + "gnu" + } else { + "msvc" + }; + format!("{arch}-pc-windows-{env}") + } else if cfg!(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )) { + format!("{arch}-unknown-{}", std::env::consts::OS) + } else { + "unknown".to_string() + } +} + +pub fn prepend_clang_target_flag(flags: &mut Vec, target: Option<&str>, tool: &str) { + let Some(target) = target.map(str::trim).filter(|t| !t.is_empty()) else { + return; + }; + if !tool.to_lowercase().contains("clang") { + return; + } + + let target_flag = format!("--target={target}"); + if !flags + .iter() + .any(|f| f == &target_flag || f.starts_with("--target=")) + { + flags.insert(0, target_flag); + } +} + pub fn get_config_str(config: &Config, key: &str) -> String { config .get(key) @@ -380,6 +427,61 @@ mod tests { assert_eq!(normalize_target_os("unknown"), "unknown"); } + #[test] + fn default_target_triple_uses_host_arch() { + let target = default_target_triple(); + if cfg!(target_os = "linux") { + assert_eq!( + target, + format!("{}-unknown-linux-gnu", std::env::consts::ARCH) + ); + } else if cfg!(target_os = "macos") { + assert_eq!(target, format!("{}-apple-darwin", std::env::consts::ARCH)); + } else if cfg!(target_os = "windows") { + assert_eq!( + target, + format!("{}-pc-windows-msvc", std::env::consts::ARCH) + ); + } else if cfg!(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )) { + assert_eq!( + target, + format!( + "{}-unknown-{}", + std::env::consts::ARCH, + std::env::consts::OS + ) + ); + } else { + assert_eq!(target, "unknown"); + } + } + + #[test] + fn prepend_clang_target_flag_adds_once_for_clang() { + let mut flags = vec!["-O2".to_string()]; + prepend_clang_target_flag(&mut flags, Some("aarch64-apple-darwin"), "clang"); + prepend_clang_target_flag(&mut flags, Some("aarch64-apple-darwin"), "clang"); + assert_eq!( + flags, + vec![ + "--target=aarch64-apple-darwin".to_string(), + "-O2".to_string() + ] + ); + } + + #[test] + fn prepend_clang_target_flag_ignores_non_clang_tools() { + let mut flags = vec!["-O2".to_string()]; + prepend_clang_target_flag(&mut flags, Some("aarch64-apple-darwin"), "gcc"); + assert_eq!(flags, vec!["-O2".to_string()]); + } + #[test] fn parse_version_parts() { let info = parse_version_info("1.2.3-beta");