mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 14:28:30 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c22d2dbddc | |||
| 83061cc460 | |||
| 467e64aa4f | |||
| 7817834790 | |||
| 9fe2604154 | |||
| cb8a3b2001 | |||
| e0fd729635 |
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.2.5] - 2026-02-26
|
||||||
|
Added:
|
||||||
|
- Incremental builds (object caching by mtime)
|
||||||
|
- `build.kind` with `staticlib` support
|
||||||
|
- Custom output directory via `build.target`
|
||||||
|
|
||||||
## [0.2.4] - 2026-02-22
|
## [0.2.4] - 2026-02-22
|
||||||
Added:
|
Added:
|
||||||
- Custom build flags: `build.cflags` and `build.ldflags`
|
- Custom build flags: `build.cflags` and `build.ldflags`
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# Вклад в проект
|
# Contributing
|
||||||
|
|
||||||
Спасибо за интерес к проекту.
|
Thanks for your interest in the project.
|
||||||
|
|
||||||
## Требования
|
## Requirements
|
||||||
|
|
||||||
- Использовать Rust stable.
|
- Use Rust stable.
|
||||||
- Перед PR код должен проходить форматирование, линт и сборку.
|
- Before opening a PR, the code must pass formatting, linting, and build.
|
||||||
|
|
||||||
## Быстрый старт
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/dexoron/dcr.git
|
git clone https://github.com/dexoron/dcr.git
|
||||||
@@ -15,16 +15,16 @@ cd dcr
|
|||||||
cargo check
|
cargo check
|
||||||
```
|
```
|
||||||
|
|
||||||
## Стиль кода
|
## Code Style
|
||||||
|
|
||||||
- Форматируйте код через `cargo fmt`.
|
- Format code with `cargo fmt`.
|
||||||
- Проверяйте предупреждения через `cargo clippy`.
|
- Check warnings with `cargo clippy`.
|
||||||
- Держите функции небольшими и сфокусированными.
|
- Keep functions small and focused.
|
||||||
- Предпочитайте понятные имена вместо "хитрых".
|
- Prefer clear names over clever ones.
|
||||||
|
|
||||||
## Проверки
|
## Checks
|
||||||
|
|
||||||
Перед PR запускайте:
|
Before PR, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo fmt --all
|
cargo fmt --all
|
||||||
@@ -32,26 +32,26 @@ cargo clippy --all-targets --all-features -- -D warnings
|
|||||||
cargo check
|
cargo check
|
||||||
```
|
```
|
||||||
|
|
||||||
## CI/CD и релизы
|
## CI/CD and Releases
|
||||||
|
|
||||||
- CI: `.github/workflows/ci.yml`
|
- CI: `.github/workflows/ci.yml`
|
||||||
- Release: `.github/workflows/release.yml`
|
- Release: `.github/workflows/release.yml`
|
||||||
- Релиз запускается по тегу `v*` и публикует бинарники для:
|
- Releases are triggered by tags `v*` and publish binaries for:
|
||||||
- `x86_64-unknown-linux-gnu`
|
- `x86_64-unknown-linux-gnu`
|
||||||
- `x86_64-apple-darwin`
|
- `x86_64-apple-darwin`
|
||||||
- `aarch64-apple-darwin`
|
- `aarch64-apple-darwin`
|
||||||
- `x86_64-pc-windows-msvc`
|
- `x86_64-pc-windows-msvc`
|
||||||
|
|
||||||
## Коммиты и PR
|
## Commits and PRs
|
||||||
|
|
||||||
- Делайте коммиты понятными.
|
- Write clear commit messages.
|
||||||
- В PR указывайте краткое описание и мотивацию изменений.
|
- In PRs, include a short description and rationale.
|
||||||
- Обновляйте документацию при изменении поведения.
|
- Update documentation when behavior changes.
|
||||||
|
|
||||||
## Вопросы
|
## Questions
|
||||||
|
|
||||||
Если что-то непонятно, открой issue или задайте вопрос в PR.
|
If anything is unclear, open an issue or ask in the PR.
|
||||||
|
|
||||||
Также можно задать вопрос напрямую:
|
You can also reach out directly:
|
||||||
- TG: @dexoron
|
- TG: @dexoron
|
||||||
- DS: dexoron
|
- DS: dexoron
|
||||||
|
|||||||
@@ -118,6 +118,9 @@ Two profiles are supported:
|
|||||||
- `--release` - built-in flags per compiler
|
- `--release` - built-in flags per compiler
|
||||||
|
|
||||||
Custom flags can be added in `dcr.toml` via `build.cflags` and `build.ldflags`.
|
Custom flags can be added in `dcr.toml` via `build.cflags` and `build.ldflags`.
|
||||||
|
You can also set `build.target` to override the output directory (profile-independent).
|
||||||
|
Use `build.kind = "staticlib"` to build a static library instead of a binary.
|
||||||
|
`dcr run` is only for `build.kind = "bin"` and will fail for `staticlib`.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
The main project file is `dcr.toml`.
|
The main project file is `dcr.toml`.
|
||||||
@@ -142,6 +145,8 @@ ldflags = ["-lm"]
|
|||||||
|
|
||||||
Path dependencies are supported. DCR will resolve them on build and generate `dcr.lock`.
|
Path dependencies are supported. DCR will resolve them on build and generate `dcr.lock`.
|
||||||
|
|
||||||
|
Incremental build note: object files are rebuilt when source `.c/.cpp` files change. Header dependency tracking is not implemented yet.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- Rust toolchain (`rustc`, `cargo`) - for building DCR from source
|
- Rust toolchain (`rustc`, `cargo`) - for building DCR from source
|
||||||
- C compiler (`clang`, `gcc`, or 'cl'(msvc))
|
- C compiler (`clang`, `gcc`, or 'cl'(msvc))
|
||||||
|
|||||||
3
TODO.md
3
TODO.md
@@ -1,5 +1,6 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
- Add incremental builds
|
- Add incremental builds
|
||||||
|
- Add header dependency tracking for incremental builds (GCC/Clang: -MMD, MSVC: /showIncludes)
|
||||||
- Add external package managers (Conan, vcpkg)
|
- Add external package managers (Conan, vcpkg)
|
||||||
- Support building static libraries (are .a)
|
- Support building static libraries (ar .a)
|
||||||
|
|||||||
35
docs/README.md
Normal file
35
docs/README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Introduction
|
||||||
|
|
||||||
|
DCR (Dexoron Cargo Realization) is a Cargo-style CLI for C/C++ projects.
|
||||||
|
|
||||||
|
Current DCR focuses on a simple, predictable workflow:
|
||||||
|
|
||||||
|
- create or initialize a project (`dcr new`, `dcr init`)
|
||||||
|
- build with `debug` or `release` profiles (`dcr build`)
|
||||||
|
- run binaries (`dcr run`)
|
||||||
|
- clean artifacts (`dcr clean`)
|
||||||
|
- update the installed binary (`dcr --update`)
|
||||||
|
|
||||||
|
## What is implemented in this version
|
||||||
|
|
||||||
|
- Project configuration in `dcr.toml` with `[package]`, `[build]`, `[dependencies]`.
|
||||||
|
- Recursive source discovery in `src/`:
|
||||||
|
- C: `*.c`
|
||||||
|
- C++: `*.cpp`, `*.cxx`, `*.cc`
|
||||||
|
- Compiler selection from `dcr.toml` (`clang`, `gcc`, `cl`, `clang-cl`, etc.).
|
||||||
|
- Two build kinds:
|
||||||
|
- `bin` (default)
|
||||||
|
- `staticlib`
|
||||||
|
- Optional custom output directory via `build.target`.
|
||||||
|
- Path dependencies with include/lib resolution and `dcr.lock` generation.
|
||||||
|
|
||||||
|
## Important behavior notes
|
||||||
|
|
||||||
|
- `dcr.toml` is required for `build`, `run`, and `clean`.
|
||||||
|
- `run` works only with `build.kind = "bin"`.
|
||||||
|
- Incremental rebuild currently tracks source file timestamps (not header dependency graphs).
|
||||||
|
- Object files are always created under `target/<profile>/obj/`.
|
||||||
|
|
||||||
|
## Repository
|
||||||
|
|
||||||
|
- <https://github.com/dexoron/dcr>
|
||||||
41
docs/SUMMARY.md
Normal file
41
docs/SUMMARY.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Table of contents
|
||||||
|
|
||||||
|
* [Introduction](README.md)
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
* [Installation](getting-started/installation.md)
|
||||||
|
* [Create your first project](getting-started/create-your-first-project.md)
|
||||||
|
* [Project structure](getting-started/project-structure.md)
|
||||||
|
* [Build and run](getting-started/build-and-run.md)
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
* [dcr.toml overview](configuration/dcr.toml-overview.md)
|
||||||
|
* [Package section](configuration/package-section.md)
|
||||||
|
* [Build section](configuration/build-section.md)
|
||||||
|
* [Dependencies section](configuration/dependencies-section.md)
|
||||||
|
* [Build profiles](configuration/build-profiles.md)
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
* [Global options](commands/global-options.md)
|
||||||
|
* [dcr init/new](commands/dcr-init-or-new.md)
|
||||||
|
* [dcr build](commands/dcr-build.md)
|
||||||
|
* [dcr run](commands/dcr-run.md)
|
||||||
|
* [dcr clean](commands/dcr-clean.md)
|
||||||
|
|
||||||
|
## Dependencies & Build
|
||||||
|
|
||||||
|
* [Dependency format](dependencies-and-build/dependency-format.md)
|
||||||
|
* [Local dependencies](dependencies-and-build/local-dependencies.md)
|
||||||
|
* [Versioning & lock file](dependencies-and-build/versioning-and-lock-file.md)
|
||||||
|
* [Target directory](dependencies-and-build/target-directory.md)
|
||||||
|
* [Compilers & linking](dependencies-and-build/compilers-and-linking.md)
|
||||||
|
|
||||||
|
## Reference & Help
|
||||||
|
|
||||||
|
* [CLI reference](reference-and-help/cli-reference.md)
|
||||||
|
* [Config reference](reference-and-help/config-reference.md)
|
||||||
|
* [FAQ](reference-and-help/faq.md)
|
||||||
|
* [Contributing & Bug reports](reference-and-help/contributing-and-bug-reports.md)
|
||||||
42
docs/commands/dcr-build.md
Normal file
42
docs/commands/dcr-build.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# dcr build
|
||||||
|
|
||||||
|
Builds the project in `debug` or `release` profile.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr build
|
||||||
|
dcr build --debug
|
||||||
|
dcr build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## What `build` does
|
||||||
|
|
||||||
|
1. Checks that `dcr.toml` exists and is valid.
|
||||||
|
2. Reads build settings from `[build]`.
|
||||||
|
3. Resolves path dependencies from `[dependencies]`.
|
||||||
|
4. Creates required output directories.
|
||||||
|
5. Recursively compiles sources from `src/`.
|
||||||
|
6. Links final artifact (binary or static library).
|
||||||
|
|
||||||
|
## Config values used
|
||||||
|
|
||||||
|
- `package.name`
|
||||||
|
- `build.compiler`
|
||||||
|
- `build.language`
|
||||||
|
- `build.standard`
|
||||||
|
- `build.kind`
|
||||||
|
- `build.target`
|
||||||
|
- `build.cflags`
|
||||||
|
- `build.ldflags`
|
||||||
|
|
||||||
|
## Source selection
|
||||||
|
|
||||||
|
- `language = "c"` -> `*.c`
|
||||||
|
- `language = "c++" | "cpp" | "cxx"` -> `*.cpp`, `*.cxx`, `*.cc`
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- The profile is selected from the first argument only.
|
||||||
|
- Unknown profile flags return an error.
|
||||||
|
- Incremental rebuild is based on source/object mtime comparison.
|
||||||
23
docs/commands/dcr-clean.md
Normal file
23
docs/commands/dcr-clean.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# dcr clean
|
||||||
|
|
||||||
|
Removes build artifacts in `target/`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr clean
|
||||||
|
dcr clean --debug
|
||||||
|
dcr clean --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Behavior
|
||||||
|
|
||||||
|
- Without arguments: removes entire `target/`.
|
||||||
|
- With profile: removes only `target/<profile>/`.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
- `dcr.toml` must exist.
|
||||||
|
- More than one argument is treated as error.
|
||||||
|
- Unknown profile is treated as error.
|
||||||
|
- If `target` or selected profile directory does not exist, command prints a warning.
|
||||||
43
docs/commands/dcr-init-or-new.md
Normal file
43
docs/commands/dcr-init-or-new.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# dcr init/new
|
||||||
|
|
||||||
|
## `dcr new <name>`
|
||||||
|
|
||||||
|
Creates a new project directory and initializes it.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr new hello
|
||||||
|
```
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
1. Validates arguments (`<name>` is required, only one name is allowed).
|
||||||
|
2. Creates `<name>/`.
|
||||||
|
3. Creates `<name>/dcr.toml`.
|
||||||
|
4. Sets `package.name = "<name>"`.
|
||||||
|
5. Creates `<name>/src/main.c` with a Hello World template.
|
||||||
|
|
||||||
|
Errors:
|
||||||
|
|
||||||
|
- Missing project name.
|
||||||
|
- Extra arguments.
|
||||||
|
- Target directory already exists.
|
||||||
|
|
||||||
|
## `dcr init`
|
||||||
|
|
||||||
|
Initializes DCR in the current directory.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr init
|
||||||
|
```
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
1. Requires current directory to be empty.
|
||||||
|
2. Creates `dcr.toml`.
|
||||||
|
3. Sets `package.name` from the current directory name.
|
||||||
|
4. Creates `src/main.c`.
|
||||||
|
|
||||||
|
Errors:
|
||||||
|
|
||||||
|
- Any arguments are treated as invalid.
|
||||||
|
- Non-empty directory is rejected.
|
||||||
27
docs/commands/dcr-run.md
Normal file
27
docs/commands/dcr-run.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# dcr run
|
||||||
|
|
||||||
|
Builds the project and runs the resulting binary.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr run
|
||||||
|
dcr run --debug
|
||||||
|
dcr run --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Behavior
|
||||||
|
|
||||||
|
1. Validates `dcr.toml`.
|
||||||
|
2. Reads `package.name`, `build.kind`, and optional `build.target`.
|
||||||
|
3. Runs the same build flow as `dcr build`.
|
||||||
|
4. Executes the built artifact path for the selected profile.
|
||||||
|
|
||||||
|
## Restrictions
|
||||||
|
|
||||||
|
- If `build.kind = "staticlib"`, `run` exits with error.
|
||||||
|
- The profile is selected from the first argument.
|
||||||
|
|
||||||
|
## On build failure
|
||||||
|
|
||||||
|
`dcr run` attempts to launch an existing binary from the same profile if present; otherwise it reports that code errors must be fixed.
|
||||||
44
docs/commands/global-options.md
Normal file
44
docs/commands/global-options.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Global options
|
||||||
|
|
||||||
|
## `dcr --help`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr --help
|
||||||
|
```
|
||||||
|
|
||||||
|
Prints top-level CLI usage, commands, flags, and examples.
|
||||||
|
|
||||||
|
## `dcr --version`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Prints:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dcr <version> (<target>)
|
||||||
|
```
|
||||||
|
|
||||||
|
## `dcr --update`
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr --update
|
||||||
|
```
|
||||||
|
|
||||||
|
Update flow:
|
||||||
|
|
||||||
|
1. Requests latest release from GitHub API.
|
||||||
|
2. Finds asset matching current `DCR_TARGET`.
|
||||||
|
3. Downloads replacement binary.
|
||||||
|
4. Replaces current executable via `self-replace`.
|
||||||
|
|
||||||
|
Limitations and behavior:
|
||||||
|
|
||||||
|
- No extra arguments are accepted.
|
||||||
|
- Requires network access to GitHub API/assets.
|
||||||
|
- On Linux, if binary is owned by pacman, DCR prints package-manager update instructions instead of self-updating.
|
||||||
|
|
||||||
|
## Running without command
|
||||||
|
|
||||||
|
Running plain `dcr` (without arguments) shows help output.
|
||||||
39
docs/configuration/build-profiles.md
Normal file
39
docs/configuration/build-profiles.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Build profiles
|
||||||
|
|
||||||
|
DCR supports two profiles:
|
||||||
|
|
||||||
|
- `debug` (default)
|
||||||
|
- `release`
|
||||||
|
|
||||||
|
## How to select
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr build --debug
|
||||||
|
dcr build --release
|
||||||
|
dcr run --release
|
||||||
|
dcr clean --debug
|
||||||
|
```
|
||||||
|
|
||||||
|
## Default profile flags
|
||||||
|
|
||||||
|
### GCC/Clang-like toolchains
|
||||||
|
|
||||||
|
- `debug`: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG`
|
||||||
|
- `release`: `-O3 -DNDEBUG -march=native`
|
||||||
|
|
||||||
|
### MSVC toolchain
|
||||||
|
|
||||||
|
- `debug`: `/Od /Zi /W4 /DDEBUG /Oy-`
|
||||||
|
- `release`: `/O2 /DNDEBUG`
|
||||||
|
|
||||||
|
## Artifacts
|
||||||
|
|
||||||
|
By default:
|
||||||
|
|
||||||
|
- `target/debug/<name>` (or `.exe` on Windows)
|
||||||
|
- `target/release/<name>` (or `.exe` on Windows)
|
||||||
|
|
||||||
|
Static library mode (`kind = "staticlib"`):
|
||||||
|
|
||||||
|
- Linux/macOS: `lib<name>.a`
|
||||||
|
- Windows: `<name>.lib`
|
||||||
31
docs/configuration/build-section.md
Normal file
31
docs/configuration/build-section.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Build section
|
||||||
|
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[build]
|
||||||
|
language = "c"
|
||||||
|
standard = "c11"
|
||||||
|
compiler = "clang"
|
||||||
|
kind = "bin"
|
||||||
|
# optional:
|
||||||
|
# target = "./dist"
|
||||||
|
# cflags = ["-Wall"]
|
||||||
|
# ldflags = ["-lm"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
- `language` (string, required): `c`, `c++`, `cpp`, or `cxx`.
|
||||||
|
- `standard` (string, required): language standard passed to compiler.
|
||||||
|
- `compiler` (string, required): compiler command (for example `clang`, `gcc`, `cl`).
|
||||||
|
- `kind` (string, required): `bin` or `staticlib`.
|
||||||
|
- `target` (string, optional): custom output directory for final artifact.
|
||||||
|
- `cflags` (string array, optional): extra compile flags.
|
||||||
|
- `ldflags` (string array, optional): extra link flags.
|
||||||
|
|
||||||
|
## Behavior notes
|
||||||
|
|
||||||
|
- Compiler backend is selected by compiler string (`gcc`, `clang`, `cl`, `clang-cl`).
|
||||||
|
- Empty or unknown compiler value falls back to clang-like build path.
|
||||||
|
- `run` is not allowed for `kind = "staticlib"`.
|
||||||
45
docs/configuration/dcr.toml-overview.md
Normal file
45
docs/configuration/dcr.toml-overview.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# dcr.toml overview
|
||||||
|
|
||||||
|
`dcr.toml` is the main project file used by DCR.
|
||||||
|
|
||||||
|
## Minimal generated template
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "hello"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
language = "c"
|
||||||
|
standard = "c11"
|
||||||
|
compiler = "clang"
|
||||||
|
kind = "bin"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
```
|
||||||
|
|
||||||
|
`dcr new` and `dcr init` generate this structure automatically.
|
||||||
|
|
||||||
|
## Required sections
|
||||||
|
|
||||||
|
- `[package]`
|
||||||
|
- `[build]`
|
||||||
|
- `[dependencies]`
|
||||||
|
|
||||||
|
## Required keys
|
||||||
|
|
||||||
|
- `package.name`
|
||||||
|
- `package.version`
|
||||||
|
- `build.language`
|
||||||
|
- `build.standard`
|
||||||
|
- `build.compiler`
|
||||||
|
- `build.kind`
|
||||||
|
|
||||||
|
`build.kind` must be either `bin` or `staticlib`.
|
||||||
|
|
||||||
|
## Optional keys
|
||||||
|
|
||||||
|
- `build.target`
|
||||||
|
- `build.cflags`
|
||||||
|
- `build.ldflags`
|
||||||
|
- dependency fields (`include`, `lib`, `libs`, `system`)
|
||||||
30
docs/configuration/dependencies-section.md
Normal file
30
docs/configuration/dependencies-section.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Dependencies section
|
||||||
|
|
||||||
|
DCR currently supports path dependencies.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
frecli = { path = "./lib/frecli", include = ["."], lib = ["."], libs = ["frecli"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported fields per dependency
|
||||||
|
|
||||||
|
- `path` (string, required): absolute path or path relative to project root.
|
||||||
|
- `include` (string array, optional): include directories inside dependency.
|
||||||
|
- `lib` (string array, optional): library directories inside dependency.
|
||||||
|
- `libs` (string array, optional): library names for linker.
|
||||||
|
- `system` (bool, optional): currently `system = true` is rejected.
|
||||||
|
|
||||||
|
## Defaults
|
||||||
|
|
||||||
|
- If `include` is omitted, DCR tries `<dep>/include`.
|
||||||
|
- If `lib` is omitted, DCR tries `<dep>/lib`, then `<dep>/lib64`.
|
||||||
|
- If `libs` is omitted, dependency key name is used.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
- Dependency value must be a TOML table.
|
||||||
|
- `path` is mandatory.
|
||||||
|
- `include`/`lib`/`libs` must be arrays of strings if provided.
|
||||||
20
docs/configuration/package-section.md
Normal file
20
docs/configuration/package-section.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Package section
|
||||||
|
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "my-app"
|
||||||
|
version = "0.1.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
- `name` (string, required): used as output artifact base name.
|
||||||
|
- `version` (string, required): used in `dcr.lock` project entry.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Empty `name` or `version` makes config invalid.
|
||||||
|
- `dcr new` sets `name` from the passed project name.
|
||||||
|
- `dcr init` sets `name` from current directory name.
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# dcr.toml
|
|
||||||
|
|
||||||
`dcr.toml` describes your project, build options, and dependencies.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[package]
|
|
||||||
name = "neoarc-frontent"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[build]
|
|
||||||
language = "c"
|
|
||||||
standard = "c11"
|
|
||||||
compiler = "gcc"
|
|
||||||
# Custom compile/link flags (optional)
|
|
||||||
cflags = ["-D_POSIX_C_SOURCE=200809L", "-Wall", "-Wextra", "-O2", "-Ilib/frecli"]
|
|
||||||
ldflags = ["-Llib/frecli", "-lfrecli", "-lm"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
frecli = { path = "./lib/frecli", include = ["."], lib = ["."], libs = ["frecli"] }
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sections
|
|
||||||
|
|
||||||
### [package]
|
|
||||||
- `name` (string, required)
|
|
||||||
- `version` (string, required)
|
|
||||||
|
|
||||||
### [build]
|
|
||||||
- `language` (string, required): `c`, `c++`, `cpp`, or `cxx`
|
|
||||||
- `standard` (string, required): e.g. `c99`, `c11`, `c++17`
|
|
||||||
- `compiler` (string, required): `gcc`, `clang`, `cl`(msvc), or `clang-cl`
|
|
||||||
- `cflags` (string[], optional): additional compile flags
|
|
||||||
- `ldflags` (string[], optional): additional link flags
|
|
||||||
|
|
||||||
### [dependencies]
|
|
||||||
Only `path` dependencies are supported right now.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
fmt = { path = "./lib/fmt", include = ["include"], lib = ["lib"], libs = ["fmt"] }
|
|
||||||
```
|
|
||||||
|
|
||||||
Rules:
|
|
||||||
- `path` can be absolute or relative to the project root.
|
|
||||||
- If `include`/`lib` are missing, DCR looks for `include`, `lib`, or `lib64` under the dependency path.
|
|
||||||
- If not found, build fails with a message suggesting to add `include`/`lib`.
|
|
||||||
- `libs` defaults to the dependency name.
|
|
||||||
|
|
||||||
## Source Discovery
|
|
||||||
|
|
||||||
DCR compiles all `.c`/`.cpp` files under `src/` recursively. The file containing `main()` can be located anywhere in that tree.
|
|
||||||
30
docs/dependencies-and-build/compilers-and-linking.md
Normal file
30
docs/dependencies-and-build/compilers-and-linking.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Compilers & linking
|
||||||
|
|
||||||
|
## Compiler backend selection
|
||||||
|
|
||||||
|
DCR picks a backend from `build.compiler`:
|
||||||
|
|
||||||
|
- contains `clang-cl` -> MSVC backend
|
||||||
|
- contains `gcc` or `g++` -> GCC backend
|
||||||
|
- contains `clang` or `clang++` -> Clang backend
|
||||||
|
- equals `cl` or contains `msvc` -> MSVC backend
|
||||||
|
- otherwise -> Clang backend fallback
|
||||||
|
|
||||||
|
## Compilation model
|
||||||
|
|
||||||
|
- Source files are found recursively in `src/` based on `build.language`.
|
||||||
|
- Each source is compiled to `target/<profile>/obj/<relative-path>.o` (`.obj` on MSVC).
|
||||||
|
- Recompile happens when source mtime is newer than object mtime.
|
||||||
|
|
||||||
|
## Linking
|
||||||
|
|
||||||
|
For `kind = "bin"`:
|
||||||
|
|
||||||
|
- Object files are linked into executable artifact.
|
||||||
|
- Dependency lib dirs and library names are passed to linker.
|
||||||
|
- `build.ldflags` are appended to link command.
|
||||||
|
|
||||||
|
For `kind = "staticlib"`:
|
||||||
|
|
||||||
|
- Linux/macOS (GCC/Clang): `ar rcs` creates `.a` archive.
|
||||||
|
- Windows (MSVC): `lib` creates `.lib` archive.
|
||||||
26
docs/dependencies-and-build/dependency-format.md
Normal file
26
docs/dependencies-and-build/dependency-format.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Dependency format
|
||||||
|
|
||||||
|
Dependencies are defined in `dcr.toml` under `[dependencies]`.
|
||||||
|
|
||||||
|
## Full example
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
fmt = { path = "./third_party/fmt", include = ["include"], lib = ["lib"], libs = ["fmt"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Field reference
|
||||||
|
|
||||||
|
- `path`: required dependency root path.
|
||||||
|
- `include`: optional include subpaths (absolute or relative to dep root).
|
||||||
|
- `lib`: optional library subpaths (absolute or relative to dep root).
|
||||||
|
- `libs`: optional linker library names.
|
||||||
|
|
||||||
|
## Common valid compact form
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
mylib = { path = "./libs/mylib" }
|
||||||
|
```
|
||||||
|
|
||||||
|
In this form DCR will try defaults for include/lib dirs and use `mylib` as the linker library name.
|
||||||
19
docs/dependencies-and-build/local-dependencies.md
Normal file
19
docs/dependencies-and-build/local-dependencies.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Local dependencies
|
||||||
|
|
||||||
|
## Resolution flow during build
|
||||||
|
|
||||||
|
For each dependency in `[dependencies]`, DCR:
|
||||||
|
|
||||||
|
1. Resolves `path` (absolute or project-relative).
|
||||||
|
2. Resolves include dirs (`include` or default `include`).
|
||||||
|
3. Resolves lib dirs (`lib` or defaults `lib`, `lib64`).
|
||||||
|
4. Resolves link libs (`libs` or dependency name).
|
||||||
|
5. Synchronizes dependency files to `target/<profile>/deps/<dep-name>/`.
|
||||||
|
6. Adds include/lib/link options to compile/link commands.
|
||||||
|
|
||||||
|
## Failure cases
|
||||||
|
|
||||||
|
- Dependency path is missing or not a directory.
|
||||||
|
- No valid include/lib directories were found.
|
||||||
|
- Any configured include/lib path does not exist.
|
||||||
|
- Invalid field types in dependency config.
|
||||||
23
docs/dependencies-and-build/target-directory.md
Normal file
23
docs/dependencies-and-build/target-directory.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Target directory
|
||||||
|
|
||||||
|
By default, DCR writes final artifacts to `target/<profile>/`.
|
||||||
|
|
||||||
|
You can override this with `build.target`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[build]
|
||||||
|
target = "./dist"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Behavior
|
||||||
|
|
||||||
|
- Binary mode:
|
||||||
|
- Linux/macOS: `<target>/<name>`
|
||||||
|
- Windows: `<target>/<name>.exe`
|
||||||
|
- Static library mode:
|
||||||
|
- Linux/macOS: `<target>/lib<name>.a`
|
||||||
|
- Windows: `<target>/<name>.lib`
|
||||||
|
|
||||||
|
## Important detail
|
||||||
|
|
||||||
|
`build.target` changes only the final artifact location. Object cache and dependency sync directories still use `target/<profile>/...`.
|
||||||
32
docs/dependencies-and-build/versioning-and-lock-file.md
Normal file
32
docs/dependencies-and-build/versioning-and-lock-file.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Versioning & lock file
|
||||||
|
|
||||||
|
DCR generates `dcr.lock` when dependency resolution succeeds and at least one dependency exists.
|
||||||
|
|
||||||
|
## What is stored
|
||||||
|
|
||||||
|
- Project entry (`name`, `version`, dependency names).
|
||||||
|
- One entry per resolved dependency:
|
||||||
|
- `name`
|
||||||
|
- `version` (from dependency `dcr.toml`, fallback `0.0.0`)
|
||||||
|
- `source` (`path+...`)
|
||||||
|
- `checksum` (SHA-256 over dependency files, excluding nested `target/`).
|
||||||
|
|
||||||
|
## Example shape
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[package]]
|
||||||
|
name = "my-app"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = ["fmt"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fmt"
|
||||||
|
version = "1.2.3"
|
||||||
|
source = "path+./third_party/fmt"
|
||||||
|
checksum = "..."
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `dcr.lock` is rewritten on successful dependency resolution.
|
||||||
|
- If `[dependencies]` is empty, lock generation is skipped.
|
||||||
46
docs/getting-started/build-and-run.md
Normal file
46
docs/getting-started/build-and-run.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Build and run
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Debug (default):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr build
|
||||||
|
# or
|
||||||
|
dcr build --debug
|
||||||
|
```
|
||||||
|
|
||||||
|
Release:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr run
|
||||||
|
# or
|
||||||
|
dcr run --release
|
||||||
|
```
|
||||||
|
|
||||||
|
`dcr run` first builds, then launches the produced binary.
|
||||||
|
|
||||||
|
## Clean artifacts
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr clean
|
||||||
|
```
|
||||||
|
|
||||||
|
Profile-only cleanup:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr clean --debug
|
||||||
|
dcr clean --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- `run` is unavailable for `build.kind = "staticlib"`.
|
||||||
|
- Build profile flag is parsed from the first command argument.
|
||||||
|
- Unknown profile flags produce an error.
|
||||||
41
docs/getting-started/create-your-first-project.md
Normal file
41
docs/getting-started/create-your-first-project.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Create your first project
|
||||||
|
|
||||||
|
## Create in a new folder
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr new hello
|
||||||
|
cd hello
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates:
|
||||||
|
|
||||||
|
```text
|
||||||
|
hello/
|
||||||
|
- dcr.toml
|
||||||
|
- src/
|
||||||
|
- - main.c
|
||||||
|
```
|
||||||
|
|
||||||
|
## Or initialize current folder
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir hello
|
||||||
|
cd hello
|
||||||
|
dcr init
|
||||||
|
```
|
||||||
|
|
||||||
|
`dcr init` requires the current directory to be empty.
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
|
||||||
|
Build and run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr run
|
||||||
|
```
|
||||||
|
|
||||||
|
Release build/run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr run --release
|
||||||
|
```
|
||||||
56
docs/getting-started/installation.md
Normal file
56
docs/getting-started/installation.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Installation
|
||||||
|
|
||||||
|
## Option 1: Install via script
|
||||||
|
|
||||||
|
### Linux/macOS
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -fsSL https://dcr.dexoron.su/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternative with `wget`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
wget -qO- https://dcr.dexoron.su/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows (PowerShell)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell -ExecutionPolicy ByPass -c "irm https://dcr.dexoron.su/install.ps1 | iex"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Option 2: Build from source
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/dexoron/dcr.git
|
||||||
|
cd dcr
|
||||||
|
cargo build --release
|
||||||
|
mkdir -p ~/.local/bin
|
||||||
|
ln -sf "$PWD/target/release/dcr" ~/.local/bin/dcr
|
||||||
|
```
|
||||||
|
|
||||||
|
## Option 3: Arch Linux (AUR)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yay -S dcr
|
||||||
|
```
|
||||||
|
|
||||||
|
(You can also use `paru` or other AUR helpers.)
|
||||||
|
|
||||||
|
## Verify installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dcr --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
dcr <version> (<target>)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Update policy
|
||||||
|
|
||||||
|
- If DCR was installed from GitHub releases, scripts, or manual build: use `dcr --update`.
|
||||||
|
- If DCR is managed by `pacman/AUR`: update via package manager. On Linux, `dcr --update` detects pacman-owned binaries and prints a package-manager hint.
|
||||||
39
docs/getting-started/project-structure.md
Normal file
39
docs/getting-started/project-structure.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Project structure
|
||||||
|
|
||||||
|
## Minimal project
|
||||||
|
|
||||||
|
```text
|
||||||
|
project/
|
||||||
|
- dcr.toml
|
||||||
|
- src/
|
||||||
|
- - main.c
|
||||||
|
```
|
||||||
|
|
||||||
|
## Typical generated/optional files
|
||||||
|
|
||||||
|
```text
|
||||||
|
project/
|
||||||
|
- dcr.toml
|
||||||
|
- dcr.lock
|
||||||
|
- src/
|
||||||
|
- - ... source files ...
|
||||||
|
- target/
|
||||||
|
- - debug/
|
||||||
|
- - - obj/
|
||||||
|
- - - deps/
|
||||||
|
- - release/
|
||||||
|
- - - obj/
|
||||||
|
- - - deps/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Meaning
|
||||||
|
|
||||||
|
- `dcr.toml`: main project configuration.
|
||||||
|
- `dcr.lock`: generated lock file for resolved path dependencies.
|
||||||
|
- `src/`: recursively scanned source directory.
|
||||||
|
- `target/<profile>/obj/`: cached object files for incremental rebuild.
|
||||||
|
- `target/<profile>/deps/`: synchronized copies of path dependencies.
|
||||||
|
- `target/<profile>/<name>` (or `.exe` on Windows): output for `kind = "bin"`.
|
||||||
|
- `target/<profile>/lib<name>.a` (or `<name>.lib` on Windows): output for `kind = "staticlib"`.
|
||||||
|
|
||||||
|
If `build.target` is set, the final artifact is written to that custom directory, while object cache still stays in `target/<profile>/obj`.
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# DCR Documentation
|
|
||||||
|
|
||||||
DCR is a lightweight build tool for C/C++ projects with a Cargo-like workflow.
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
```sh
|
|
||||||
dcr new hello
|
|
||||||
cd hello
|
|
||||||
dcr run
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Project configuration lives in `dcr.toml`.
|
|
||||||
See `docs/dcr-toml.md` for the full schema and examples.
|
|
||||||
|
|
||||||
## Build Flags
|
|
||||||
|
|
||||||
You can add custom compile and link flags in `[build]`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[build]
|
|
||||||
compiler = "gcc"
|
|
||||||
standard = "c99"
|
|
||||||
cflags = ["-D_POSIX_C_SOURCE=200809L", "-Wall", "-Wextra", "-O2", "-Ilib/frecli"]
|
|
||||||
ldflags = ["-Llib/frecli", "-lfrecli", "-lm"]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
Path dependencies can be declared in `[dependencies]` and are resolved on build.
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
frecli = { path = "./lib/frecli", include = ["."], lib = ["."], libs = ["frecli"] }
|
|
||||||
```
|
|
||||||
|
|
||||||
## Source Discovery
|
|
||||||
|
|
||||||
DCR compiles all `.c`/`.cpp` files under `src/` recursively. The file containing `main()` can be in any subdirectory.
|
|
||||||
26
docs/reference-and-help/cli-reference.md
Normal file
26
docs/reference-and-help/cli-reference.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# CLI reference
|
||||||
|
|
||||||
|
## Command list
|
||||||
|
|
||||||
|
```text
|
||||||
|
dcr new <name>
|
||||||
|
dcr init
|
||||||
|
dcr build [--debug|--release]
|
||||||
|
dcr run [--debug|--release]
|
||||||
|
dcr clean [--debug|--release]
|
||||||
|
dcr --help
|
||||||
|
dcr --version
|
||||||
|
dcr --update
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes on argument parsing
|
||||||
|
|
||||||
|
- Most commands parse profile from the first argument.
|
||||||
|
- `new` requires exactly one argument.
|
||||||
|
- `init` and `--update` do not accept extra arguments.
|
||||||
|
- `clean` accepts at most one argument.
|
||||||
|
|
||||||
|
## Exit behavior overview
|
||||||
|
|
||||||
|
- Successful command execution returns `0`.
|
||||||
|
- Validation/build/runtime errors return non-zero status.
|
||||||
41
docs/reference-and-help/config-reference.md
Normal file
41
docs/reference-and-help/config-reference.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Config reference
|
||||||
|
|
||||||
|
## Full schema
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[package]
|
||||||
|
name = "string" # required
|
||||||
|
version = "string" # required
|
||||||
|
|
||||||
|
[build]
|
||||||
|
language = "c|c++|cpp|cxx" # required
|
||||||
|
standard = "string" # required
|
||||||
|
compiler = "string" # required
|
||||||
|
kind = "bin|staticlib" # required
|
||||||
|
target = "string" # optional
|
||||||
|
cflags = ["string", "..."] # optional
|
||||||
|
ldflags = ["string", "..."] # optional
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
name = {
|
||||||
|
path = "string", # required for each dependency
|
||||||
|
include = ["string", "..."], # optional
|
||||||
|
lib = ["string", "..."], # optional
|
||||||
|
libs = ["string", "..."], # optional
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Validation rules
|
||||||
|
|
||||||
|
- `[package]`, `[build]`, `[dependencies]` must exist.
|
||||||
|
- Required string fields must be non-empty.
|
||||||
|
- `build.kind` must be `bin` or `staticlib`.
|
||||||
|
- Dependency fields `include/lib/libs` must be string arrays when provided.
|
||||||
|
|
||||||
|
## Generated defaults (`dcr new` / `dcr init`)
|
||||||
|
|
||||||
|
- `package.version = "0.1.0"`
|
||||||
|
- `build.language = "c"`
|
||||||
|
- `build.standard = "c11"`
|
||||||
|
- `build.compiler = "clang"`
|
||||||
|
- `build.kind = "bin"`
|
||||||
34
docs/reference-and-help/contributing-and-bug-reports.md
Normal file
34
docs/reference-and-help/contributing-and-bug-reports.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Contributing & Bug reports
|
||||||
|
|
||||||
|
## Contribution workflow
|
||||||
|
|
||||||
|
1. Fork `dexoron/dcr` (and `dexoron/dcr-site` if docs website changes are needed).
|
||||||
|
2. Make focused changes.
|
||||||
|
3. Run checks locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
cargo check
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Open a PR with short rationale and behavior impact.
|
||||||
|
5. Update docs when CLI behavior changes.
|
||||||
|
|
||||||
|
## Bug report checklist
|
||||||
|
|
||||||
|
Include:
|
||||||
|
|
||||||
|
1. DCR version (`dcr --version`).
|
||||||
|
2. OS and compiler/toolchain version.
|
||||||
|
3. Reproduction steps.
|
||||||
|
4. Expected result.
|
||||||
|
5. Actual result and full error output.
|
||||||
|
6. Minimal reproducible project.
|
||||||
|
|
||||||
|
## Where to report
|
||||||
|
|
||||||
|
Use GitHub Issues in the relevant repository:
|
||||||
|
|
||||||
|
- <https://github.com/dexoron/dcr>
|
||||||
|
- <https://github.com/dexoron/dcr-site>
|
||||||
34
docs/reference-and-help/faq.md
Normal file
34
docs/reference-and-help/faq.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# FAQ
|
||||||
|
|
||||||
|
## What commands are available?
|
||||||
|
|
||||||
|
`new`, `init`, `build`, `run`, `clean`, `--help`, `--version`, `--update`.
|
||||||
|
|
||||||
|
## Is `dcr.toml` mandatory?
|
||||||
|
|
||||||
|
Yes, for `build`, `run`, and `clean`.
|
||||||
|
|
||||||
|
## What source files are compiled?
|
||||||
|
|
||||||
|
DCR scans `src/` recursively:
|
||||||
|
|
||||||
|
- for C: `*.c`
|
||||||
|
- for C++: `*.cpp`, `*.cxx`, `*.cc`
|
||||||
|
|
||||||
|
## Can I switch compiler?
|
||||||
|
|
||||||
|
Yes. Set `build.compiler` in `dcr.toml` (for example `gcc`, `clang`, `cl`, `clang-cl`).
|
||||||
|
|
||||||
|
## How does incremental rebuild work?
|
||||||
|
|
||||||
|
It compares source file mtime with object file mtime. Header dependency tracking is not implemented yet.
|
||||||
|
|
||||||
|
## What does `dcr run` do if build fails?
|
||||||
|
|
||||||
|
It tries to run an existing binary from the selected profile; if none exists, it reports an error.
|
||||||
|
|
||||||
|
## How do I update DCR?
|
||||||
|
|
||||||
|
Use `dcr --update` for non-package-managed installs.
|
||||||
|
|
||||||
|
If installed through pacman/AUR, update via package manager.
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
# Вклад в проект
|
|
||||||
|
|
||||||
Спасибо за интерес к проекту.
|
|
||||||
|
|
||||||
## Требования
|
|
||||||
|
|
||||||
- Использовать Rust stable.
|
|
||||||
- Перед PR код должен проходить форматирование, линт и сборку.
|
|
||||||
|
|
||||||
## Быстрый старт
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/dexoron/dcr.git
|
|
||||||
cd dcr
|
|
||||||
cargo check
|
|
||||||
```
|
|
||||||
|
|
||||||
## Стиль кода
|
|
||||||
|
|
||||||
- Форматируйте код через `cargo fmt`.
|
|
||||||
- Проверяйте предупреждения через `cargo clippy`.
|
|
||||||
- Держите функции небольшими и сфокусированными.
|
|
||||||
- Предпочитайте понятные имена вместо "хитрых".
|
|
||||||
|
|
||||||
## Проверки
|
|
||||||
|
|
||||||
Перед PR запускайте:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo fmt --all
|
|
||||||
cargo clippy --all-targets --all-features -- -D warnings
|
|
||||||
cargo check
|
|
||||||
```
|
|
||||||
|
|
||||||
## CI/CD и релизы
|
|
||||||
|
|
||||||
- CI: `.github/workflows/ci.yml`
|
|
||||||
- Release: `.github/workflows/release.yml`
|
|
||||||
- Релиз запускается по тегу `v*` и публикует бинарники для:
|
|
||||||
- `x86_64-unknown-linux-gnu`
|
|
||||||
- `x86_64-apple-darwin`
|
|
||||||
- `aarch64-apple-darwin`
|
|
||||||
- `x86_64-pc-windows-msvc`
|
|
||||||
|
|
||||||
## Коммиты и PR
|
|
||||||
|
|
||||||
- Делайте коммиты понятными.
|
|
||||||
- В PR указывайте краткое описание и мотивацию изменений.
|
|
||||||
- Обновляйте документацию при изменении поведения.
|
|
||||||
|
|
||||||
## Вопросы
|
|
||||||
|
|
||||||
Если что-то непонятно, открой issue или задайте вопрос в PR.
|
|
||||||
|
|
||||||
Также можно задать вопрос напрямую:
|
|
||||||
- TG: @dexoron
|
|
||||||
- DS: dexoron
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
# FAQ
|
|
||||||
|
|
||||||
## В чем суть проекта?
|
|
||||||
`dcr` - это инструмент для управления C/C++ проектами и их зависимостями.
|
|
||||||
Он вдохновлен Cargo, но не является аналогом Makefile, CMake или других классических систем сборки.
|
|
||||||
|
|
||||||
Цель проекта - дать более простую и удобную в настройке среду для разработки.
|
|
||||||
|
|
||||||
## Как разрабатывается проект?
|
|
||||||
Проект написан на Rust и в основном развивается одним разработчиком - Dexoron.
|
|
||||||
|
|
||||||
В работе используются ИИ-инструменты, но они не пишут проект целиком: их роль - помощь с отдельными задачами (например, советы, проверка формулировок, переводы и т.д.).
|
|
||||||
|
|
||||||
## Какие инструменты используются для разработки?
|
|
||||||
Основной стек разработки:
|
|
||||||
- `RustRover` 2025 - IDE для разработки.
|
|
||||||
- `Codex` (`GPT-5.3-Codex (medium)`) - основной ИИ-инструмент, интегрированный через JetBrains AI Chat.
|
|
||||||
- `Rust` - основной язык проекта.
|
|
||||||
- `Cargo` - инструмент сборки, тестов и управления зависимостями Rust-проектов.
|
|
||||||
|
|
||||||
## Проект открытый?
|
|
||||||
Да, проект открыт (Open Source).
|
|
||||||
Вы можете предлагать идеи, находить ошибки и вносить изменения в код.
|
|
||||||
|
|
||||||
Проект распространяется по лицензии MIT (см. `LICENSE`).
|
|
||||||
|
|
||||||
## Как внести вклад?
|
|
||||||
Спасибо за желание помочь проекту.
|
|
||||||
Вы можете:
|
|
||||||
- помочь с кодом;
|
|
||||||
- помочь с переводом;
|
|
||||||
- помочь с документацией;
|
|
||||||
- предложить идею или сообщить о баге.
|
|
||||||
|
|
||||||
### Если вы хотите внести изменения (код, перевод, документация)
|
|
||||||
1. Сделайте форк нужного репозитория: `dexoron/dcr` (основной проект) или `dexoron/dcr-site` (сайт проекта).
|
|
||||||
2. Внесите изменения с учетом правил из `CONTRIBUTING.md`.
|
|
||||||
3. Отправьте изменения в свой форк.
|
|
||||||
4. Создайте Pull Request.
|
|
||||||
5. Дождитесь ревью.
|
|
||||||
|
|
||||||
### Если вы хотите сообщить о проблеме или предложить идею
|
|
||||||
1. Откройте нужный репозиторий: `dexoron/dcr` или `dexoron/dcr-site`.
|
|
||||||
2. Перейдите во вкладку `Issues`.
|
|
||||||
3. Создайте Issue и укажите тип (баг, предложение, вопрос/помощь).
|
|
||||||
4. Опишите проблему или идею кратко и понятно.
|
|
||||||
5. Дождитесь обратной связи.
|
|
||||||
|
|
||||||
## Как установить `dcr`?
|
|
||||||
Актуальные способы установки зависят от текущей версии проекта.
|
|
||||||
Рекомендуемый путь:
|
|
||||||
- проверьте инструкции в `README.md`;
|
|
||||||
- если готового пакета для вашей платформы нет, соберите проект из исходников через `cargo build --release`.
|
|
||||||
|
|
||||||
## Как быстро начать работу?
|
|
||||||
Минимальный сценарий:
|
|
||||||
1. Установите `dcr`.
|
|
||||||
2. Создайте проект (или перейдите в существующий C/C++ проект).
|
|
||||||
3. Инициализируйте конфигурацию `dcr`.
|
|
||||||
4. Добавьте зависимости проекта.
|
|
||||||
5. Запустите сборку через `dcr`.
|
|
||||||
|
|
||||||
Подробные команды и примеры смотрите в `README.md` и документации проекта.
|
|
||||||
|
|
||||||
## На какой стадии проект?
|
|
||||||
`dcr` активно развивается.
|
|
||||||
Это означает, что интерфейсы и поведение некоторых функций могут меняться между версиями.
|
|
||||||
|
|
||||||
Перед обновлением рекомендуется читать changelog и проверять заметки к релизу.
|
|
||||||
|
|
||||||
## С какими системами работает `dcr`?
|
|
||||||
`dcr` ориентирован на современные среды разработки C/C++.
|
|
||||||
Фактическая совместимость зависит от версии `dcr`, операционной системы и используемого toolchain.
|
|
||||||
|
|
||||||
Перед началом работы проверьте в документации:
|
|
||||||
- поддерживаемые ОС;
|
|
||||||
- поддерживаемые компиляторы и линкеры;
|
|
||||||
- ограничения конкретной версии.
|
|
||||||
|
|
||||||
## Чем `dcr` отличается от Make/CMake?
|
|
||||||
`dcr` не пытается быть прямой заменой Make/CMake.
|
|
||||||
Главный фокус `dcr` - упростить управление проектом и зависимостями в стиле, близком к опыту Cargo.
|
|
||||||
|
|
||||||
Если вам нужен низкоуровневый полный контроль над процессом сборки, классические инструменты могут быть привычнее.
|
|
||||||
Если нужна более простая и единообразная модель конфигурации - `dcr` может быть удобнее.
|
|
||||||
|
|
||||||
## Где смотреть документацию и примеры?
|
|
||||||
Основные источники:
|
|
||||||
- `README.md` в репозитории;
|
|
||||||
- документация проекта (смотреть сайт проекта);
|
|
||||||
- `Issues` для известных проблем и обсуждений;
|
|
||||||
|
|
||||||
## Как правильно сообщить о баге?
|
|
||||||
Чтобы баг-репорт можно было быстро воспроизвести, укажите:
|
|
||||||
1. Версию `dcr`.
|
|
||||||
2. ОС и версию компилятора/toolchain.
|
|
||||||
3. Шаги воспроизведения.
|
|
||||||
4. Ожидаемое поведение.
|
|
||||||
5. Фактическое поведение и текст ошибки.
|
|
||||||
6. Минимальный пример проекта (по возможности).
|
|
||||||
|
|
||||||
Баги и проблемы отправляйте через `Issues` в соответствующем репозитории.
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
# DCR (Dexoron Cargo Realization)
|
|
||||||
|
|
||||||
DCR — это утилита для управления проектами на C/C++ в стиле Cargo.
|
|
||||||
|
|
||||||
Текущая реализация написана на Rust.
|
|
||||||
|
|
||||||
## Зачем DCR
|
|
||||||
- Единая структура проекта без ручной настройки
|
|
||||||
- Простые команды для типовых задач
|
|
||||||
- Прозрачная компиляция и предсказуемые профили сборки
|
|
||||||
|
|
||||||
## Возможности
|
|
||||||
- Создание нового проекта или инициализация текущей директории
|
|
||||||
- Сборка проекта в профилях `debug` и `release`
|
|
||||||
- Запуск собранного бинарника
|
|
||||||
- Очистка результатов сборки
|
|
||||||
- Генерация минимального шаблона C-проекта
|
|
||||||
- Обновление бинарника через `dcr --update` (GitHub Releases, не для pacman-установок)
|
|
||||||
|
|
||||||
## Поддерживаемые платформы
|
|
||||||
- Linux: `x86_64-unknown-linux-gnu`
|
|
||||||
- macOS Intel: `x86_64-apple-darwin`
|
|
||||||
- macOS Apple Silicon: `aarch64-apple-darwin`
|
|
||||||
- Windows: `x86_64-pc-windows-msvc`
|
|
||||||
|
|
||||||
## Установка
|
|
||||||
|
|
||||||
### Пакетный менеджер
|
|
||||||
|
|
||||||
**ArchLinux**
|
|
||||||
```sh
|
|
||||||
yay -S dcr # или paru и остальные менеджеры пакетов AUR
|
|
||||||
```
|
|
||||||
|
|
||||||
### Из исходников
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git clone https://github.com/dexoron/dcr.git
|
|
||||||
cd dcr
|
|
||||||
cargo build --release
|
|
||||||
mkdir -p ~/.local/bin
|
|
||||||
ln -sf "$PWD/target/release/dcr" ~/.local/bin/dcr
|
|
||||||
```
|
|
||||||
|
|
||||||
### Через install.sh (Linux/macOS)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
curl -fsSL https://dcr.dexoron.su/install.sh | bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### Через install.ps1 (Windows)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
irm https://dcr.dexoron.su/install.ps1 | iex
|
|
||||||
```
|
|
||||||
|
|
||||||
Оба скрипта при запуске спрашивают:
|
|
||||||
- скачать готовый бинарник из GitHub Release
|
|
||||||
- или собрать проект из `git`
|
|
||||||
|
|
||||||
Релизные ассеты:
|
|
||||||
- `dcr-x86_64-unknown-linux-gnu`
|
|
||||||
- `dcr-x86_64-apple-darwin`
|
|
||||||
- `dcr-aarch64-apple-darwin`
|
|
||||||
- `dcr-x86_64-pc-windows-msvc.exe`
|
|
||||||
|
|
||||||
## Обновление
|
|
||||||
|
|
||||||
- Если DCR установлен из GitHub Releases, через `install.sh`, `install.ps1` или собран вручную:
|
|
||||||
- используйте `dcr --update`
|
|
||||||
- Если DCR установлен через `pacman/AUR`:
|
|
||||||
- обновляйте через пакетный менеджер: `paru/yay -Syu dcr` или `sudo pacman -Syu dcr`
|
|
||||||
- `dcr --update` определяет пакетную установку и подсказывает обновляться через пакетный менеджер
|
|
||||||
|
|
||||||
## Быстрый старт
|
|
||||||
|
|
||||||
Создать новый проект:
|
|
||||||
`dcr new hello`
|
|
||||||
|
|
||||||
Или инициализировать текущую директорию (директория должна быть пустой):
|
|
||||||
`dcr init`
|
|
||||||
|
|
||||||
Структура проекта:
|
|
||||||
|
|
||||||
```txt
|
|
||||||
hello/
|
|
||||||
- src/
|
|
||||||
- - main.c
|
|
||||||
- dcr.toml
|
|
||||||
```
|
|
||||||
|
|
||||||
Сборка и запуск проекта:
|
|
||||||
`dcr run` или `dcr run --release`
|
|
||||||
|
|
||||||
## Команды
|
|
||||||
|
|
||||||
### `dcr new <name>`
|
|
||||||
Создает проект в текущей директории с указанным именем.
|
|
||||||
|
|
||||||
### `dcr init`
|
|
||||||
Создает проект в текущей директории. Имя проекта будет равно имени директории. Директория должна быть пустой.
|
|
||||||
|
|
||||||
### `dcr build [profile]`
|
|
||||||
Собирает проект. Если профиль не указан, используется `--debug`.
|
|
||||||
|
|
||||||
### `dcr run [profile]`
|
|
||||||
Собирает проект и запускает бинарник. Если профиль не указан, используется `--debug`.
|
|
||||||
|
|
||||||
Запуск вручную:
|
|
||||||
`./target/<profile>/<name>`
|
|
||||||
|
|
||||||
### `dcr clean`
|
|
||||||
Удаляет папку `target` в корне проекта.
|
|
||||||
|
|
||||||
## Профили сборки
|
|
||||||
Поддерживаются два профиля:
|
|
||||||
- `--debug` (по умолчанию) — встроенные флаги для каждого компилятора
|
|
||||||
- `--release` — встроенные флаги для каждого компилятора
|
|
||||||
|
|
||||||
Кастомные флаги можно добавить через `build.cflags` и `build.ldflags` в `dcr.toml`.
|
|
||||||
|
|
||||||
## Конфигурация
|
|
||||||
Основной файл проекта — `dcr.toml`.
|
|
||||||
|
|
||||||
Пример `dcr.toml`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[package]
|
|
||||||
name = "hello"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[build]
|
|
||||||
language = "c"
|
|
||||||
standard = "c11"
|
|
||||||
compiler = "clang"
|
|
||||||
# Опциональные флаги
|
|
||||||
cflags = ["-Wall", "-Wextra"]
|
|
||||||
ldflags = ["-lm"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
```
|
|
||||||
|
|
||||||
Поддерживаются path-зависимости. DCR резолвит их при сборке и создаёт `dcr.lock`.
|
|
||||||
|
|
||||||
## Требования
|
|
||||||
- Rust toolchain (`rustc`, `cargo`) - Для ручной сборки DCR
|
|
||||||
- C-компилятор (`clang`, `gcc` или 'cl'(msvc))
|
|
||||||
|
|
||||||
## Релизы
|
|
||||||
Релизы собираются автоматически через GitHub Actions (`.github/workflows/release.yml`) при пуше тега формата `v*`.
|
|
||||||
|
|
||||||
## Лицензия
|
|
||||||
См. файл `LICENSE`.
|
|
||||||
@@ -30,6 +30,8 @@ pub fn build(args: &[String]) -> i32 {
|
|||||||
let project_compiler = get_config_str(&config, "build.compiler");
|
let project_compiler = get_config_str(&config, "build.compiler");
|
||||||
let build_language = get_config_str(&config, "build.language");
|
let build_language = get_config_str(&config, "build.language");
|
||||||
let build_standard = get_config_str(&config, "build.standard");
|
let build_standard = get_config_str(&config, "build.standard");
|
||||||
|
let build_target = get_config_str(&config, "build.target");
|
||||||
|
let build_kind = get_config_str(&config, "build.kind");
|
||||||
let build_cflags = match get_config_list(&config, "build.cflags") {
|
let build_cflags = match get_config_list(&config, "build.cflags") {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
@@ -52,7 +54,7 @@ pub fn build(args: &[String]) -> i32 {
|
|||||||
colored(&project_compiler, BOLD_GREEN)
|
colored(&project_compiler, BOLD_GREEN)
|
||||||
);
|
);
|
||||||
|
|
||||||
ensure_target_dirs(&items, &active_profile);
|
ensure_target_dirs(&items, &active_profile, normalize_target(&build_target));
|
||||||
|
|
||||||
let project_root = match std::env::current_dir() {
|
let project_root = match std::env::current_dir() {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
@@ -74,6 +76,8 @@ pub fn build(args: &[String]) -> i32 {
|
|||||||
compiler: &project_compiler,
|
compiler: &project_compiler,
|
||||||
language: &build_language,
|
language: &build_language,
|
||||||
standard: &build_standard,
|
standard: &build_standard,
|
||||||
|
target_dir: normalize_target(&build_target),
|
||||||
|
kind: normalize_kind(&build_kind),
|
||||||
include_dirs: &resolved.include_dirs,
|
include_dirs: &resolved.include_dirs,
|
||||||
lib_dirs: &resolved.lib_dirs,
|
lib_dirs: &resolved.lib_dirs,
|
||||||
libs: &resolved.libs,
|
libs: &resolved.libs,
|
||||||
@@ -138,7 +142,11 @@ fn get_config_list(config: &Config, key: &str) -> Result<Vec<String>, String> {
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_target_dirs(items: &[String], profile: &str) {
|
fn ensure_target_dirs(items: &[String], profile: &str, target_dir: Option<&str>) {
|
||||||
|
if let Some(dir) = target_dir {
|
||||||
|
let _ = fs::create_dir_all(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if !items.contains(&"target".to_string()) {
|
if !items.contains(&"target".to_string()) {
|
||||||
let _ = fs::create_dir("./target");
|
let _ = fs::create_dir("./target");
|
||||||
}
|
}
|
||||||
@@ -162,3 +170,17 @@ fn run_build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
Err(_) => Err("Build failed".to_string()),
|
Err(_) => Err("Build failed".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_target(target: &str) -> Option<&str> {
|
||||||
|
let trimmed = target.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(trimmed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_kind(kind: &str) -> &str {
|
||||||
|
let trimmed = kind.trim();
|
||||||
|
if trimmed.is_empty() { "bin" } else { trimmed }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::cli::build::build;
|
use crate::cli::build::build;
|
||||||
use crate::config::{PROFILE, flags};
|
use crate::config::{PROFILE, flags};
|
||||||
use crate::core::config::Config;
|
use crate::core::config::Config;
|
||||||
|
use crate::core::runner::run_binary;
|
||||||
use crate::utils::fs::check_dir;
|
use crate::utils::fs::check_dir;
|
||||||
use crate::utils::log::{error, warn};
|
use crate::utils::log::{error, warn};
|
||||||
use crate::utils::text::{BOLD_GREEN, colored};
|
use crate::utils::text::{BOLD_GREEN, colored};
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
pub fn run(args: &[String]) -> i32 {
|
pub fn run(args: &[String]) -> i32 {
|
||||||
let mut active_profile = PROFILE.to_string();
|
let mut active_profile = PROFILE.to_string();
|
||||||
@@ -26,6 +26,15 @@ pub fn run(args: &[String]) -> i32 {
|
|||||||
.get("package.name")
|
.get("package.name")
|
||||||
.and_then(|v| v.as_str())
|
.and_then(|v| v.as_str())
|
||||||
.unwrap_or("");
|
.unwrap_or("");
|
||||||
|
let build_kind = config
|
||||||
|
.get("build.kind")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.unwrap_or("");
|
||||||
|
let target_dir = config
|
||||||
|
.get("build.target")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.map(|s| s.trim())
|
||||||
|
.filter(|s| !s.is_empty());
|
||||||
|
|
||||||
if let Some(first_arg) = args.first() {
|
if let Some(first_arg) = args.first() {
|
||||||
if first_arg.starts_with("--") {
|
if first_arg.starts_with("--") {
|
||||||
@@ -42,30 +51,23 @@ pub fn run(args: &[String]) -> i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if build_kind.trim() == "staticlib" {
|
||||||
|
error("Cannot run static library");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
let build_status = build(args);
|
let build_status = build(args);
|
||||||
|
let bin_path = crate::platform::bin_path(&active_profile, project_name, target_dir);
|
||||||
if build_status == 0 {
|
if build_status == 0 {
|
||||||
println!(
|
println!("\n {} {}", colored("Running", BOLD_GREEN), bin_path);
|
||||||
"\n {} target/{active_profile}/{project_name}",
|
|
||||||
colored("Running", BOLD_GREEN)
|
|
||||||
);
|
|
||||||
println!("--------------------------------");
|
println!("--------------------------------");
|
||||||
return Command::new(format!("./target/{active_profile}/{project_name}"))
|
return run_binary(project_name, &active_profile, target_dir);
|
||||||
.status()
|
|
||||||
.map(|status| status.code().unwrap_or(1))
|
|
||||||
.unwrap_or(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if check_dir(Some(&format!("target/{active_profile}")))
|
let fallback_code = run_binary(project_name, &active_profile, target_dir);
|
||||||
.unwrap_or_default()
|
if fallback_code != 1 {
|
||||||
.contains(&active_profile)
|
return fallback_code;
|
||||||
{
|
|
||||||
warn("Launch of the latest release");
|
|
||||||
return Command::new(format!("./target/{active_profile}/{project_name}"))
|
|
||||||
.status()
|
|
||||||
.map(|status| status.code().unwrap_or(1))
|
|
||||||
.unwrap_or(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error("Fix errors in the code to run the project");
|
error("Fix errors in the code to run the project");
|
||||||
0
|
1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::core::builder::BuildContext;
|
use crate::core::builder::BuildContext;
|
||||||
use crate::platform;
|
use crate::platform;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
@@ -11,13 +12,30 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
ctx.compiler
|
ctx.compiler
|
||||||
};
|
};
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mut cmd = Command::new(compiler);
|
|
||||||
let sources = collect_sources(ctx.language)?;
|
let sources = collect_sources(ctx.language)?;
|
||||||
for source in &sources {
|
let obj_dir = Path::new("./target").join(ctx.profile).join("obj");
|
||||||
cmd.arg(source);
|
let objects = build_objects(compiler, &sources, &obj_dir, ctx, "o")?;
|
||||||
|
|
||||||
|
if ctx.kind == "staticlib" {
|
||||||
|
let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir);
|
||||||
|
let mut cmd = Command::new("ar");
|
||||||
|
cmd.arg("rcs").arg(&lib_path);
|
||||||
|
for obj in &objects {
|
||||||
|
cmd.arg(obj);
|
||||||
|
}
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {
|
||||||
|
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||||
|
return Ok(elapsed);
|
||||||
|
}
|
||||||
|
Ok(_) => return Err("Build failed".to_string()),
|
||||||
|
Err(err) => return Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !ctx.standard.is_empty() {
|
|
||||||
cmd.arg(format!("-std={}", ctx.standard));
|
let mut cmd = Command::new(compiler);
|
||||||
|
for obj in &objects {
|
||||||
|
cmd.arg(obj);
|
||||||
}
|
}
|
||||||
for flag in default_flags(ctx.profile) {
|
for flag in default_flags(ctx.profile) {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
@@ -25,9 +43,6 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for flag in ctx.cflags {
|
for flag in ctx.cflags {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
for dir in ctx.include_dirs {
|
|
||||||
cmd.arg(format!("-I{dir}"));
|
|
||||||
}
|
|
||||||
for dir in ctx.lib_dirs {
|
for dir in ctx.lib_dirs {
|
||||||
cmd.arg(format!("-L{dir}"));
|
cmd.arg(format!("-L{dir}"));
|
||||||
}
|
}
|
||||||
@@ -37,8 +52,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for flag in ctx.ldflags {
|
for flag in ctx.ldflags {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
cmd.arg("-o")
|
cmd.arg("-o").arg(platform::bin_path(
|
||||||
.arg(platform::bin_path(ctx.profile, ctx.project_name));
|
ctx.profile,
|
||||||
|
ctx.project_name,
|
||||||
|
ctx.target_dir,
|
||||||
|
));
|
||||||
|
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
Ok(status) if status.success() => {
|
Ok(status) if status.success() => {
|
||||||
@@ -103,3 +121,63 @@ fn default_flags(profile: &str) -> &'static [&'static str] {
|
|||||||
_ => &[],
|
_ => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_objects(
|
||||||
|
compiler: &str,
|
||||||
|
sources: &[String],
|
||||||
|
obj_dir: &Path,
|
||||||
|
ctx: &BuildContext,
|
||||||
|
obj_ext: &str,
|
||||||
|
) -> Result<Vec<String>, String> {
|
||||||
|
let mut objects = Vec::new();
|
||||||
|
for source in sources {
|
||||||
|
let obj_path = object_path(obj_dir, source, obj_ext);
|
||||||
|
if let Some(parent) = Path::new(&obj_path).parent() {
|
||||||
|
fs::create_dir_all(parent).map_err(|err| format!("obj dir error: {err}"))?;
|
||||||
|
}
|
||||||
|
if needs_rebuild(source, &obj_path) {
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
|
cmd.arg("-c").arg(source).arg("-o").arg(&obj_path);
|
||||||
|
if !ctx.standard.is_empty() {
|
||||||
|
cmd.arg(format!("-std={}", ctx.standard));
|
||||||
|
}
|
||||||
|
for flag in default_flags(ctx.profile) {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
for flag in ctx.cflags {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
for dir in ctx.include_dirs {
|
||||||
|
cmd.arg(format!("-I{dir}"));
|
||||||
|
}
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {}
|
||||||
|
Ok(_) => return Err("Build failed".to_string()),
|
||||||
|
Err(err) => return Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objects.push(obj_path);
|
||||||
|
}
|
||||||
|
Ok(objects)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_path(obj_dir: &Path, source: &str, obj_ext: &str) -> String {
|
||||||
|
let src_path = Path::new(source);
|
||||||
|
let rel = src_path
|
||||||
|
.strip_prefix("./src")
|
||||||
|
.or_else(|_| src_path.strip_prefix("src"))
|
||||||
|
.unwrap_or(src_path);
|
||||||
|
let mut out = obj_dir.join(rel);
|
||||||
|
out.set_extension(obj_ext.trim_start_matches('.'));
|
||||||
|
out.to_string_lossy().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs_rebuild(source: &str, object: &str) -> bool {
|
||||||
|
let src_time = fs::metadata(source).and_then(|m| m.modified());
|
||||||
|
let obj_time = fs::metadata(object).and_then(|m| m.modified());
|
||||||
|
match (src_time, obj_time) {
|
||||||
|
(Ok(s), Ok(o)) => s > o,
|
||||||
|
(Ok(_), Err(_)) => true,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::core::builder::BuildContext;
|
use crate::core::builder::BuildContext;
|
||||||
use crate::platform;
|
use crate::platform;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
@@ -11,13 +12,30 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
ctx.compiler
|
ctx.compiler
|
||||||
};
|
};
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mut cmd = Command::new(compiler);
|
|
||||||
let sources = collect_sources(ctx.language)?;
|
let sources = collect_sources(ctx.language)?;
|
||||||
for source in &sources {
|
let obj_dir = Path::new("./target").join(ctx.profile).join("obj");
|
||||||
cmd.arg(source);
|
let objects = build_objects(compiler, &sources, &obj_dir, ctx, "o")?;
|
||||||
|
|
||||||
|
if ctx.kind == "staticlib" {
|
||||||
|
let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir);
|
||||||
|
let mut cmd = Command::new("ar");
|
||||||
|
cmd.arg("rcs").arg(&lib_path);
|
||||||
|
for obj in &objects {
|
||||||
|
cmd.arg(obj);
|
||||||
|
}
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {
|
||||||
|
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||||
|
return Ok(elapsed);
|
||||||
|
}
|
||||||
|
Ok(_) => return Err("Build failed".to_string()),
|
||||||
|
Err(err) => return Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !ctx.standard.is_empty() {
|
|
||||||
cmd.arg(format!("-std={}", ctx.standard));
|
let mut cmd = Command::new(compiler);
|
||||||
|
for obj in &objects {
|
||||||
|
cmd.arg(obj);
|
||||||
}
|
}
|
||||||
for flag in default_flags(ctx.profile) {
|
for flag in default_flags(ctx.profile) {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
@@ -25,9 +43,6 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for flag in ctx.cflags {
|
for flag in ctx.cflags {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
for dir in ctx.include_dirs {
|
|
||||||
cmd.arg(format!("-I{dir}"));
|
|
||||||
}
|
|
||||||
for dir in ctx.lib_dirs {
|
for dir in ctx.lib_dirs {
|
||||||
cmd.arg(format!("-L{dir}"));
|
cmd.arg(format!("-L{dir}"));
|
||||||
}
|
}
|
||||||
@@ -37,8 +52,11 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
for flag in ctx.ldflags {
|
for flag in ctx.ldflags {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
cmd.arg("-o")
|
cmd.arg("-o").arg(platform::bin_path(
|
||||||
.arg(platform::bin_path(ctx.profile, ctx.project_name));
|
ctx.profile,
|
||||||
|
ctx.project_name,
|
||||||
|
ctx.target_dir,
|
||||||
|
));
|
||||||
|
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
Ok(status) if status.success() => {
|
Ok(status) if status.success() => {
|
||||||
@@ -103,3 +121,63 @@ fn default_flags(profile: &str) -> &'static [&'static str] {
|
|||||||
_ => &[],
|
_ => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_objects(
|
||||||
|
compiler: &str,
|
||||||
|
sources: &[String],
|
||||||
|
obj_dir: &Path,
|
||||||
|
ctx: &BuildContext,
|
||||||
|
obj_ext: &str,
|
||||||
|
) -> Result<Vec<String>, String> {
|
||||||
|
let mut objects = Vec::new();
|
||||||
|
for source in sources {
|
||||||
|
let obj_path = object_path(obj_dir, source, obj_ext);
|
||||||
|
if let Some(parent) = Path::new(&obj_path).parent() {
|
||||||
|
fs::create_dir_all(parent).map_err(|err| format!("obj dir error: {err}"))?;
|
||||||
|
}
|
||||||
|
if needs_rebuild(source, &obj_path) {
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
|
cmd.arg("-c").arg(source).arg("-o").arg(&obj_path);
|
||||||
|
if !ctx.standard.is_empty() {
|
||||||
|
cmd.arg(format!("-std={}", ctx.standard));
|
||||||
|
}
|
||||||
|
for flag in default_flags(ctx.profile) {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
for flag in ctx.cflags {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
for dir in ctx.include_dirs {
|
||||||
|
cmd.arg(format!("-I{dir}"));
|
||||||
|
}
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {}
|
||||||
|
Ok(_) => return Err("Build failed".to_string()),
|
||||||
|
Err(err) => return Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objects.push(obj_path);
|
||||||
|
}
|
||||||
|
Ok(objects)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_path(obj_dir: &Path, source: &str, obj_ext: &str) -> String {
|
||||||
|
let src_path = Path::new(source);
|
||||||
|
let rel = src_path
|
||||||
|
.strip_prefix("./src")
|
||||||
|
.or_else(|_| src_path.strip_prefix("src"))
|
||||||
|
.unwrap_or(src_path);
|
||||||
|
let mut out = obj_dir.join(rel);
|
||||||
|
out.set_extension(obj_ext.trim_start_matches('.'));
|
||||||
|
out.to_string_lossy().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs_rebuild(source: &str, object: &str) -> bool {
|
||||||
|
let src_time = fs::metadata(source).and_then(|m| m.modified());
|
||||||
|
let obj_time = fs::metadata(object).and_then(|m| m.modified());
|
||||||
|
match (src_time, obj_time) {
|
||||||
|
(Ok(s), Ok(o)) => s > o,
|
||||||
|
(Ok(_), Err(_)) => true,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ pub struct BuildContext<'a> {
|
|||||||
pub compiler: &'a str,
|
pub compiler: &'a str,
|
||||||
pub language: &'a str,
|
pub language: &'a str,
|
||||||
pub standard: &'a str,
|
pub standard: &'a str,
|
||||||
|
pub target_dir: Option<&'a str>,
|
||||||
|
pub kind: &'a str,
|
||||||
pub include_dirs: &'a [String],
|
pub include_dirs: &'a [String],
|
||||||
pub lib_dirs: &'a [String],
|
pub lib_dirs: &'a [String],
|
||||||
pub libs: &'a [String],
|
pub libs: &'a [String],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::core::builder::BuildContext;
|
use crate::core::builder::BuildContext;
|
||||||
use crate::platform;
|
use crate::platform;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
@@ -11,9 +12,28 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
ctx.compiler
|
ctx.compiler
|
||||||
};
|
};
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mut cmd = Command::new(compiler);
|
|
||||||
let sources = collect_sources(ctx.language)?;
|
let sources = collect_sources(ctx.language)?;
|
||||||
|
let obj_dir = Path::new("./target").join(ctx.profile).join("obj");
|
||||||
|
let objects = build_objects(compiler, &sources, &obj_dir, ctx, "obj")?;
|
||||||
|
|
||||||
|
if ctx.kind == "staticlib" {
|
||||||
|
let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir);
|
||||||
|
let mut cmd = Command::new("lib");
|
||||||
|
cmd.arg("/nologo").arg(format!("/OUT:{lib_path}"));
|
||||||
|
for obj in &objects {
|
||||||
|
cmd.arg(obj);
|
||||||
|
}
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {
|
||||||
|
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||||
|
return Ok(elapsed);
|
||||||
|
}
|
||||||
|
Ok(_) => return Err("Build failed".to_string()),
|
||||||
|
Err(err) => return Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
cmd.arg("/nologo");
|
cmd.arg("/nologo");
|
||||||
match ctx.language.to_lowercase().as_str() {
|
match ctx.language.to_lowercase().as_str() {
|
||||||
"c" => {
|
"c" => {
|
||||||
@@ -32,15 +52,15 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
cmd.arg(std_flag);
|
cmd.arg(std_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for obj in &objects {
|
||||||
|
cmd.arg(obj);
|
||||||
|
}
|
||||||
for flag in default_flags(ctx.profile) {
|
for flag in default_flags(ctx.profile) {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
for flag in ctx.cflags {
|
for flag in ctx.cflags {
|
||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
for dir in ctx.include_dirs {
|
|
||||||
cmd.arg(format!("/I{dir}"));
|
|
||||||
}
|
|
||||||
for dir in ctx.lib_dirs {
|
for dir in ctx.lib_dirs {
|
||||||
cmd.arg(format!("/LIBPATH:{dir}"));
|
cmd.arg(format!("/LIBPATH:{dir}"));
|
||||||
}
|
}
|
||||||
@@ -57,13 +77,9 @@ pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
|||||||
cmd.arg(flag);
|
cmd.arg(flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for source in &sources {
|
|
||||||
cmd.arg(source);
|
|
||||||
}
|
|
||||||
cmd.arg(format!(
|
cmd.arg(format!(
|
||||||
"/Fe:{}",
|
"/Fe:{}",
|
||||||
platform::bin_path(ctx.profile, ctx.project_name)
|
platform::bin_path(ctx.profile, ctx.project_name, ctx.target_dir)
|
||||||
));
|
));
|
||||||
|
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
@@ -145,3 +161,76 @@ fn default_flags(profile: &str) -> &'static [&'static str] {
|
|||||||
_ => &[],
|
_ => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_objects(
|
||||||
|
compiler: &str,
|
||||||
|
sources: &[String],
|
||||||
|
obj_dir: &Path,
|
||||||
|
ctx: &BuildContext,
|
||||||
|
obj_ext: &str,
|
||||||
|
) -> Result<Vec<String>, String> {
|
||||||
|
let mut objects = Vec::new();
|
||||||
|
for source in sources {
|
||||||
|
let obj_path = object_path(obj_dir, source, obj_ext);
|
||||||
|
if let Some(parent) = Path::new(&obj_path).parent() {
|
||||||
|
fs::create_dir_all(parent).map_err(|err| format!("obj dir error: {err}"))?;
|
||||||
|
}
|
||||||
|
if needs_rebuild(source, &obj_path) {
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
|
cmd.arg("/nologo");
|
||||||
|
match ctx.language.to_lowercase().as_str() {
|
||||||
|
"c" => {
|
||||||
|
cmd.arg("/TC");
|
||||||
|
}
|
||||||
|
"c++" | "cpp" | "cxx" => {
|
||||||
|
cmd.arg("/TP");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err("Unsupported language".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ctx.standard.is_empty() {
|
||||||
|
let std_flag = msvc_standard_flag(ctx.language, ctx.standard)?;
|
||||||
|
cmd.arg(std_flag);
|
||||||
|
}
|
||||||
|
for flag in default_flags(ctx.profile) {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
for flag in ctx.cflags {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
for dir in ctx.include_dirs {
|
||||||
|
cmd.arg(format!("/I{dir}"));
|
||||||
|
}
|
||||||
|
cmd.arg("/c").arg(source).arg(format!("/Fo:{}", obj_path));
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {}
|
||||||
|
Ok(_) => return Err("Build failed".to_string()),
|
||||||
|
Err(err) => return Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
objects.push(obj_path);
|
||||||
|
}
|
||||||
|
Ok(objects)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object_path(obj_dir: &Path, source: &str, obj_ext: &str) -> String {
|
||||||
|
let src_path = Path::new(source);
|
||||||
|
let rel = src_path
|
||||||
|
.strip_prefix("./src")
|
||||||
|
.or_else(|_| src_path.strip_prefix("src"))
|
||||||
|
.unwrap_or(src_path);
|
||||||
|
let mut out = obj_dir.join(rel);
|
||||||
|
out.set_extension(obj_ext.trim_start_matches('.'));
|
||||||
|
out.to_string_lossy().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs_rebuild(source: &str, object: &str) -> bool {
|
||||||
|
let src_time = fs::metadata(source).and_then(|m| m.modified());
|
||||||
|
let obj_time = fs::metadata(object).and_then(|m| m.modified());
|
||||||
|
match (src_time, obj_time) {
|
||||||
|
(Ok(s), Ok(o)) => s > o,
|
||||||
|
(Ok(_), Err(_)) => true,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const DEFAULT_VERSION: &str = "0.1.0";
|
|||||||
const DEFAULT_LANGUAGE: &str = "c";
|
const DEFAULT_LANGUAGE: &str = "c";
|
||||||
const DEFAULT_STANDARD: &str = "c11";
|
const DEFAULT_STANDARD: &str = "c11";
|
||||||
const DEFAULT_COMPILER: &str = "clang";
|
const DEFAULT_COMPILER: &str = "clang";
|
||||||
|
const DEFAULT_KIND: &str = "bin";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ConfigError {
|
pub enum ConfigError {
|
||||||
@@ -114,12 +115,18 @@ impl Config {
|
|||||||
.and_then(|v| v.as_table())
|
.and_then(|v| v.as_table())
|
||||||
.ok_or_else(|| ConfigError::Invalid("missing [build]".into()))?;
|
.ok_or_else(|| ConfigError::Invalid("missing [build]".into()))?;
|
||||||
|
|
||||||
for key in ["language", "standard", "compiler"] {
|
for key in ["language", "standard", "compiler", "kind"] {
|
||||||
let value = build.get(key).and_then(|v| v.as_str()).unwrap_or("");
|
let value = build.get(key).and_then(|v| v.as_str()).unwrap_or("");
|
||||||
if value.trim().is_empty() {
|
if value.trim().is_empty() {
|
||||||
return Err(ConfigError::Invalid(format!("build.{key} is empty")));
|
return Err(ConfigError::Invalid(format!("build.{key} is empty")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(kind) = build.get("kind").and_then(|v| v.as_str()) {
|
||||||
|
let kind = kind.trim();
|
||||||
|
if kind != "bin" && kind != "staticlib" {
|
||||||
|
return Err(ConfigError::Invalid("build.kind is invalid".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +178,7 @@ fn default_toml() -> Result<Value, ConfigError> {
|
|||||||
"compiler".to_string(),
|
"compiler".to_string(),
|
||||||
Value::String(DEFAULT_COMPILER.to_string()),
|
Value::String(DEFAULT_COMPILER.to_string()),
|
||||||
);
|
);
|
||||||
|
build.insert("kind".to_string(), Value::String(DEFAULT_KIND.to_string()));
|
||||||
|
|
||||||
let mut root = Map::new();
|
let mut root = Map::new();
|
||||||
root.insert("package".to_string(), Value::Table(package));
|
root.insert("package".to_string(), Value::Table(package));
|
||||||
@@ -216,16 +224,24 @@ fn format_toml(value: &Value) -> Result<String, ConfigError> {
|
|||||||
out.push_str("[build]\n");
|
out.push_str("[build]\n");
|
||||||
out.push_str(&format!("language = \"{language}\"\n"));
|
out.push_str(&format!("language = \"{language}\"\n"));
|
||||||
out.push_str(&format!("standard = \"{standard}\"\n"));
|
out.push_str(&format!("standard = \"{standard}\"\n"));
|
||||||
out.push_str(&format!("compiler = \"{compiler}\"\n\n"));
|
out.push_str(&format!("compiler = \"{compiler}\"\n"));
|
||||||
|
let kind = build
|
||||||
|
.get("kind")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.unwrap_or(DEFAULT_KIND);
|
||||||
|
out.push_str(&format!("kind = \"{kind}\"\n"));
|
||||||
|
if let Some(target) = build.get("target").and_then(|v| v.as_str())
|
||||||
|
&& !target.trim().is_empty()
|
||||||
|
{
|
||||||
|
out.push_str(&format!("target = \"{target}\"\n"));
|
||||||
|
}
|
||||||
if let Some(cflags) = build.get("cflags") {
|
if let Some(cflags) = build.get("cflags") {
|
||||||
out.push_str(&format!("cflags = {}\n", format_string_array(cflags)));
|
out.push_str(&format!("cflags = {}\n", format_string_array(cflags)));
|
||||||
}
|
}
|
||||||
if let Some(ldflags) = build.get("ldflags") {
|
if let Some(ldflags) = build.get("ldflags") {
|
||||||
out.push_str(&format!("ldflags = {}\n", format_string_array(ldflags)));
|
out.push_str(&format!("ldflags = {}\n", format_string_array(ldflags)));
|
||||||
}
|
}
|
||||||
if build.contains_key("cflags") || build.contains_key("ldflags") {
|
out.push('\n');
|
||||||
out.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
out.push_str("[dependencies]\n");
|
out.push_str("[dependencies]\n");
|
||||||
if !deps.is_empty() {
|
if !deps.is_empty() {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod builder;
|
pub mod builder;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod deps;
|
pub mod deps;
|
||||||
|
pub mod runner;
|
||||||
|
|||||||
37
src/core/runner.rs
Normal file
37
src/core/runner.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
use crate::platform;
|
||||||
|
use crate::utils::fs::check_dir;
|
||||||
|
use crate::utils::log::warn;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
pub fn run_binary(project_name: &str, profile: &str, target_dir: Option<&str>) -> i32 {
|
||||||
|
let bin_path = platform::bin_path(profile, project_name, target_dir);
|
||||||
|
if Path::new(&bin_path).exists() {
|
||||||
|
return Command::new(bin_path)
|
||||||
|
.status()
|
||||||
|
.map(|status| status.code().unwrap_or(1))
|
||||||
|
.unwrap_or(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_dir.is_none()
|
||||||
|
&& check_dir(Some(&format!("target/{profile}")))
|
||||||
|
.unwrap_or_default()
|
||||||
|
.contains(&profile.to_string())
|
||||||
|
{
|
||||||
|
warn("Launch of the latest release");
|
||||||
|
return Command::new(platform::bin_path(profile, project_name, target_dir))
|
||||||
|
.status()
|
||||||
|
.map(|status| status.code().unwrap_or(1))
|
||||||
|
.unwrap_or(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_dir.is_some() && Path::new(&bin_path).exists() {
|
||||||
|
warn("Launch of the latest release");
|
||||||
|
return Command::new(bin_path)
|
||||||
|
.status()
|
||||||
|
.map(|status| status.code().unwrap_or(1))
|
||||||
|
.unwrap_or(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
1
|
||||||
|
}
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
pub fn bin_path(profile: &str, name: &str) -> String {
|
pub fn bin_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
format!("./target/{profile}/{name}")
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/{}", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/{name}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lib_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/lib{}.a", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/lib{name}.a"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
pub fn bin_path(profile: &str, name: &str) -> String {
|
pub fn bin_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
format!("./target/{profile}/{name}")
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/{}", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/{name}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lib_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/lib{}.a", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/lib{name}.a"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,21 +5,46 @@ pub mod macos;
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
|
||||||
pub fn bin_path(profile: &str, name: &str) -> String {
|
pub fn bin_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
linux::bin_path(profile, name)
|
linux::bin_path(profile, name, target_dir)
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
{
|
{
|
||||||
return macos::bin_path(profile, name);
|
return macos::bin_path(profile, name, target_dir);
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
return windows::bin_path(profile, name);
|
return windows::bin_path(profile, name, target_dir);
|
||||||
}
|
}
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
|
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
|
||||||
{
|
{
|
||||||
format!("./target/{profile}/{name}")
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/{}", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/{name}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lib_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
linux::lib_path(profile, name, target_dir)
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
return macos::lib_path(profile, name, target_dir);
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
return windows::lib_path(profile, name, target_dir);
|
||||||
|
}
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
|
||||||
|
{
|
||||||
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/lib{}.a", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/lib{name}.a"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
pub fn bin_path(profile: &str, name: &str) -> String {
|
pub fn bin_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
format!("./target/{profile}/{name}.exe")
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/{}.exe", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/{name}.exe"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lib_path(profile: &str, name: &str, target_dir: Option<&str>) -> String {
|
||||||
|
match target_dir {
|
||||||
|
Some(dir) => format!("{}/{}.lib", dir.trim_end_matches('/'), name),
|
||||||
|
None => format!("./target/{profile}/{name}.lib"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user