mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 14:18:36 +00:00
feat: add AGENTS.md for quick start and CI guidelines; update documentation for dcr add and dcr build commands
This commit is contained in:
77
AGENT.md
77
AGENT.md
@@ -1,77 +0,0 @@
|
|||||||
# AGENT.md
|
|
||||||
|
|
||||||
## Project Overview
|
|
||||||
|
|
||||||
**DCR (Dexoron Cargo Realization)** — CLI tool for managing C/C++/ASM projects in a Cargo-style.
|
|
||||||
|
|
||||||
- **Implementation Language**: Rust (edition 2024)
|
|
||||||
- **License**: MIT
|
|
||||||
- **Repository**: [github.com/dexoron/dcr](https://github.com/dexoron/dcr)
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Source Tree (`src/`)
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── main.rs # Entry point, CLI command routing
|
|
||||||
├── config.rs # Global constants
|
|
||||||
├── cli/ # CLI command implementation
|
|
||||||
│ ├── new.rs # dcr new <name>
|
|
||||||
│ ├── init.rs # dcr init
|
|
||||||
│ ├── setup.rs # dcr setup (registry initialization)
|
|
||||||
│ ├── add.rs # dcr add <name>
|
|
||||||
│ ├── build.rs # dcr build
|
|
||||||
│ ├── run.rs # dcr run
|
|
||||||
│ ├── clean.rs # dcr clean
|
|
||||||
│ ├── help.rs # dcr --help
|
|
||||||
│ └── flag_update.rs # dcr --update
|
|
||||||
├── core/ # Business logic
|
|
||||||
│ ├── config.rs # dcr.toml parsing
|
|
||||||
│ ├── registry.rs # Package index management (RegistryManager)
|
|
||||||
│ ├── deps/ # Dependency resolution (path, git)
|
|
||||||
│ ├── runner.rs # Binary execution
|
|
||||||
│ ├── workspace.rs # [workspace] support
|
|
||||||
│ └── builder/ # Compiler backends (gcc, clang, msvc, nasm, gas)
|
|
||||||
├── platform/ # Platform-specific logic
|
|
||||||
└── utils/ # Helper utilities
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Concepts
|
|
||||||
|
|
||||||
- **`~/.dcr/`**: Centralized storage for registries and configurations.
|
|
||||||
- **`config.toml`**: File in `~/.dcr/` defining available package indices and their priorities.
|
|
||||||
- **`dcr.toml`**: Local project configuration.
|
|
||||||
- **Registry System**: `RegistryManager` handles package discovery across multiple indices based on priority.
|
|
||||||
|
|
||||||
## Supported Platforms
|
|
||||||
|
|
||||||
| Platform | Target triple |
|
|
||||||
|---|---|
|
|
||||||
| Linux | `x86_64-unknown-linux-gnu` |
|
|
||||||
| macOS Intel | `x86_64-apple-darwin` |
|
|
||||||
| macOS ARM | `aarch64-apple-darwin` |
|
|
||||||
| Windows | `x86_64-pc-windows-msvc` |
|
|
||||||
|
|
||||||
## Dependencies (Cargo)
|
|
||||||
|
|
||||||
| Crate | Purpose |
|
|
||||||
|---|---|
|
|
||||||
| `reqwest` | HTTP requests |
|
|
||||||
| `serde` | Serialization |
|
|
||||||
| `toml` | Configuration parsing |
|
|
||||||
| `git2` | Git dependency handling |
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Build & Run
|
|
||||||
```bash
|
|
||||||
cargo build --release
|
|
||||||
./target/release/dcr setup
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Conventions
|
|
||||||
- Rust stable edition 2024.
|
|
||||||
- `cargo fmt` and `cargo clippy -- -D warnings`.
|
|
||||||
- CLI output in English.
|
|
||||||
- Use `utils::log` for messaging.
|
|
||||||
56
AGENTS.md
Normal file
56
AGENTS.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build --release && ./target/release/dcr setup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pre-PR (CI) gate
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all --check
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
cargo check --all-targets --all-features
|
||||||
|
cargo test
|
||||||
|
```
|
||||||
|
|
||||||
|
CI (`.github/workflows/ci.yml`) runs fmt, clippy, check — **not** tests.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
- Integration tests in `tests/` build the dcr binary and run it in temp dirs under `sandbox/cli-tests/` (gitignored).
|
||||||
|
- Some tests **skip** if no C compiler (`gcc`/`clang`/`cc`) is found at runtime.
|
||||||
|
- Compiler can be overridden via `DCR_COMPILER` or `DCR_CC` env vars.
|
||||||
|
- Tests use `$CARGO_BIN_EXE_dcr` when available, else `target/debug/dcr`.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **Single Rust package** (edition 2024), not a workspace. Only one binary: `dcr`.
|
||||||
|
- **Entrypoint**: `src/main.rs` — matches `args[1]` against command names.
|
||||||
|
- **Compiler backends** in `src/core/builder/`: `unix_cc` (gcc/clang), `msvc` (cl/clang-cl), `gas`, `nasm`. Dispatched by matching compiler name string.
|
||||||
|
- **Config**: `dcr.toml` (per-project), `~/.dcr/config.toml` (registry), `~/.dcr/index.json` (index). Defaults: `language=c`, `standard=c11`, `compiler=clang`, `kind=bin`.
|
||||||
|
- **`build.rs`** embeds `TARGET` as `DCR_TARGET` env var (shown in `--version`).
|
||||||
|
- **CLI output** must be in English. Use `utils::log` for messaging.
|
||||||
|
|
||||||
|
## Key commands
|
||||||
|
|
||||||
|
| Command | Notes |
|
||||||
|
|---|---|
|
||||||
|
| `dcr new <name>` | Creates project dir |
|
||||||
|
| `dcr init` | Init from CWD (must be empty) |
|
||||||
|
| `dcr build [--debug\|--release] [--target <triple>]` | Default profile: `--debug` |
|
||||||
|
| `dcr run [--debug\|--release]` | Only for `kind = "bin"` |
|
||||||
|
| `dcr clean [--debug\|--release] [--all]` | `--all` for workspace roots |
|
||||||
|
| `dcr tree` | Dependency tree viewer |
|
||||||
|
| `dcr test [--init]` | Runs/test project tests |
|
||||||
|
| `dcr gen <vscode\|clion\|compile-commands>` | IDE integration |
|
||||||
|
| `dcr --update` | Self-update from GitHub Releases |
|
||||||
|
|
||||||
|
## Cross-compilation
|
||||||
|
|
||||||
|
`--target` accepts short names (`linux`, `macos`, `windows`) or full triples. In CI, Linux cross-builds use `cargo-zigbuild`. When `build.target` is set in `dcr.toml`, DCR auto-injects `--target=<value>` into cflags (clang). Bare-metal targets (containing `none`/`-elf`/`eabi`/`baremetal`) skip DCR's default compiler flags.
|
||||||
|
|
||||||
|
## Dependencies (Cargo)
|
||||||
|
|
||||||
|
reqwest (blocking+json+rustls-tls), serde, toml, git2, openssl (vendored), self-replace, sha2, ctrlc.
|
||||||
@@ -14,6 +14,9 @@ Added:
|
|||||||
Produces `KERNEL.EFI` (works for `bin`, `staticlib`, and `sharedlib`).
|
Produces `KERNEL.EFI` (works for `bin`, `staticlib`, and `sharedlib`).
|
||||||
- Automatic injection of `--target=<build.target>` into compiler flags when `build.target` is set in `dcr.toml`. This greatly simplifies clang-based cross-compilation (especially for bare-metal targets like `aarch64-none-elf`).
|
- Automatic injection of `--target=<build.target>` into compiler flags when `build.target` is set in `dcr.toml`. This greatly simplifies clang-based cross-compilation (especially for bare-metal targets like `aarch64-none-elf`).
|
||||||
- Bare-metal targets (containing `none`, `-elf`, `eabi`, `baremetal`) no longer receive DCR's internal default flags (`-g`, `-Wall`, `-Wextra`, `-fno-omit-frame-pointer`, `-DDCR_DEBUG`, etc.). Prevents unwanted sections (`.comment`, debug info, etc.) that break custom linker scripts when `inherit = true`.
|
- Bare-metal targets (containing `none`, `-elf`, `eabi`, `baremetal`) no longer receive DCR's internal default flags (`-g`, `-Wall`, `-Wextra`, `-fno-omit-frame-pointer`, `-DDCR_DEBUG`, etc.). Prevents unwanted sections (`.comment`, debug info, etc.) that break custom linker scripts when `inherit = true`.
|
||||||
|
- `build.ldscript` in `dcr.toml` — linker script path passed as `-T <path>` to the linker. Essential for bare-metal/embedded/freestanding targets.
|
||||||
|
- `dcr build --verbose` — prints compiler/linker command lines (also works with `DCR_DEBUG` env var).
|
||||||
|
- `dcr add <name>` without a source argument — if a registry is configured, DCR looks up the package by name and adds it as a version dependency.
|
||||||
|
|
||||||
Fixed:
|
Fixed:
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ Add a dependency to `dcr.toml`.
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dcr add <name> <source> [options]
|
dcr add <name> [source] [options]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If `<source>` is omitted and a registry is configured, DCR will look up the
|
||||||
|
package by name in the registry and add it as a version dependency.
|
||||||
|
|
||||||
## Sources
|
## Sources
|
||||||
|
|
||||||
|
- *omitted*: Look up in the configured registry.
|
||||||
- `path:./path/to/lib`: Local directory.
|
- `path:./path/to/lib`: Local directory.
|
||||||
- `github:user/repo`: GitHub repository.
|
- `github:user/repo`: GitHub repository.
|
||||||
- `gitlab:user/repo`: GitLab repository.
|
- `gitlab:user/repo`: GitLab repository.
|
||||||
@@ -29,4 +33,5 @@ dcr add my_lib path:./libs/my_lib
|
|||||||
dcr add cool_lib github:user/cool_lib
|
dcr add cool_lib github:user/cool_lib
|
||||||
dcr add shared_lib gitlab:org/shared --branch develop
|
dcr add shared_lib gitlab:org/shared --branch develop
|
||||||
dcr add custom_lib git:git.internal.com/r/lib --tag v1.0.0
|
dcr add custom_lib git:git.internal.com/r/lib --tag v1.0.0
|
||||||
|
dcr add mylib # Looks up in registry
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ dcr build --debug --clean
|
|||||||
- `build.platform`
|
- `build.platform`
|
||||||
- `build.cflags`
|
- `build.cflags`
|
||||||
- `build.ldflags`
|
- `build.ldflags`
|
||||||
|
- `build.ldscript`
|
||||||
- `build.debug` / `build.release`
|
- `build.debug` / `build.release`
|
||||||
- `build.exclude`
|
- `build.exclude`
|
||||||
- `build.include`
|
- `build.include`
|
||||||
@@ -58,6 +59,7 @@ dcr build --debug --clean
|
|||||||
- Profile flag (`--debug` / `--release`) can appear in any argument position (duplicates are rejected).
|
- Profile flag (`--debug` / `--release`) can appear in any argument position (duplicates are rejected).
|
||||||
- Unknown profile flags return an error.
|
- Unknown profile flags return an error.
|
||||||
- `--target <triple>` builds for specified target (short names: `linux`, `macos`, `windows`).
|
- `--target <triple>` builds for specified target (short names: `linux`, `macos`, `windows`).
|
||||||
|
- `--verbose` prints the compiler/linker command lines to stderr (also works via `DCR_DEBUG` env var).
|
||||||
- If no `--target`, builds for `build.targets` or native.
|
- If no `--target`, builds for `build.targets` or native.
|
||||||
- Incremental rebuild checks source/object mtime and tracked header dependencies.
|
- Incremental rebuild checks source/object mtime and tracked header dependencies.
|
||||||
- `--force` skips build cache checks and recompiles.
|
- `--force` skips build cache checks and recompiles.
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ kind = "bin"
|
|||||||
- `platform` (string, optional): architecture hint for compiler (used for `-march` or `/arch`).
|
- `platform` (string, optional): architecture hint for compiler (used for `-march` or `/arch`).
|
||||||
- `cflags` (string array, optional): extra compile flags.
|
- `cflags` (string array, optional): extra compile flags.
|
||||||
- `ldflags` (string array, optional): extra link flags.
|
- `ldflags` (string array, optional): extra link flags.
|
||||||
|
- `ldscript` (string, optional): linker script path. Passed as `-T <path>` to the linker. Useful for bare-metal/embedded/freestanding targets.
|
||||||
- `exclude` (string array, optional): paths or glob patterns to skip during source/header collection.
|
- `exclude` (string array, optional): paths or glob patterns to skip during source/header collection.
|
||||||
- `include` (string array, optional): allowlist paths or globs that override `exclude`.
|
- `include` (string array, optional): allowlist paths or globs that override `exclude`.
|
||||||
- `include` directory entries (non-glob) are also passed to the compiler as `-I` include paths.
|
- `include` directory entries (non-glob) are also passed to the compiler as `-I` include paths.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ dcr --update
|
|||||||
|
|
||||||
## Notes on argument parsing
|
## Notes on argument parsing
|
||||||
|
|
||||||
- `build`/`run` parse flags in any order (`--debug|--release`, `--force`, `--clean`) and reject duplicates.
|
- `build`/`run` parse flags in any order (`--debug|--release`, `--force`, `--clean`, `--verbose`) and reject duplicates.
|
||||||
- `new` requires exactly one argument.
|
- `new` requires exactly one argument.
|
||||||
- `init` and `--update` do not accept extra arguments.
|
- `init` and `--update` do not accept extra arguments.
|
||||||
- `clean` accepts `--debug|--release` and optional `--all`.
|
- `clean` accepts `--debug|--release` and optional `--all`.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ target = "string" # optional
|
|||||||
platform = "string" # optional
|
platform = "string" # optional
|
||||||
cflags = ["string", "..."] # optional
|
cflags = ["string", "..."] # optional
|
||||||
ldflags = ["string", "..."] # optional
|
ldflags = ["string", "..."] # optional
|
||||||
|
ldscript = "string" # optional (linker script, passed as -T<path>)
|
||||||
exclude = ["string", "..."] # optional
|
exclude = ["string", "..."] # optional
|
||||||
include = ["string", "..."] # optional
|
include = ["string", "..."] # optional
|
||||||
roots = ["string", "..."] # optional
|
roots = ["string", "..."] # optional
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::core::config::Config;
|
use crate::core::config::Config;
|
||||||
|
use crate::core::deps::register;
|
||||||
use crate::utils::fs::find_project_root;
|
use crate::utils::fs::find_project_root;
|
||||||
use crate::utils::log::error;
|
use crate::utils::log::error;
|
||||||
use crate::utils::text::{BOLD_GREEN, colored};
|
use crate::utils::text::{BOLD_GREEN, colored};
|
||||||
@@ -12,6 +13,7 @@ pub struct AddArgs {
|
|||||||
pub branch: Option<String>,
|
pub branch: Option<String>,
|
||||||
pub tag: Option<String>,
|
pub tag: Option<String>,
|
||||||
pub rev: Option<String>,
|
pub rev: Option<String>,
|
||||||
|
pub version_from_registry: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(args: &[String]) -> i32 {
|
pub fn add(args: &[String]) -> i32 {
|
||||||
@@ -71,6 +73,8 @@ pub fn add(args: &[String]) -> i32 {
|
|||||||
let mut table = Map::new();
|
let mut table = Map::new();
|
||||||
table.insert("path".to_string(), Value::String(path));
|
table.insert("path".to_string(), Value::String(path));
|
||||||
Value::Table(table)
|
Value::Table(table)
|
||||||
|
} else if let Some(version) = add_args.version_from_registry {
|
||||||
|
Value::String(version)
|
||||||
} else {
|
} else {
|
||||||
error("Dependency source (path or git) must be provided");
|
error("Dependency source (path or git) must be provided");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -124,8 +128,38 @@ fn parse_add_args(args: &[String]) -> Result<AddArgs, i32> {
|
|||||||
}
|
}
|
||||||
source_spec = s.clone();
|
source_spec = s.clone();
|
||||||
} else {
|
} else {
|
||||||
error("Dependency source is required");
|
// No source provided — try registry auto-lookup
|
||||||
return Err(1);
|
match register::resolve_package_from_registry(&name) {
|
||||||
|
Ok(info) => {
|
||||||
|
let version = info
|
||||||
|
.get("latest_version")
|
||||||
|
.or_else(|| info.get("version"))
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.ok_or_else(|| {
|
||||||
|
(
|
||||||
|
"Registry entry for `".to_string() + &name + "` has no version field",
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(|(msg, code)| {
|
||||||
|
error(&msg);
|
||||||
|
code
|
||||||
|
})?;
|
||||||
|
return Ok(AddArgs {
|
||||||
|
name,
|
||||||
|
path: None,
|
||||||
|
git: None,
|
||||||
|
branch: None,
|
||||||
|
tag: None,
|
||||||
|
rev: None,
|
||||||
|
version_from_registry: Some(version.to_string()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error(&format!("Cannot add `{}` without source: {}", name, e));
|
||||||
|
return Err(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(arg) = iter.next() {
|
while let Some(arg) = iter.next() {
|
||||||
@@ -197,5 +231,6 @@ fn parse_add_args(args: &[String]) -> Result<AddArgs, i32> {
|
|||||||
branch,
|
branch,
|
||||||
tag,
|
tag,
|
||||||
rev,
|
rev,
|
||||||
|
version_from_registry: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,13 @@ pub fn build(args: &[String]) -> i32 {
|
|||||||
let _ = clean(&clean_args);
|
let _ = clean(&clean_args);
|
||||||
}
|
}
|
||||||
match with_dir(&root, || {
|
match with_dir(&root, || {
|
||||||
build_from_root(&root, &flags.profile, flags.target.as_deref(), flags.force)
|
build_from_root(
|
||||||
|
&root,
|
||||||
|
&flags.profile,
|
||||||
|
flags.target.as_deref(),
|
||||||
|
flags.force,
|
||||||
|
flags.verbose,
|
||||||
|
)
|
||||||
}) {
|
}) {
|
||||||
Ok(()) => 0,
|
Ok(()) => 0,
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
@@ -377,6 +383,7 @@ fn build_from_root(
|
|||||||
profile: &str,
|
profile: &str,
|
||||||
target: Option<&str>,
|
target: Option<&str>,
|
||||||
force: bool,
|
force: bool,
|
||||||
|
verbose: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let config = Config::open("./dcr.toml").map_err(|err| err.to_string())?;
|
let config = Config::open("./dcr.toml").map_err(|err| err.to_string())?;
|
||||||
let project_name = get_config_str(&config, "package.name");
|
let project_name = get_config_str(&config, "package.name");
|
||||||
@@ -418,12 +425,19 @@ fn build_from_root(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Some(workspace) = parse_workspace(&config, profile, build_target.as_deref(), root)? {
|
if let Some(workspace) = parse_workspace(&config, profile, build_target.as_deref(), root)? {
|
||||||
build_workspace(&workspace, profile, build_target.as_deref(), force)?;
|
build_workspace(&workspace, profile, build_target.as_deref(), force, verbose)?;
|
||||||
let excludes: Vec<std::path::PathBuf> =
|
let excludes: Vec<std::path::PathBuf> =
|
||||||
workspace.members.iter().map(|m| m.path.clone()).collect();
|
workspace.members.iter().map(|m| m.path.clone()).collect();
|
||||||
build_project_at(root, profile, build_target.as_deref(), &excludes, force)?;
|
build_project_at(
|
||||||
|
root,
|
||||||
|
profile,
|
||||||
|
build_target.as_deref(),
|
||||||
|
&excludes,
|
||||||
|
force,
|
||||||
|
verbose,
|
||||||
|
)?;
|
||||||
} else {
|
} else {
|
||||||
build_project_at(root, profile, build_target.as_deref(), &[], force)?;
|
build_project_at(root, profile, build_target.as_deref(), &[], force, verbose)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||||
@@ -440,9 +454,10 @@ fn build_workspace(
|
|||||||
profile: &str,
|
profile: &str,
|
||||||
target: Option<&str>,
|
target: Option<&str>,
|
||||||
force: bool,
|
force: bool,
|
||||||
|
verbose: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
for member in &workspace.members {
|
for member in &workspace.members {
|
||||||
build_project_at(&member.path, profile, target, &[], force)?;
|
build_project_at(&member.path, profile, target, &[], force, verbose)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -453,6 +468,7 @@ fn build_project_at(
|
|||||||
target: Option<&str>,
|
target: Option<&str>,
|
||||||
exclude_dirs: &[std::path::PathBuf],
|
exclude_dirs: &[std::path::PathBuf],
|
||||||
force: bool,
|
force: bool,
|
||||||
|
verbose: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
with_dir(project_root, || {
|
with_dir(project_root, || {
|
||||||
check_interrupted()?;
|
check_interrupted()?;
|
||||||
@@ -500,21 +516,30 @@ fn build_project_at(
|
|||||||
.or_else(|| get_config_opt(&config, "toolchain.rcc"));
|
.or_else(|| get_config_opt(&config, "toolchain.rcc"));
|
||||||
let mut build_cflags =
|
let mut build_cflags =
|
||||||
get_list_with_profile_and_target(&config, "cflags", profile, build_target)?;
|
get_list_with_profile_and_target(&config, "cflags", profile, build_target)?;
|
||||||
// Автоматически добавляем --target=..., если задан build.target и флаг ещё не указан
|
if let Some(t) = build_target
|
||||||
if let Some(t) = build_target {
|
&& !t.trim().is_empty()
|
||||||
if !t.trim().is_empty() {
|
{
|
||||||
let target_flag = format!("--target={}", t.trim());
|
let target_flag = format!("--target={}", t.trim());
|
||||||
if !build_cflags.iter().any(|f| f == &target_flag || f.starts_with("--target=")) {
|
if !build_cflags
|
||||||
build_cflags.insert(0, target_flag);
|
.iter()
|
||||||
}
|
.any(|f| f == &target_flag || f.starts_with("--target="))
|
||||||
|
{
|
||||||
|
build_cflags.insert(0, target_flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let build_ldflags =
|
let mut build_ldflags =
|
||||||
get_list_with_profile_and_target(&config, "ldflags", profile, build_target)?;
|
get_list_with_profile_and_target(&config, "ldflags", profile, build_target)?;
|
||||||
|
let build_ldscript =
|
||||||
|
get_string_with_profile_and_target(&config, "ldscript", profile, build_target);
|
||||||
|
if !build_ldscript.is_empty() {
|
||||||
|
build_ldflags.push(format!("-T{}", build_ldscript));
|
||||||
|
}
|
||||||
|
|
||||||
// Новые поля: filename и extension
|
// Новые поля: filename и extension
|
||||||
let output_filename = get_string_with_profile_and_target(&config, "filename", profile, build_target);
|
let output_filename =
|
||||||
let output_extension = get_string_with_profile_and_target(&config, "extension", profile, build_target);
|
get_string_with_profile_and_target(&config, "filename", profile, build_target);
|
||||||
|
let output_extension =
|
||||||
|
get_string_with_profile_and_target(&config, "extension", profile, build_target);
|
||||||
let build_excludes =
|
let build_excludes =
|
||||||
get_list_with_profile_and_target(&config, "exclude", profile, build_target)?;
|
get_list_with_profile_and_target(&config, "exclude", profile, build_target)?;
|
||||||
let build_includes =
|
let build_includes =
|
||||||
@@ -578,7 +603,7 @@ fn build_project_at(
|
|||||||
dep_root.display()
|
dep_root.display()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
build_project_at(&dep_root, profile, build_target, &[], force)?;
|
build_project_at(&dep_root, profile, build_target, &[], force, verbose)?;
|
||||||
print!(
|
print!(
|
||||||
"\r{:100}\r {} {} v{}",
|
"\r{:100}\r {} {} v{}",
|
||||||
"",
|
"",
|
||||||
@@ -693,8 +718,17 @@ fn build_project_at(
|
|||||||
libs: &resolved.libs,
|
libs: &resolved.libs,
|
||||||
cflags: &resolved_cflags,
|
cflags: &resolved_cflags,
|
||||||
ldflags: &resolved_ldflags,
|
ldflags: &resolved_ldflags,
|
||||||
output_filename: if output_filename.is_empty() { None } else { Some(output_filename.as_str()) },
|
output_filename: if output_filename.is_empty() {
|
||||||
output_extension: if output_extension.is_empty() { None } else { Some(output_extension.as_str()) },
|
None
|
||||||
|
} else {
|
||||||
|
Some(output_filename.as_str())
|
||||||
|
},
|
||||||
|
output_extension: if output_extension.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(output_extension.as_str())
|
||||||
|
},
|
||||||
|
verbose,
|
||||||
};
|
};
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] debug: compiler={}", ctx.compiler);
|
eprintln!("[dcr] debug: compiler={}", ctx.compiler);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ pub struct BuildRunFlags {
|
|||||||
pub target: Option<String>,
|
pub target: Option<String>,
|
||||||
pub force: bool,
|
pub force: bool,
|
||||||
pub clean: bool,
|
pub clean: bool,
|
||||||
|
pub verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
||||||
@@ -13,6 +14,7 @@ pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
|||||||
let mut target = None;
|
let mut target = None;
|
||||||
let mut force = false;
|
let mut force = false;
|
||||||
let mut clean = false;
|
let mut clean = false;
|
||||||
|
let mut verbose = false;
|
||||||
let mut iter = args.iter();
|
let mut iter = args.iter();
|
||||||
|
|
||||||
while let Some(arg) = iter.next() {
|
while let Some(arg) = iter.next() {
|
||||||
@@ -29,6 +31,10 @@ pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
|||||||
clean = true;
|
clean = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if candidate == "verbose" {
|
||||||
|
verbose = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if candidate == "target" {
|
if candidate == "target" {
|
||||||
if let Some(t) = iter.next() {
|
if let Some(t) = iter.next() {
|
||||||
target = Some(t.clone());
|
target = Some(t.clone());
|
||||||
@@ -55,5 +61,6 @@ pub fn parse_build_run_flags(args: &[String]) -> Result<BuildRunFlags, i32> {
|
|||||||
target,
|
target,
|
||||||
force,
|
force,
|
||||||
clean,
|
clean,
|
||||||
|
verbose,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -339,6 +339,7 @@ fn collect_project_info_inner(root: &Path, profile: &str) -> Result<ProjectInfo,
|
|||||||
ldflags: &resolved_ldflags,
|
ldflags: &resolved_ldflags,
|
||||||
output_filename: None,
|
output_filename: None,
|
||||||
output_extension: None,
|
output_extension: None,
|
||||||
|
verbose: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let sources = collect_sources(&ctx).map_err(|e| format!("Failed to collect sources: {e}"))?;
|
let sources = collect_sources(&ctx).map_err(|e| format!("Failed to collect sources: {e}"))?;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for obj in &objects {
|
for obj in &objects {
|
||||||
cmd.arg(obj);
|
cmd.arg(obj);
|
||||||
}
|
}
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
@@ -72,7 +72,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
}
|
}
|
||||||
let name = ctx.output_filename.unwrap_or(ctx.project_name);
|
let name = ctx.output_filename.unwrap_or(ctx.project_name);
|
||||||
let ext = ctx.output_extension.unwrap_or("");
|
let ext = ctx.output_extension.unwrap_or("");
|
||||||
let final_name = if ext.is_empty() { name.to_string() } else { format!("{}.{}", name, ext) };
|
let final_name = if ext.is_empty() {
|
||||||
|
name.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}.{}", name, ext)
|
||||||
|
};
|
||||||
|
|
||||||
let out_path = if ctx.kind == "sharedlib" {
|
let out_path = if ctx.kind == "sharedlib" {
|
||||||
platform::shared_lib_path(ctx.profile, &final_name, ctx.target_dir)
|
platform::shared_lib_path(ctx.profile, &final_name, ctx.target_dir)
|
||||||
@@ -81,7 +85,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
};
|
};
|
||||||
cmd.arg("-o").arg(out_path);
|
cmd.arg("-o").arg(out_path);
|
||||||
|
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ pub struct BuildContext<'a> {
|
|||||||
pub ldflags: &'a [String],
|
pub ldflags: &'a [String],
|
||||||
pub output_filename: Option<&'a str>,
|
pub output_filename: Option<&'a str>,
|
||||||
pub output_extension: Option<&'a str>,
|
pub output_extension: Option<&'a str>,
|
||||||
|
pub verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for obj in &objects {
|
for obj in &objects {
|
||||||
cmd.arg(obj);
|
cmd.arg(obj);
|
||||||
}
|
}
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
@@ -97,7 +97,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
};
|
};
|
||||||
cmd.arg(format!("/Fe:{out_path}"));
|
cmd.arg(format!("/Fe:{out_path}"));
|
||||||
|
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for obj in &objects {
|
for obj in &objects {
|
||||||
cmd.arg(obj);
|
cmd.arg(obj);
|
||||||
}
|
}
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
@@ -72,7 +72,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
}
|
}
|
||||||
let name = ctx.output_filename.unwrap_or(ctx.project_name);
|
let name = ctx.output_filename.unwrap_or(ctx.project_name);
|
||||||
let ext = ctx.output_extension.unwrap_or("");
|
let ext = ctx.output_extension.unwrap_or("");
|
||||||
let final_name = if ext.is_empty() { name.to_string() } else { format!("{}.{}", name, ext) };
|
let final_name = if ext.is_empty() {
|
||||||
|
name.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}.{}", name, ext)
|
||||||
|
};
|
||||||
|
|
||||||
let out_path = if ctx.kind == "sharedlib" {
|
let out_path = if ctx.kind == "sharedlib" {
|
||||||
platform::shared_lib_path(ctx.profile, &final_name, ctx.target_dir)
|
platform::shared_lib_path(ctx.profile, &final_name, ctx.target_dir)
|
||||||
@@ -81,7 +85,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
};
|
};
|
||||||
cmd.arg("-o").arg(out_path);
|
cmd.arg("-o").arg(out_path);
|
||||||
|
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
@@ -151,7 +155,7 @@ fn build_object(
|
|||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for obj in &objects {
|
for obj in &objects {
|
||||||
cmd.arg(obj);
|
cmd.arg(obj);
|
||||||
}
|
}
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
@@ -65,7 +65,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
}
|
}
|
||||||
let name = ctx.output_filename.unwrap_or(ctx.project_name);
|
let name = ctx.output_filename.unwrap_or(ctx.project_name);
|
||||||
let ext = ctx.output_extension.unwrap_or("");
|
let ext = ctx.output_extension.unwrap_or("");
|
||||||
let final_name = if ext.is_empty() { name.to_string() } else { format!("{}.{}", name, ext) };
|
let final_name = if ext.is_empty() {
|
||||||
|
name.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}.{}", name, ext)
|
||||||
|
};
|
||||||
|
|
||||||
let out_path = if ctx.kind == "sharedlib" {
|
let out_path = if ctx.kind == "sharedlib" {
|
||||||
platform::shared_lib_path(ctx.profile, &final_name, ctx.target_dir)
|
platform::shared_lib_path(ctx.profile, &final_name, ctx.target_dir)
|
||||||
@@ -74,7 +78,7 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
};
|
};
|
||||||
cmd.arg("-o").arg(out_path);
|
cmd.arg("-o").arg(out_path);
|
||||||
|
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
@@ -214,7 +218,7 @@ fn build_object(
|
|||||||
let d_path = Path::new(obj_path).with_extension("d");
|
let d_path = Path::new(obj_path).with_extension("d");
|
||||||
cmd.arg("-MMD").arg("-MF").arg(&d_path);
|
cmd.arg("-MMD").arg("-MF").arg(&d_path);
|
||||||
|
|
||||||
if std::env::var("DCR_DEBUG").is_ok() {
|
if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() {
|
||||||
eprintln!("[dcr] {:?}", cmd);
|
eprintln!("[dcr] {:?}", cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,23 @@ pub struct DcrConfig {
|
|||||||
pub registry: std::collections::HashMap<String, Registry>,
|
pub registry: std::collections::HashMap<String, Registry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn home_dir() -> Option<PathBuf> {
|
||||||
|
if let Ok(home) = std::env::var("HOME") {
|
||||||
|
return Some(PathBuf::from(home));
|
||||||
|
}
|
||||||
|
if let Ok(profile) = std::env::var("USERPROFILE") {
|
||||||
|
return Some(PathBuf::from(profile));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dcr_config_dir() -> Option<PathBuf> {
|
||||||
|
home_dir().map(|h| h.join(".dcr"))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_registry_config() -> Option<DcrConfig> {
|
pub fn get_registry_config() -> Option<DcrConfig> {
|
||||||
let home = std::env::var("HOME").ok()?;
|
let home = home_dir()?;
|
||||||
let config_path = Path::new(&home).join(".dcr/config.toml");
|
let config_path = home.join(".dcr/config.toml");
|
||||||
if !config_path.exists() {
|
if !config_path.exists() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -30,8 +44,9 @@ pub fn get_index_path() -> PathBuf {
|
|||||||
std::env::var("DCR_INDEX_PATH")
|
std::env::var("DCR_INDEX_PATH")
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
|
dcr_config_dir()
|
||||||
Path::new(&home).join(".dcr").join("index.json")
|
.unwrap_or_else(|| PathBuf::from("."))
|
||||||
|
.join("index.json")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,21 @@ pub struct RegistryManager {
|
|||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn home_dir() -> Option<PathBuf> {
|
||||||
|
if let Ok(home) = std::env::var("HOME") {
|
||||||
|
return Some(PathBuf::from(home));
|
||||||
|
}
|
||||||
|
if let Ok(profile) = std::env::var("USERPROFILE") {
|
||||||
|
return Some(PathBuf::from(profile));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
impl RegistryManager {
|
impl RegistryManager {
|
||||||
pub fn load() -> Result<Self, Box<dyn std::error::Error>> {
|
pub fn load() -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let home = std::env::var("HOME")?;
|
let dcr_dir = home_dir()
|
||||||
let dcr_dir = PathBuf::from(home).join(".dcr");
|
.ok_or("Cannot determine home directory")?
|
||||||
|
.join(".dcr");
|
||||||
let config_path = dcr_dir.join("config.toml");
|
let config_path = dcr_dir.join("config.toml");
|
||||||
|
|
||||||
if !config_path.exists() {
|
if !config_path.exists() {
|
||||||
|
|||||||
Reference in New Issue
Block a user