mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 21:39:36 +00:00
- `build.kind = "efi"` — UEFI PE32+ executable support. Links with `-shared -nostdlib -Wl,-dll -Wl,--subsystem,10`, output via `efi_path()` with `.efi` extension, rejected by `dcr run`.
- `build.kind = "elf"` — bare-metal ELF executable support. Uses `elf_path()` output path, rejected by `dcr run`, no extra linker flags.
Fixed:
- `dcr run` with `--target` or `build.target` now correctly finds the binary in the arch-specific target directory.
- `dcr run` checks profile-specific `build.{profile}.kind` before rejecting library builds (previously only checked `build.kind`).
- `dcr clean` now reads `build.target` from `dcr.toml` when no `--target` flag is given.
- Linux: target directory is now consistent — `target/<arch>-unknown-linux-gnu/<profile>/` (no stale `target/<profile>/`).
- `dcr.lock` is now populated with all resolved dependencies (registry, path, git) instead of being always empty.
- Git dependencies are now properly recognized and recorded in `dcr.lock`.
- `is_registry_dep` correctly identifies version-based registry dependency tables (`{ version = "..." }`) and rejects tables with unknown keys.
- `dcr test` accepts `--debug`/`--release` flags (defaults to `debug` profile instead of always `release`).
- Build fingerprint cache (`build_cache_path`) now includes `target_dir` — different targets no longer share a single cache entry.
- `object_path` no longer hardcodes the `src/` prefix — works correctly with custom `build.roots` (e.g. `roots = ["lib"]`).
- `dcr update` now generates `.exe` candidates for all Windows targets, not just `x86_64-pc-windows-msvc`.
- Compiler existence is verified before starting the build (clear error if compiler is not found in PATH).
- Consolidated duplicate `OUTPUT_MUTEX` definitions — MSVC backend now uses the shared mutex from `common.rs`.
- Registry cache root directory is created if missing (prevents cryptic errors when `~/.dcr/` does not exist).
177 lines
5.2 KiB
Rust
177 lines
5.2 KiB
Rust
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::fs::find_project_root;
|
|
use crate::utils::fs::with_dir;
|
|
use crate::utils::log::error;
|
|
use crate::utils::text::{BOLD_GREEN, colored};
|
|
use std::process::Command;
|
|
|
|
fn get_run_cmd(
|
|
config: &Config,
|
|
profile: &str,
|
|
target: Option<&str>,
|
|
version: &str,
|
|
) -> Option<String> {
|
|
let base = config.get("run.cmd").and_then(|v| v.as_str());
|
|
let target_cmd = if let Some(t) = target {
|
|
let normalized_t = normalize_target_os(t);
|
|
config
|
|
.get(&format!("run.{}.cmd", normalized_t))
|
|
.or_else(|| config.get(&format!("run.{}.cmd", t)))
|
|
.and_then(|v| v.as_str())
|
|
} else {
|
|
None
|
|
};
|
|
let profile_cmd = config
|
|
.get(&format!("run.{}.cmd", profile))
|
|
.and_then(|v| v.as_str());
|
|
let cmd = target_cmd.or(profile_cmd).or(base)?;
|
|
let trimmed = cmd.trim();
|
|
if trimmed.is_empty() {
|
|
None
|
|
} else {
|
|
Some(substitute_run_vars(trimmed, profile, version))
|
|
}
|
|
}
|
|
|
|
pub fn run(args: &[String]) -> i32 {
|
|
let start_dir = match std::env::current_dir() {
|
|
Ok(dir) => dir,
|
|
Err(_) => {
|
|
error("Failed to determine current directory");
|
|
return 1;
|
|
}
|
|
};
|
|
let root = match find_project_root(&start_dir) {
|
|
Ok(Some(dir)) => dir,
|
|
Ok(None) => {
|
|
error("dcr.toml file not found");
|
|
return 1;
|
|
}
|
|
Err(_) => {
|
|
error("Failed to find project root");
|
|
return 1;
|
|
}
|
|
};
|
|
let config = match with_dir(&root, || {
|
|
Config::open("./dcr.toml").map_err(|err| err.to_string())
|
|
}) {
|
|
Ok(cfg) => cfg,
|
|
Err(err) => {
|
|
error(&err);
|
|
return 1;
|
|
}
|
|
};
|
|
let project_name: &str = config
|
|
.get("package.name")
|
|
.and_then(|v| v.as_str())
|
|
.unwrap_or("");
|
|
|
|
let mut flags = match parse_build_run_flags(args) {
|
|
Ok(v) => v,
|
|
Err(_) => return 1,
|
|
};
|
|
|
|
// If no target specified, use default host target for target-specific config
|
|
if flags.target.is_none() {
|
|
let default_target = if cfg!(target_os = "linux") {
|
|
"x86_64-unknown-linux-gnu"
|
|
} else if cfg!(target_os = "macos") {
|
|
"x86_64-apple-darwin"
|
|
} else if cfg!(target_os = "windows") {
|
|
"x86_64-pc-windows-msvc"
|
|
} else {
|
|
"unknown"
|
|
};
|
|
flags.target = Some(default_target.to_string());
|
|
}
|
|
|
|
let build_kind = config
|
|
.get(&format!("build.{}.kind", flags.profile))
|
|
.and_then(|v| v.as_str())
|
|
.or_else(|| config.get("build.kind").and_then(|v| v.as_str()))
|
|
.unwrap_or("");
|
|
|
|
let normalized_target_dir = flags
|
|
.target
|
|
.as_ref()
|
|
.and_then(|t| crate::cli::build::normalize_target(t, &flags.profile));
|
|
|
|
let version = config
|
|
.get("package.version")
|
|
.and_then(|v| v.as_str())
|
|
.unwrap_or("");
|
|
let run_cmd = get_run_cmd(&config, &flags.profile, flags.target.as_deref(), version);
|
|
|
|
let kind = build_kind.trim();
|
|
if run_cmd.is_none()
|
|
&& (kind == "staticlib" || kind == "sharedlib" || kind == "efi" || kind == "elf")
|
|
{
|
|
error("Cannot run library build");
|
|
return 1;
|
|
}
|
|
let build_status = build(args);
|
|
let bin_path = crate::platform::bin_path(
|
|
&flags.profile,
|
|
project_name,
|
|
normalized_target_dir.as_deref(),
|
|
);
|
|
if build_status == 0 {
|
|
if let Some(cmd) = run_cmd {
|
|
println!("\n {} {}", colored("Running", BOLD_GREEN), cmd);
|
|
println!("--------------------------------");
|
|
return run_shell(&cmd);
|
|
}
|
|
println!("\n {} {}", colored("Running", BOLD_GREEN), bin_path);
|
|
println!("--------------------------------");
|
|
return run_binary(
|
|
project_name,
|
|
&flags.profile,
|
|
normalized_target_dir.as_deref(),
|
|
);
|
|
}
|
|
|
|
let fallback_code = if let Some(cmd) = run_cmd {
|
|
run_shell(&cmd)
|
|
} else {
|
|
run_binary(
|
|
project_name,
|
|
&flags.profile,
|
|
normalized_target_dir.as_deref(),
|
|
)
|
|
};
|
|
if fallback_code != 1 {
|
|
return fallback_code;
|
|
}
|
|
|
|
error("Fix errors in the code to run the project");
|
|
1
|
|
}
|
|
|
|
fn run_shell(cmd: &str) -> i32 {
|
|
let status = if cfg!(target_os = "windows") {
|
|
Command::new("cmd").arg("/C").arg(cmd).status()
|
|
} else {
|
|
Command::new("sh").arg("-c").arg(cmd).status()
|
|
};
|
|
match status {
|
|
Ok(s) if s.success() => 0,
|
|
Ok(s) => s.code().unwrap_or(1),
|
|
Err(_) => 1,
|
|
}
|
|
}
|
|
|
|
fn substitute_run_vars(cmd: &str, profile: &str, version: &str) -> String {
|
|
let info = parse_version_info(version);
|
|
cmd.replace("{profile}", profile)
|
|
.replace("{version}", &info.full)
|
|
.replace("{version_major}", &info.major)
|
|
.replace("{version_minor}", &info.minor)
|
|
.replace("{version_patch}", &info.patch)
|
|
.replace("{version_suffix}", &info.suffix)
|
|
.replace("{version_suffix_dash}", &info.suffix_dash)
|
|
}
|