mirror of
https://github.com/dexoron/dcr.git
synced 2026-10-21 16:19:37 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff12ca2758 | |||
| 468491b5b1 | |||
| 0f48151b68 | |||
| e87e0cbc47 | |||
| fff8baa3c9 | |||
| ad0d4cdcb7 | |||
| 45806f193e |
15
.github/workflows/aur.yml
vendored
15
.github/workflows/aur.yml
vendored
@@ -1,6 +1,11 @@
|
|||||||
name: AUR Publish
|
name: AUR Publish
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: "Tag version without v prefix (e.g. 0.2.2)"
|
||||||
|
required: true
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*"
|
- "v*"
|
||||||
@@ -11,6 +16,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
publish-aur:
|
publish-aur:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
environment: aur
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -20,7 +26,11 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
PKGVER="${GITHUB_REF_NAME#v}"
|
if [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" ]]; then
|
||||||
|
PKGVER="${{ inputs.version }}"
|
||||||
|
else
|
||||||
|
PKGVER="${GITHUB_REF_NAME#v}"
|
||||||
|
fi
|
||||||
SRC_URL="https://github.com/dexoron/dcr/archive/refs/tags/v${PKGVER}.tar.gz"
|
SRC_URL="https://github.com/dexoron/dcr/archive/refs/tags/v${PKGVER}.tar.gz"
|
||||||
SHA256="$(curl -fsSL "$SRC_URL" | sha256sum | awk '{print $1}')"
|
SHA256="$(curl -fsSL "$SRC_URL" | sha256sum | awk '{print $1}')"
|
||||||
|
|
||||||
@@ -57,7 +67,8 @@ jobs:
|
|||||||
build() {
|
build() {
|
||||||
cd "\$srcdir/\$pkgname-\$pkgver"
|
cd "\$srcdir/\$pkgname-\$pkgver"
|
||||||
export CARGO_PROFILE_RELEASE_LTO=false
|
export CARGO_PROFILE_RELEASE_LTO=false
|
||||||
export RUSTFLAGS="${RUSTFLAGS/-C link-arg=-fuse-ld=lld/}"
|
export RUSTFLAGS="\${RUSTFLAGS:-}"
|
||||||
|
export RUSTFLAGS="\${RUSTFLAGS/-C link-arg=-fuse-ld=lld/}"
|
||||||
cargo build --release --locked
|
cargo build --release --locked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
.github/workflows/release.yml
vendored
35
.github/workflows/release.yml
vendored
@@ -9,6 +9,34 @@ permissions:
|
|||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
notes:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Prepare Release Notes
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
tag="${GITHUB_REF_NAME#v}"
|
||||||
|
notes_file=".github/release-notes.md"
|
||||||
|
if grep -q "^## \\[${tag}\\]" CHANGELOG.md; then
|
||||||
|
awk -v ver="$tag" '
|
||||||
|
$0 ~ "^## \\[" ver "\\]" {found=1; next}
|
||||||
|
found && $0 ~ "^## \\[" {exit}
|
||||||
|
found {print}
|
||||||
|
' CHANGELOG.md | sed -e '${/^$/d;}' > "$notes_file"
|
||||||
|
else
|
||||||
|
echo "No CHANGELOG section for $tag." > "$notes_file"
|
||||||
|
git log -1 --pretty=format:"%s%n%n%b" >> "$notes_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload Notes Artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-notes
|
||||||
|
path: .github/release-notes.md
|
||||||
|
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -28,8 +56,14 @@ jobs:
|
|||||||
asset_name: dcr-x86_64-pc-windows-msvc.exe
|
asset_name: dcr-x86_64-pc-windows-msvc.exe
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: notes
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Download Release Notes
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-notes
|
||||||
|
path: .github
|
||||||
|
|
||||||
- name: Setup Rust
|
- name: Setup Rust
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
@@ -55,3 +89,4 @@ jobs:
|
|||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: ${{ matrix.asset_name }}
|
files: ${{ matrix.asset_name }}
|
||||||
|
body_path: .github/release-notes.md
|
||||||
|
|||||||
66
CHANGELOG.md
66
CHANGELOG.md
@@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.2.3] - 2026-02-21
|
||||||
|
Added:
|
||||||
|
- Modular builders for `gcc`, `clang`, `msvc`
|
||||||
|
- Platform-specific binary path generation (Linux/macOS/Windows)
|
||||||
|
|
||||||
|
Changed:
|
||||||
|
- Build configuration moved to `[build]` (`language`, `standard`, `compiler`)
|
||||||
|
- `dcr.toml` formatting now includes the `[build]` section
|
||||||
|
- Build uses built-in `debug/release` flags per compiler
|
||||||
|
- Build compiles all `*.c/*.cpp` files in `src/` into a single binary (no incremental build)
|
||||||
|
- Updated `dcr.toml` examples in documentation
|
||||||
|
|
||||||
## [0.2.2] - 2026-02-20
|
## [0.2.2] - 2026-02-20
|
||||||
Changed:
|
Changed:
|
||||||
- Reworked `dcr.toml` handling: added read, validation, and edit through `core::config`
|
- Reworked `dcr.toml` handling: added read, validation, and edit through `core::config`
|
||||||
@@ -14,40 +26,40 @@ Changed:
|
|||||||
- Translated installer script messages in `install.sh` and `install.ps1` to English
|
- Translated installer script messages in `install.sh` and `install.ps1` to English
|
||||||
|
|
||||||
## [0.2.0] - 2026-02-17
|
## [0.2.0] - 2026-02-17
|
||||||
Изменено:
|
Changed:
|
||||||
- Проект переведен с Python на Rust
|
- Project migrated from Python to Rust
|
||||||
- CLI и команды (`new`, `init`, `build`, `run`, `clean`, `--help`, `--version`, `--update`) перенесены на Rust
|
- CLI and commands (`new`, `init`, `build`, `run`, `clean`, `--help`, `--version`, `--update`) ported to Rust
|
||||||
- Обновлен флаг `--update` - добавлена поддержка GNU\Linux, Windows, MacOS
|
- Updated `--update` flag: added support for GNU/Linux, Windows, macOS
|
||||||
- Обновлены `README.md`, `CONTRIBUTING.md`, `install.sh` под Rust-реализацию
|
- Updated `README.md`, `CONTRIBUTING.md`, and `install.sh` for the Rust implementation
|
||||||
- Добавлен `install.ps1` для Windows
|
- Added `install.ps1` for Windows
|
||||||
- Обновлен `install.sh` для GNU/Linux и MacOS
|
- Updated `install.sh` for GNU/Linux and macOS
|
||||||
|
|
||||||
Добавлено:
|
Added:
|
||||||
- Добавлен `install.ps1` для Windows
|
- Added `install.ps1` for Windows
|
||||||
- Поддержка GNU\Linux, Windows, MacOS(x86_64/arm)
|
- Support for GNU/Linux, Windows, macOS (x86_64/arm)
|
||||||
|
|
||||||
ВАЖНО:
|
Important:
|
||||||
- Код перенесен с помощью нейронных сетей, в будущих версиях будет баг-фикс и изменение логики
|
- Code was ported with neural networks; future versions will include bug fixes and logic changes
|
||||||
|
|
||||||
## [0.1.2] - 2026-02-12
|
## [0.1.2] - 2026-02-12
|
||||||
Добавлено:
|
Added:
|
||||||
- Команда обновления
|
- Update command
|
||||||
- Скрипт установки `install.sh` и инструкции по установке в README
|
- `install.sh` install script and README instructions
|
||||||
- Флаг `--version` для вывода версии
|
- `--version` flag
|
||||||
|
|
||||||
Изменено:
|
Changed:
|
||||||
- Улучшен консольный вывод команд, добавлены цвета и обновлена справка `--help`
|
- Improved CLI output, added colors, and updated `--help`
|
||||||
- Обновлен запуск проекта и обработка сборки в `run.py`/`build.py`
|
- Updated project run/build handling in `run.py`/`build.py`
|
||||||
|
|
||||||
## [0.1.1] - 2026-02-11
|
## [0.1.1] - 2026-02-11
|
||||||
Изменено:
|
Changed:
|
||||||
- Обновлена справка `--help`
|
- Updated `--help`
|
||||||
- `main.py` теперь корректно запускается при прямом выполнении
|
- `main.py` now runs correctly when executed directly
|
||||||
|
|
||||||
## [0.1.0] - 2026-02-11
|
## [0.1.0] - 2026-02-11
|
||||||
Первый публичный релиз.
|
First public release.
|
||||||
|
|
||||||
Добавлено:
|
Added:
|
||||||
- Базовые команды `new`, `init`, `build`, `run`, `clean`
|
- Base commands `new`, `init`, `build`, `run`, `clean`
|
||||||
- Профили сборки `debug` и `release`
|
- Build profiles `debug` and `release`
|
||||||
- Шаблоны `dcr.toml` и `src/main.c`
|
- `dcr.toml` and `src/main.c` templates
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -62,7 +62,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dcr"
|
name = "dcr"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"self-replace",
|
"self-replace",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "dcr"
|
name = "dcr"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -107,15 +107,15 @@ Builds the project. If no profile is specified, `--debug` is used.
|
|||||||
Builds the project and runs the binary. If no profile is specified, `--debug` is used.
|
Builds the project and runs the binary. If no profile is specified, `--debug` is used.
|
||||||
|
|
||||||
Run manually:
|
Run manually:
|
||||||
`./target/<profile>/main`
|
`./target/<profile>/<name>`
|
||||||
|
|
||||||
### `dcr clean`
|
### `dcr clean`
|
||||||
Removes the `target` directory in the project root.
|
Removes the `target` directory in the project root.
|
||||||
|
|
||||||
## Build Profiles
|
## Build Profiles
|
||||||
Two profiles are supported:
|
Two profiles are supported:
|
||||||
- `--debug` (default) - flags: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG`
|
- `--debug` (default) - flags: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG`(Clang)
|
||||||
- `--release` - flags: `-O3 -DNDEBUG -march=native`
|
- `--release` - flags: `-O3 -DNDEBUG -march=native`(Clang)
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
The main project file is `dcr.toml`.
|
The main project file is `dcr.toml`.
|
||||||
@@ -126,7 +126,10 @@ Example `dcr.toml`:
|
|||||||
[package]
|
[package]
|
||||||
name = "hello"
|
name = "hello"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[build]
|
||||||
language = "c"
|
language = "c"
|
||||||
|
standard = "c11"
|
||||||
compiler = "clang"
|
compiler = "clang"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -134,7 +137,7 @@ compiler = "clang"
|
|||||||
|
|
||||||
## 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 others)
|
- C compiler (`clang`, `gcc`, or 'cl'(msvc))
|
||||||
|
|
||||||
## Releases
|
## Releases
|
||||||
Releases are built automatically via GitHub Actions (`.github/workflows/release.yml`) when a tag matching `v*` is pushed.
|
Releases are built automatically via GitHub Actions (`.github/workflows/release.yml`) when a tag matching `v*` is pushed.
|
||||||
|
|||||||
@@ -107,15 +107,15 @@ hello/
|
|||||||
Собирает проект и запускает бинарник. Если профиль не указан, используется `--debug`.
|
Собирает проект и запускает бинарник. Если профиль не указан, используется `--debug`.
|
||||||
|
|
||||||
Запуск вручную:
|
Запуск вручную:
|
||||||
`./target/<profile>/main`
|
`./target/<profile>/<name>`
|
||||||
|
|
||||||
### `dcr clean`
|
### `dcr clean`
|
||||||
Удаляет папку `target` в корне проекта.
|
Удаляет папку `target` в корне проекта.
|
||||||
|
|
||||||
## Профили сборки
|
## Профили сборки
|
||||||
Поддерживаются два профиля:
|
Поддерживаются два профиля:
|
||||||
- `--debug` (по умолчанию) — флаги: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG`
|
- `--debug` (по умолчанию) — флаги: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDEBUG`(Clang)
|
||||||
- `--release` — флаги: `-O3 -DNDEBUG -march=native`
|
- `--release` — флаги: `-O3 -DNDEBUG -march=native`(Clang)
|
||||||
|
|
||||||
## Конфигурация
|
## Конфигурация
|
||||||
Основной файл проекта — `dcr.toml`.
|
Основной файл проекта — `dcr.toml`.
|
||||||
@@ -126,7 +126,10 @@ hello/
|
|||||||
[package]
|
[package]
|
||||||
name = "hello"
|
name = "hello"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[build]
|
||||||
language = "c"
|
language = "c"
|
||||||
|
standard = "c11"
|
||||||
compiler = "clang"
|
compiler = "clang"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -134,7 +137,7 @@ compiler = "clang"
|
|||||||
|
|
||||||
## Требования
|
## Требования
|
||||||
- Rust toolchain (`rustc`, `cargo`) - Для ручной сборки DCR
|
- Rust toolchain (`rustc`, `cargo`) - Для ручной сборки DCR
|
||||||
- C-компилятор (`clang`, `gcc` или другие)
|
- C-компилятор (`clang`, `gcc` или 'cl'(msvc))
|
||||||
|
|
||||||
## Релизы
|
## Релизы
|
||||||
Релизы собираются автоматически через GitHub Actions (`.github/workflows/release.yml`) при пуше тега формата `v*`.
|
Релизы собираются автоматически через GitHub Actions (`.github/workflows/release.yml`) при пуше тега формата `v*`.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ sha256sums=('30e334fa98cd51073c0fa84c80a982584b00156b57084311ad53419441ce6235')
|
|||||||
build() {
|
build() {
|
||||||
cd "$srcdir/$pkgname-$pkgver"
|
cd "$srcdir/$pkgname-$pkgver"
|
||||||
export CARGO_PROFILE_RELEASE_LTO=false
|
export CARGO_PROFILE_RELEASE_LTO=false
|
||||||
|
export RUSTFLAGS="${RUSTFLAGS:-}"
|
||||||
export RUSTFLAGS="${RUSTFLAGS/-C link-arg=-fuse-ld=lld/}"
|
export RUSTFLAGS="${RUSTFLAGS/-C link-arg=-fuse-ld=lld/}"
|
||||||
cargo build --release --locked
|
cargo build --release --locked
|
||||||
}
|
}
|
||||||
|
|||||||
131
src/cli/build.rs
131
src/cli/build.rs
@@ -1,15 +1,13 @@
|
|||||||
use crate::config::{PROFILE, flags};
|
use crate::config::{PROFILE, flags};
|
||||||
|
use crate::core::builder::{BuildContext, build as build_project};
|
||||||
use crate::core::config::Config;
|
use crate::core::config::Config;
|
||||||
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::fs;
|
use std::fs;
|
||||||
use std::process::Command;
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
pub fn build(args: &[String]) -> i32 {
|
pub fn build(args: &[String]) -> i32 {
|
||||||
let mut active_profile = PROFILE.to_string();
|
|
||||||
|
|
||||||
let items = check_dir(None).unwrap_or_default();
|
let items = check_dir(None).unwrap_or_default();
|
||||||
if !items.contains(&"dcr.toml".to_string()) {
|
if !items.contains(&"dcr.toml".to_string()) {
|
||||||
error("dcr.toml file not found");
|
error("dcr.toml file not found");
|
||||||
@@ -23,73 +21,92 @@ pub fn build(args: &[String]) -> i32 {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let project_compiler: &str = config
|
let active_profile = match parse_profile(args) {
|
||||||
.get("package.compiler")
|
Ok(profile) => profile,
|
||||||
.and_then(|v| v.as_str())
|
Err(code) => return code,
|
||||||
.unwrap_or("");
|
};
|
||||||
let project_name: &str = config
|
let project_name = get_config_str(&config, "package.name");
|
||||||
.get("package.name")
|
let project_compiler = get_config_str(&config, "build.compiler");
|
||||||
.and_then(|v| v.as_str())
|
let build_language = get_config_str(&config, "build.language");
|
||||||
.unwrap_or("");
|
let build_standard = get_config_str(&config, "build.standard");
|
||||||
|
|
||||||
|
println!(
|
||||||
|
" Building project `{}`\n Profile: {}\n Compiler: {}\n",
|
||||||
|
colored(&project_name, BOLD_GREEN),
|
||||||
|
colored(&active_profile, BOLD_GREEN),
|
||||||
|
colored(&project_compiler, BOLD_GREEN)
|
||||||
|
);
|
||||||
|
|
||||||
|
ensure_target_dirs(&items, &active_profile);
|
||||||
|
|
||||||
|
let ctx = BuildContext {
|
||||||
|
profile: &active_profile,
|
||||||
|
project_name: &project_name,
|
||||||
|
compiler: &project_compiler,
|
||||||
|
language: &build_language,
|
||||||
|
standard: &build_standard,
|
||||||
|
};
|
||||||
|
match run_build(&ctx) {
|
||||||
|
Ok(times) => {
|
||||||
|
println!(
|
||||||
|
" {} Build completed successfully in {} seconds",
|
||||||
|
colored("✔", BOLD_GREEN),
|
||||||
|
colored(×.to_string(), BOLD_GREEN)
|
||||||
|
);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
Err(msg) => {
|
||||||
|
error(&msg);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_profile(args: &[String]) -> Result<String, i32> {
|
||||||
if let Some(first_arg) = args.first() {
|
if let Some(first_arg) = args.first() {
|
||||||
if first_arg.starts_with("--") {
|
if first_arg.starts_with("--") {
|
||||||
let candidate = first_arg.trim_start_matches("--");
|
let candidate = first_arg.trim_start_matches("--");
|
||||||
if flags(candidate).is_some() {
|
if flags(candidate).is_some() {
|
||||||
active_profile = candidate.to_string();
|
return Ok(candidate.to_string());
|
||||||
} else {
|
|
||||||
warn("Unknown build flag");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
} else {
|
warn("Unknown build flag");
|
||||||
warn("Unknown argument");
|
return Err(1);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
warn("Unknown argument");
|
||||||
|
return Err(1);
|
||||||
}
|
}
|
||||||
|
Ok(PROFILE.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
fn get_config_str(config: &Config, key: &str) -> String {
|
||||||
" Building project `{}`\n Profile: {}\n Compiler: {}\n",
|
config
|
||||||
colored(project_name, BOLD_GREEN),
|
.get(key)
|
||||||
colored(&active_profile, BOLD_GREEN),
|
.and_then(|v| v.as_str())
|
||||||
colored(project_compiler, BOLD_GREEN)
|
.unwrap_or("")
|
||||||
);
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_target_dirs(items: &[String], profile: &str) {
|
||||||
if !items.contains(&"target".to_string()) {
|
if !items.contains(&"target".to_string()) {
|
||||||
let _ = fs::create_dir("./target");
|
let _ = fs::create_dir("./target");
|
||||||
}
|
}
|
||||||
let target_items = check_dir(Some("target")).unwrap_or_default();
|
let target_items = check_dir(Some("target")).unwrap_or_default();
|
||||||
if !target_items.contains(&active_profile) {
|
if !target_items.contains(&profile.to_string()) {
|
||||||
let _ = fs::create_dir(format!("./target/{active_profile}"));
|
let _ = fs::create_dir(format!("./target/{profile}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_build(ctx: &BuildContext) -> Result<f64, String> {
|
||||||
|
let start_time = Instant::now();
|
||||||
|
match build_project(ctx) {
|
||||||
|
Ok(times) => {
|
||||||
|
let times = if times == 0.0 {
|
||||||
|
((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0
|
||||||
|
} else {
|
||||||
|
times
|
||||||
|
};
|
||||||
|
Ok(times)
|
||||||
|
}
|
||||||
|
Err(_) => Err("Build failed".to_string()),
|
||||||
}
|
}
|
||||||
|
|
||||||
let src_items = check_dir(Some("src")).unwrap_or_default();
|
|
||||||
if src_items.contains(&"main.c".to_string()) {
|
|
||||||
let compile_flags = flags(&active_profile).unwrap_or(&[]);
|
|
||||||
let start_time = Instant::now();
|
|
||||||
let mut cmd = Command::new(project_compiler);
|
|
||||||
cmd.arg("./src/main.c");
|
|
||||||
for flag in compile_flags {
|
|
||||||
cmd.arg(flag);
|
|
||||||
}
|
|
||||||
cmd.arg("-o")
|
|
||||||
.arg(format!("./target/{active_profile}/{project_name}"));
|
|
||||||
|
|
||||||
match cmd.status() {
|
|
||||||
Ok(status) if status.success() => {
|
|
||||||
let times = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
|
||||||
println!(
|
|
||||||
" {} Build completed successfully in {} seconds",
|
|
||||||
colored("✔", BOLD_GREEN),
|
|
||||||
colored(×.to_string(), BOLD_GREEN)
|
|
||||||
);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
error("Build failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
|
|||||||
81
src/core/builder/clang.rs
Normal file
81
src/core/builder/clang.rs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
use crate::core::builder::BuildContext;
|
||||||
|
use crate::platform;
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
||||||
|
let compiler = if ctx.compiler.is_empty() {
|
||||||
|
"cc"
|
||||||
|
} else {
|
||||||
|
ctx.compiler
|
||||||
|
};
|
||||||
|
let start_time = Instant::now();
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
|
let sources = collect_sources(ctx.language)?;
|
||||||
|
for source in &sources {
|
||||||
|
cmd.arg(source);
|
||||||
|
}
|
||||||
|
if !ctx.standard.is_empty() {
|
||||||
|
cmd.arg(format!("-std={}", ctx.standard));
|
||||||
|
}
|
||||||
|
for flag in default_flags(ctx.profile) {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
cmd.arg("-o")
|
||||||
|
.arg(platform::bin_path(ctx.profile, ctx.project_name));
|
||||||
|
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {
|
||||||
|
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||||
|
Ok(elapsed)
|
||||||
|
}
|
||||||
|
Ok(_) => Err("Build failed".to_string()),
|
||||||
|
Err(err) => Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_sources(language: &str) -> Result<Vec<String>, String> {
|
||||||
|
let lang = language.to_lowercase();
|
||||||
|
let mut sources = Vec::new();
|
||||||
|
let entries = fs::read_dir("./src").map_err(|err| format!("src dir error: {err}"))?;
|
||||||
|
for entry in entries {
|
||||||
|
let entry = entry.map_err(|err| format!("src dir error: {err}"))?;
|
||||||
|
let path = entry.path();
|
||||||
|
if !path.is_file() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let ext = path
|
||||||
|
.extension()
|
||||||
|
.and_then(|v| v.to_str())
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_lowercase();
|
||||||
|
let file = path.to_string_lossy().to_string();
|
||||||
|
let allowed = (lang == "c" && ext == "c")
|
||||||
|
|| ((lang == "c++" || lang == "cpp" || lang == "cxx")
|
||||||
|
&& (ext == "cpp" || ext == "cxx" || ext == "cc"));
|
||||||
|
if allowed {
|
||||||
|
sources.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sources.sort();
|
||||||
|
if sources.is_empty() {
|
||||||
|
return Err("No source files found in ./src".to_string());
|
||||||
|
}
|
||||||
|
Ok(sources)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_flags(profile: &str) -> &'static [&'static str] {
|
||||||
|
match profile {
|
||||||
|
"release" => &["-O3", "-DNDEBUG", "-march=native"],
|
||||||
|
"debug" => &[
|
||||||
|
"-O0",
|
||||||
|
"-g",
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
"-DDEBUG",
|
||||||
|
],
|
||||||
|
_ => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
81
src/core/builder/gcc.rs
Normal file
81
src/core/builder/gcc.rs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
use crate::core::builder::BuildContext;
|
||||||
|
use crate::platform;
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
||||||
|
let compiler = if ctx.compiler.is_empty() {
|
||||||
|
"cc"
|
||||||
|
} else {
|
||||||
|
ctx.compiler
|
||||||
|
};
|
||||||
|
let start_time = Instant::now();
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
|
let sources = collect_sources(ctx.language)?;
|
||||||
|
for source in &sources {
|
||||||
|
cmd.arg(source);
|
||||||
|
}
|
||||||
|
if !ctx.standard.is_empty() {
|
||||||
|
cmd.arg(format!("-std={}", ctx.standard));
|
||||||
|
}
|
||||||
|
for flag in default_flags(ctx.profile) {
|
||||||
|
cmd.arg(flag);
|
||||||
|
}
|
||||||
|
cmd.arg("-o")
|
||||||
|
.arg(platform::bin_path(ctx.profile, ctx.project_name));
|
||||||
|
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {
|
||||||
|
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||||
|
Ok(elapsed)
|
||||||
|
}
|
||||||
|
Ok(_) => Err("Build failed".to_string()),
|
||||||
|
Err(err) => Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_sources(language: &str) -> Result<Vec<String>, String> {
|
||||||
|
let lang = language.to_lowercase();
|
||||||
|
let mut sources = Vec::new();
|
||||||
|
let entries = fs::read_dir("./src").map_err(|err| format!("src dir error: {err}"))?;
|
||||||
|
for entry in entries {
|
||||||
|
let entry = entry.map_err(|err| format!("src dir error: {err}"))?;
|
||||||
|
let path = entry.path();
|
||||||
|
if !path.is_file() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let ext = path
|
||||||
|
.extension()
|
||||||
|
.and_then(|v| v.to_str())
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_lowercase();
|
||||||
|
let file = path.to_string_lossy().to_string();
|
||||||
|
let allowed = (lang == "c" && ext == "c")
|
||||||
|
|| ((lang == "c++" || lang == "cpp" || lang == "cxx")
|
||||||
|
&& (ext == "cpp" || ext == "cxx" || ext == "cc"));
|
||||||
|
if allowed {
|
||||||
|
sources.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sources.sort();
|
||||||
|
if sources.is_empty() {
|
||||||
|
return Err("No source files found in ./src".to_string());
|
||||||
|
}
|
||||||
|
Ok(sources)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_flags(profile: &str) -> &'static [&'static str] {
|
||||||
|
match profile {
|
||||||
|
"release" => &["-O3", "-DNDEBUG", "-march=native"],
|
||||||
|
"debug" => &[
|
||||||
|
"-O0",
|
||||||
|
"-g",
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-fno-omit-frame-pointer",
|
||||||
|
"-DDEBUG",
|
||||||
|
],
|
||||||
|
_ => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/core/builder/mod.rs
Normal file
28
src/core/builder/mod.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
pub mod clang;
|
||||||
|
pub mod gcc;
|
||||||
|
pub mod msvc;
|
||||||
|
|
||||||
|
pub struct BuildContext<'a> {
|
||||||
|
pub profile: &'a str,
|
||||||
|
pub project_name: &'a str,
|
||||||
|
pub compiler: &'a str,
|
||||||
|
pub language: &'a str,
|
||||||
|
pub standard: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
||||||
|
let compiler = ctx.compiler.to_lowercase();
|
||||||
|
if compiler.contains("clang-cl") {
|
||||||
|
return msvc::build(ctx);
|
||||||
|
}
|
||||||
|
if compiler.contains("gcc") || compiler.contains("g++") {
|
||||||
|
return gcc::build(ctx);
|
||||||
|
}
|
||||||
|
if compiler.contains("clang") || compiler.contains("clang++") {
|
||||||
|
return clang::build(ctx);
|
||||||
|
}
|
||||||
|
if compiler == "cl" || compiler.contains("msvc") {
|
||||||
|
return msvc::build(ctx);
|
||||||
|
}
|
||||||
|
clang::build(ctx)
|
||||||
|
}
|
||||||
116
src/core/builder/msvc.rs
Normal file
116
src/core/builder/msvc.rs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
use crate::core::builder::BuildContext;
|
||||||
|
use crate::platform;
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
pub fn build(ctx: &BuildContext) -> Result<f64, String> {
|
||||||
|
let compiler = if ctx.compiler.is_empty() {
|
||||||
|
"cl"
|
||||||
|
} else {
|
||||||
|
ctx.compiler
|
||||||
|
};
|
||||||
|
let start_time = Instant::now();
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
|
let sources = collect_sources(ctx.language)?;
|
||||||
|
|
||||||
|
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 source in &sources {
|
||||||
|
cmd.arg(source);
|
||||||
|
}
|
||||||
|
cmd.arg(format!(
|
||||||
|
"/Fe:{}",
|
||||||
|
platform::bin_path(ctx.profile, ctx.project_name)
|
||||||
|
));
|
||||||
|
|
||||||
|
match cmd.status() {
|
||||||
|
Ok(status) if status.success() => {
|
||||||
|
let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0;
|
||||||
|
Ok(elapsed)
|
||||||
|
}
|
||||||
|
Ok(_) => Err("Build failed".to_string()),
|
||||||
|
Err(err) => Err(format!("Build failed: {err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_sources(language: &str) -> Result<Vec<String>, String> {
|
||||||
|
let lang = language.to_lowercase();
|
||||||
|
let mut sources = Vec::new();
|
||||||
|
let entries = fs::read_dir("./src").map_err(|err| format!("src dir error: {err}"))?;
|
||||||
|
for entry in entries {
|
||||||
|
let entry = entry.map_err(|err| format!("src dir error: {err}"))?;
|
||||||
|
let path = entry.path();
|
||||||
|
if !path.is_file() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let ext = path
|
||||||
|
.extension()
|
||||||
|
.and_then(|v| v.to_str())
|
||||||
|
.unwrap_or("")
|
||||||
|
.to_lowercase();
|
||||||
|
let file = path.to_string_lossy().to_string();
|
||||||
|
let allowed = (lang == "c" && ext == "c")
|
||||||
|
|| ((lang == "c++" || lang == "cpp" || lang == "cxx")
|
||||||
|
&& (ext == "cpp" || ext == "cxx" || ext == "cc"));
|
||||||
|
if allowed {
|
||||||
|
sources.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sources.sort();
|
||||||
|
if sources.is_empty() {
|
||||||
|
return Err("No source files found in ./src".to_string());
|
||||||
|
}
|
||||||
|
Ok(sources)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msvc_standard_flag(language: &str, standard: &str) -> Result<String, String> {
|
||||||
|
let lang = language.to_lowercase();
|
||||||
|
let std = standard.to_lowercase();
|
||||||
|
if lang == "c" {
|
||||||
|
return match std.as_str() {
|
||||||
|
"c11" => Ok("/std:c11".to_string()),
|
||||||
|
"c17" => Ok("/std:c17".to_string()),
|
||||||
|
_ => Err("Unsupported C standard for MSVC".to_string()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if lang == "c++" || lang == "cpp" || lang == "cxx" {
|
||||||
|
return match std.as_str() {
|
||||||
|
"c++11" => Ok("/std:c++11".to_string()),
|
||||||
|
"c++14" => Ok("/std:c++14".to_string()),
|
||||||
|
"c++17" => Ok("/std:c++17".to_string()),
|
||||||
|
"c++20" => Ok("/std:c++20".to_string()),
|
||||||
|
"c++23" => Ok("/std:c++latest".to_string()),
|
||||||
|
_ => Err("Unsupported C++ standard for MSVC".to_string()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err("Unsupported language".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_flags(profile: &str) -> &'static [&'static str] {
|
||||||
|
match profile {
|
||||||
|
"release" => &["/O2", "/DNDEBUG"],
|
||||||
|
"debug" => &["/Od", "/Zi", "/W4", "/DDEBUG", "/Oy-"],
|
||||||
|
_ => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ use toml::map::Map;
|
|||||||
|
|
||||||
const DEFAULT_VERSION: &str = "0.1.0";
|
const DEFAULT_VERSION: &str = "0.1.0";
|
||||||
const DEFAULT_LANGUAGE: &str = "c";
|
const DEFAULT_LANGUAGE: &str = "c";
|
||||||
|
const DEFAULT_STANDARD: &str = "c11";
|
||||||
const DEFAULT_COMPILER: &str = "clang";
|
const DEFAULT_COMPILER: &str = "clang";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -101,12 +102,24 @@ impl Config {
|
|||||||
.and_then(|v| v.as_table())
|
.and_then(|v| v.as_table())
|
||||||
.ok_or_else(|| ConfigError::Invalid("missing [package]".into()))?;
|
.ok_or_else(|| ConfigError::Invalid("missing [package]".into()))?;
|
||||||
|
|
||||||
for key in ["name", "version", "language", "compiler"] {
|
for key in ["name", "version"] {
|
||||||
let value = package.get(key).and_then(|v| v.as_str()).unwrap_or("");
|
let value = package.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!("package.{key} is empty")));
|
return Err(ConfigError::Invalid(format!("package.{key} is empty")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let build = self
|
||||||
|
.get("build")
|
||||||
|
.and_then(|v| v.as_table())
|
||||||
|
.ok_or_else(|| ConfigError::Invalid("missing [build]".into()))?;
|
||||||
|
|
||||||
|
for key in ["language", "standard", "compiler"] {
|
||||||
|
let value = build.get(key).and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
if value.trim().is_empty() {
|
||||||
|
return Err(ConfigError::Invalid(format!("build.{key} is empty")));
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +141,7 @@ fn read_toml(path: &Path) -> Result<Value, ConfigError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_toml(path: &Path, value: &Value) -> Result<(), ConfigError> {
|
fn write_toml(path: &Path, value: &Value) -> Result<(), ConfigError> {
|
||||||
let content = toml::to_string(value)?;
|
let content = format_toml(value)?;
|
||||||
fs::write(path, content)?;
|
fs::write(path, content)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -145,22 +158,78 @@ fn default_toml() -> Result<Value, ConfigError> {
|
|||||||
"version".to_string(),
|
"version".to_string(),
|
||||||
Value::String(DEFAULT_VERSION.to_string()),
|
Value::String(DEFAULT_VERSION.to_string()),
|
||||||
);
|
);
|
||||||
package.insert(
|
let mut build = Map::new();
|
||||||
|
build.insert(
|
||||||
"language".to_string(),
|
"language".to_string(),
|
||||||
Value::String(DEFAULT_LANGUAGE.to_string()),
|
Value::String(DEFAULT_LANGUAGE.to_string()),
|
||||||
);
|
);
|
||||||
package.insert(
|
build.insert(
|
||||||
|
"standard".to_string(),
|
||||||
|
Value::String(DEFAULT_STANDARD.to_string()),
|
||||||
|
);
|
||||||
|
build.insert(
|
||||||
"compiler".to_string(),
|
"compiler".to_string(),
|
||||||
Value::String(DEFAULT_COMPILER.to_string()),
|
Value::String(DEFAULT_COMPILER.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));
|
||||||
|
root.insert("build".to_string(), Value::Table(build));
|
||||||
root.insert("dependencies".to_string(), Value::Table(Map::new()));
|
root.insert("dependencies".to_string(), Value::Table(Map::new()));
|
||||||
|
|
||||||
Ok(Value::Table(root))
|
Ok(Value::Table(root))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_toml(value: &Value) -> Result<String, ConfigError> {
|
||||||
|
let root = value
|
||||||
|
.as_table()
|
||||||
|
.ok_or_else(|| ConfigError::Invalid("root is not a table".into()))?;
|
||||||
|
|
||||||
|
let package = root
|
||||||
|
.get("package")
|
||||||
|
.and_then(|v| v.as_table())
|
||||||
|
.ok_or_else(|| ConfigError::Invalid("missing [package]".into()))?;
|
||||||
|
let build = root
|
||||||
|
.get("build")
|
||||||
|
.and_then(|v| v.as_table())
|
||||||
|
.ok_or_else(|| ConfigError::Invalid("missing [build]".into()))?;
|
||||||
|
let deps = root
|
||||||
|
.get("dependencies")
|
||||||
|
.and_then(|v| v.as_table())
|
||||||
|
.ok_or_else(|| ConfigError::Invalid("missing [dependencies]".into()))?;
|
||||||
|
|
||||||
|
let name = package.get("name").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
let version = package
|
||||||
|
.get("version")
|
||||||
|
.and_then(|v| v.as_str())
|
||||||
|
.unwrap_or("");
|
||||||
|
|
||||||
|
let language = build.get("language").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
let standard = build.get("standard").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
let compiler = build.get("compiler").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
|
||||||
|
let mut out = String::new();
|
||||||
|
out.push_str("[package]\n");
|
||||||
|
out.push_str(&format!("name = \"{name}\"\n"));
|
||||||
|
out.push_str(&format!("version = \"{version}\"\n\n"));
|
||||||
|
|
||||||
|
out.push_str("[build]\n");
|
||||||
|
out.push_str(&format!("language = \"{language}\"\n"));
|
||||||
|
out.push_str(&format!("standard = \"{standard}\"\n"));
|
||||||
|
out.push_str(&format!("compiler = \"{compiler}\"\n\n"));
|
||||||
|
|
||||||
|
out.push_str("[dependencies]\n");
|
||||||
|
if !deps.is_empty() {
|
||||||
|
let mut keys: Vec<&String> = deps.keys().collect();
|
||||||
|
keys.sort();
|
||||||
|
for key in keys {
|
||||||
|
let val = deps.get(key).and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
out.push_str(&format!("{key} = \"{val}\"\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_path<'a>(value: &'a Value, path: &[&str]) -> Option<&'a Value> {
|
fn get_path<'a>(value: &'a Value, path: &[&str]) -> Option<&'a Value> {
|
||||||
let mut current = value;
|
let mut current = value;
|
||||||
for key in path {
|
for key in path {
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
pub mod builder;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::utils::log::error;
|
|||||||
mod cli;
|
mod cli;
|
||||||
mod config;
|
mod config;
|
||||||
mod core;
|
mod core;
|
||||||
|
mod platform;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
3
src/platform/linux.rs
Normal file
3
src/platform/linux.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn bin_path(profile: &str, name: &str) -> String {
|
||||||
|
format!("./target/{profile}/{name}")
|
||||||
|
}
|
||||||
3
src/platform/macos.rs
Normal file
3
src/platform/macos.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn bin_path(profile: &str, name: &str) -> String {
|
||||||
|
format!("./target/{profile}/{name}")
|
||||||
|
}
|
||||||
25
src/platform/mod.rs
Normal file
25
src/platform/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub mod linux;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub mod macos;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub mod windows;
|
||||||
|
|
||||||
|
pub fn bin_path(profile: &str, name: &str) -> String {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
linux::bin_path(profile, name)
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
return macos::bin_path(profile, name);
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
return windows::bin_path(profile, name);
|
||||||
|
}
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
|
||||||
|
{
|
||||||
|
format!("./target/{profile}/{name}")
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/platform/windows.rs
Normal file
3
src/platform/windows.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn bin_path(profile: &str, name: &str) -> String {
|
||||||
|
format!("./target/{profile}/{name}.exe")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user