diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5fde99d..62b0e02 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,10 @@ on: description: "Publish to crates.io" type: boolean default: false + run_snap: + description: "Publish to Snap Store (dcrup)" + type: boolean + default: false run_brew: description: "Update Homebrew tap" type: boolean @@ -100,10 +104,28 @@ jobs: name: release-notes path: .github/release-notes.md + # ── Create Release (prevent race conditions) ─────────────────────────────── + create-release: + needs: [setup, notes] + runs-on: ubuntu-latest + steps: + - name: Download Release Notes + uses: actions/download-artifact@v4 + with: + name: release-notes + path: .github + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ needs.setup.outputs.tag }} + body_path: .github/release-notes.md + prerelease: ${{ needs.setup.outputs.prerelease == 'true' }} + # ── Linux Binaries Matrix ────────────────────────────────────────────────── build-linux: if: ${{ github.event_name == 'push' || github.event.inputs.run_linux == 'true' }} - needs: [setup, notes] + needs: [setup, notes, create-release] runs-on: ubuntu-latest strategy: fail-fast: false @@ -129,6 +151,12 @@ jobs: pip install cargo-zigbuild echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Setup Zig + if: matrix.target != 'x86_64-unknown-linux-gnu' + uses: mlugg/setup-zig@v1 + with: + version: 0.13.0 + - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: @@ -222,14 +250,15 @@ jobs: - name: Build Arch Package inside Container if: matrix.package_type == 'arch' run: | - PKGVER='${{ needs.setup.outputs.version }}' + PKGVER_ORIG='${{ needs.setup.outputs.version }}' + PKGVER_CLEAN="${PKGVER_ORIG//-/.}" TAG='${{ needs.setup.outputs.tag }}' SRC_URL="https://github.com/dexoron/dcr/archive/refs/tags/${TAG}.tar.gz" SHA256="$(curl -fsSL "$SRC_URL" | sha256sum | awk '{print $1}')" mkdir -p arch-build cat > arch-build/PKGBUILD <> "$GITHUB_ENV" + + # --- UPLOAD TARGET --- - name: Upload BSD Asset to Release uses: softprops/action-gh-release@v2 @@ -433,7 +464,7 @@ jobs: # ── Windows Matrix ───────────────────────────────────────────────────────── build-windows: if: ${{ github.event_name == 'push' || github.event.inputs.run_windows == 'true' }} - needs: [setup, notes] + needs: [setup, notes, create-release] runs-on: windows-latest strategy: fail-fast: false @@ -500,14 +531,15 @@ jobs: shell: bash run: | set -euo pipefail - PKGVER='${{ needs.setup.outputs.version }}' + PKGVER_ORIG='${{ needs.setup.outputs.version }}' + PKGVER_CLEAN="${PKGVER_ORIG//-/.}" SRC_URL='${{ steps.meta.outputs.source_url }}' SHA256='${{ steps.meta.outputs.sha256 }}' mkdir -p packages/aur/dcr cat > packages/aur/dcr/PKGBUILD < packages/aur/dcr/.SRCINFO < packages/aur/dcr-bin/PKGBUILD < packages/aur/dcr-bin/.SRCINFO </` path for final artifacts. Supported in `build`, `run`, and config validation. +- **`dcr fmt` command** — new CLI command that formats all C/C++ source files (`*.c`, `*.cpp`, `*.h`, `*.hpp`) in `src/` and `tests/` using `clang-format`. +- **Incremental linking** — `needs_link()` function in `common.rs` that checks whether any object file is newer than the linked output, skipping unnecessary re-linking. Implemented for all backends (`unix_cc`, `msvc`, `gas`, `nasm`). +- **`build.kind = "none"` and `"custom"`** — two new project kind types for special build scenarios where no standard artifact is produced. +- **`install_bsd.sh`** — dedicated POSIX-compliant install script for BSD systems (FreeBSD, OpenBSD, NetBSD) with binary download and source build modes. +- **Linux ARM64 support in `install.sh`** — added `Linux:aarch64|Linux:arm64` target triple detection for pre-built binary downloads. +- **BSD OS detection in `install.sh`** — FreeBSD, OpenBSD, NetBSD detection and target triple resolution. +- **`rust-toolchain.toml`** — explicit `stable` channel toolchain pinning. +- **Nix support** — `flake.nix` for Nix package manager. Run via `nix run github:dexoron/dcr` or install with `nix profile install github:dexoron/dcr`. Contributed by community contributor. +- **Snapcraft publish** — `dcrup` published on Snapcraft. Install with `sudo snap install dcrup`. +- **Integration tests** — `build_with_target_config` (verifies `build.target = "linux"`) and `build_with_out_dir` (verifies custom output directory). +- **`get_build_string_with_profile` made `pub`** — so `run.rs` can resolve custom output directory configuration. + +Changed: + +- **`build.target` semantics changed** — now strictly holds the target triple (e.g. `x86_64-unknown-linux-gnu`) or a short name (`linux`, `macos`, `windows`). No longer doubles as a custom output directory — that functionality moved to `build.out_dir`. +- **`build.standard` made optional** — changed from `String` to `Option`. Validation only enforces non-empty for non-ASM languages. Skipped in `dcr.toml` output when empty. +- **`dcr run` with `out_dir`** — now resolves target directory respecting `build.out_dir` when configured, via `get_build_string_with_profile()` from `build.rs`. +- **`collect_sources()` returns empty vec** instead of error when no source files are found, allowing `kind = "none"` or `kind = "custom"` projects to have no source files. +- **CI/CD release workflow refactored** — `git2` made target-specific (no vendored-openssl on Windows), Zig-based cross-compilation for non-x86_64 Linux targets, Arch Linux package version sanitization (dashes → dots), NetBSD `gmake` symlink. +- **README compatibility table** — FreeBSD, OpenBSD, NetBSD build/runtime status upgraded from community/best-effort to officially supported. +- **Documentation rewritten** — available at [dcr.dexoron.su/docs](https://dcr.dexoron.su/docs) or in the `docs/` directory. Installation guides, commands, and reference updated to reflect current CLI and config format. +- **Site rewritten** — `dcr-site` migrated to Docusaurus with internationalization (i18n) support, improved navigation, and updated content across all sections. +- **Dev channel dependency check in `install.sh`** — checks for `python3` or `jq` before attempting dev channel installations. + +Fixed: + +- **`dcr run` stdout/stderr not inherited** — child process output was captured and manually printed, breaking interactive programs. Fixed by switching to `Command::status()`. +- **Release CI race condition** — build matrix jobs could upload assets to a release that did not yet exist. Fixed by adding a dedicated `create-release` job. +- **GHA release — stable toolchain override** — resolved Rust toolchain override issues in CI. +- **Arch Linux package version sanitization** — version strings with dashes (e.g. `0.7.0-dev`) are invalid for Arch Linux `pkgver`. Fixed by replacing dashes with dots. +- **GPG permissions after Docker** — Docker operations changed GPG directory ownership. Fixed by running `chown` after Docker commands. +- **RPM package artifact paths** — RPM artifacts placed under `rpm/x86_64/` instead of `fedora/x86_64/`. Corrected in Dexoron Packages Index workflow. +- **`install.sh` JSON parsing robustness** — added `jq` as primary parser with `python3` fallback for dev channel release lookups. + +Removed: + +- **`format_roots()` helper** — removed from `common.rs`. Was only used by the old error path in `collect_sources()`. +- **Individual per-distro artifact download steps** — three separate `actions/download-artifact` steps replaced with unified `gh release download --clobber`. + ## [0.6.9] - 2026-05-28 Added: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8d1263..44b179a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ DCR supports cross-compilation via `--target ` or short names: - Configure multiple targets in `dcr.toml`: ```toml - [build.targets] + [build] targets = ["linux", "macos"] [build.linux] diff --git a/Cargo.lock b/Cargo.lock index fc4c9b9..92aee21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "anyhow" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "atomic-waker" @@ -22,9 +22,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "block-buffer" @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytes" @@ -58,9 +58,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.56" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", @@ -112,7 +112,7 @@ dependencies = [ [[package]] name = "dcr" -version = "0.6.9" +version = "0.7.0" dependencies = [ "ctrlc", "git2", @@ -150,9 +150,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -177,9 +177,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "find-msvc-tools" @@ -298,20 +298,20 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "wasip2", "wasip3", ] @@ -348,9 +348,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -360,9 +360,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "http" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" dependencies = [ "bytes", "itoa", @@ -399,9 +399,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "1.8.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -412,7 +412,6 @@ dependencies = [ "httparse", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -420,15 +419,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -460,12 +458,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -473,9 +472,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -486,9 +485,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -500,15 +499,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -520,15 +519,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -558,9 +557,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -568,37 +567,27 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" @@ -612,10 +601,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -628,15 +619,15 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.182" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libgit2-sys" -version = "0.18.4+1.9.3" +version = "0.18.5+1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b26f66f35e1871b22efcf7191564123d2a446ca0538cde63c23adfefa9b15b7" +checksum = "005d6ae6eac1912906073e069f7db60b1fa98e052a68227824afe3e3a1c59ca2" dependencies = [ "cc", "libc", @@ -662,9 +653,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.28" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22" +checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9" dependencies = [ "cc", "libc", @@ -674,21 +665,21 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" [[package]] name = "lru-slab" @@ -698,15 +689,15 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "mio" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi", @@ -715,9 +706,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.31.2" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ "bitflags", "cfg-if", @@ -742,15 +733,15 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "openssl" -version = "0.10.79" +version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0b434746ee2832f4f0baf10137e1cabb18cbe6912c69e2e33263c45250f542" +checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ "bitflags", "cfg-if", @@ -788,9 +779,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.115" +version = "0.9.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158fe5b292746440aa6e7a7e690e55aeb72d41505e2804c23c6973ad0e9c9781" +checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" dependencies = [ "cc", "libc", @@ -807,15 +798,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" @@ -825,9 +810,9 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -882,9 +867,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", "getrandom 0.3.4", @@ -917,9 +902,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -931,10 +916,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "rand" -version = "0.9.2" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core", @@ -1015,15 +1006,15 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", @@ -1034,9 +1025,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" dependencies = [ "once_cell", "ring", @@ -1048,9 +1039,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ "web-time", "zeroize", @@ -1058,9 +1049,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "ring", "rustls-pki-types", @@ -1092,9 +1083,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -1128,9 +1119,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -1141,9 +1132,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -1173,9 +1164,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "slab" @@ -1191,12 +1182,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1213,9 +1204,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.116" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1244,12 +1235,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.25.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.1", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -1277,9 +1268,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -1287,9 +1278,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -1302,9 +1293,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -1326,9 +1317,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.0.3+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7614eaf19ad818347db24addfa201729cf2a9b6fdfd9eb0ab870fcacc606c0c" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ "indexmap", "serde_core", @@ -1341,27 +1332,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.0.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tower" @@ -1380,20 +1371,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "bitflags", "bytes", "futures-util", "http", "http-body", - "iri-string", "pin-project-lite", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -1435,9 +1426,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" @@ -1504,11 +1495,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -1517,14 +1508,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -1535,23 +1526,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1559,9 +1546,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -1572,9 +1559,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] @@ -1615,9 +1602,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" dependencies = [ "js-sys", "wasm-bindgen", @@ -1635,9 +1622,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] @@ -1806,9 +1793,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" [[package]] name = "wit-bindgen" @@ -1819,6 +1806,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" @@ -1900,15 +1893,15 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -1917,9 +1910,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -1929,18 +1922,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", @@ -1949,18 +1942,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -1976,9 +1969,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -1987,9 +1980,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -1998,9 +1991,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 451e9d1..347fcdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dcr" -version = "0.6.9" +version = "0.7.0" edition = "2024" build = "build.rs" description = "DCR is a utility for managing C/C++ projects in a Cargo-like style." @@ -42,7 +42,10 @@ sha2 = "0.10" toml = "1.0.3" serde_json = "1" ctrlc = "3" -git2 = { version = "0.20.4", features = ["vendored-libgit2", "vendored-openssl"] } [target.'cfg(not(windows))'.dependencies] -openssl = { version = "0.10", features = ["vendored"] } \ No newline at end of file +git2 = { version = "0.20.4", features = ["vendored-libgit2", "vendored-openssl"] } +openssl = { version = "0.10", features = ["vendored"] } + +[target.'cfg(windows)'.dependencies] +git2 = { version = "0.20.4", features = ["vendored-libgit2"] } \ No newline at end of file diff --git a/README.md b/README.md index 99a3130..d313c82 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,32 @@ + + + + + + + + @@ -71,6 +109,16 @@ cargo install dcr curl -fsSL https://dcr.dexoron.su/install.sh | bash ``` + + + + + @@ -142,15 +190,21 @@ kind = "bin" |---|---| | `dcr new ` | Create a new project | | `dcr init` | Initialize current directory | +| `dcr add ` | Add a dependency | | `dcr build [--release]` | Build the project | | `dcr run [--release]` | Build and run | | `dcr clean` | Remove build artifacts | +| `dcr test` | Run project tests | +| `dcr fmt` | Format C/C++ sources (clang-format) | +| `dcr tree` | View dependency tree | +| `dcr gen ` | Generate IDE integration | +| `dcr setup` | Initialize DCR registry | other in [docs/](docs/) and `dcr --help` --- -## Platforms +## Platforms(pre-build source)
@@ -159,9 +213,9 @@ other in [docs/](docs/) and `dcr --help` | Linux | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | | macOS | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Windows | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | -| FreeBSD | ⚠️ | ⚠️ | ❌ | ❌ | ❌ | ⚠️ | ❌ | ❌ | ❌ | -| OpenBSD | ⚠️ | ⚠️ | ❌ | ❌ | ❌ | ⚠️ | ❌ | ❌ | ❌ | -| NetBSD | ⚠️ | ⚠️ | ❌ | ❌ | ❌ | ⚠️ | ❌ | ❌ | ❌ | +| FreeBSD | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| OpenBSD | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | +| NetBSD | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ officially supported · ⚠️ community / best-effort · ❌ not supported diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index ec944ba..0000000 --- a/docs/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# 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.). -- ASM support via `language = "asm"` (GCC/Clang, NASM, GAS). -- Mixed language builds via `language = ["c", "asm"]` and similar combinations. -- Three build kinds: - - `bin` (default) - - `staticlib` - - `sharedlib` -- Optional custom output directory via `build.target`. -- Optional `build.platform` to pass architecture hints (`-march` / `/arch`). -- Optional `build.exclude`/`build.include` for source/header selection. -- Optional `build.roots`/`build.src_disable` to replace the default `src/` root. -- Optional build steps with `build.steps` and `build.post_steps`. -- Optional `build.pkg_config` integration. -- Optional `build.clean` and `build.expect`. -- Optional `[run].cmd` to override run command. -- Workspace builds via `[workspace]` with per-project `dcr.toml`. -- 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 tracks source file timestamps and header dependencies (rebuilds when either source or included headers change). -- Object files are always created under `target//obj/`. - -## Repository - -- diff --git a/docs/README.mdx b/docs/README.mdx new file mode 100644 index 0000000..cfa6eb6 --- /dev/null +++ b/docs/README.mdx @@ -0,0 +1,60 @@ +--- +sidebar_label: Introduction +--- + +# DCR — C/C++ Build Tool & Package Manager + +
+Quick reference + +```bash +# Installation +curl -fsSL https://dcr.dexoron.su/install.sh | sh + +# Create a project +dcr new my-app +cd my-app + +# Build and run +dcr build +dcr run + +# Run tests +dcr test + +# Add a dependency +dcr add fmt + +# Generate IDE files +dcr gen vscode +``` + +
+ +## Contents + +| Section | Description | +|---------|-------------| +| [Getting Started](/docs/getting-started/installation) | Installation and first steps | +| [Commands](/docs/commands/project-commands) | All CLI commands | +| [Reference](/docs/reference/dcr-toml) | Configuration, build, dependencies, platforms | +| [Testing](/docs/testing/test-framework) | Built-in test framework | +| [Recipes](/docs/recipes/cross-to-windows) | Common scenarios | +| [IDE Integration](/docs/ide-integration) | VS Code, CLion, compile_commands.json | +| [Self Update](/docs/self-update) | Auto-update | +| [FAQ](/docs/faq) | Frequently asked questions | +| [Changelog](/docs/changelog) | Version history | +| [Contributing](/docs/contributing) | DCR development | + +## Features + +- **Incremental builds** — mtime + `.d` headers + SHA256 fingerprint +- **Parallel compilation** — thread::scope, atomic task queue +- **4 backends** — gcc/clang, MSVC/clang-cl, GAS (ARM), NASM (x86) +- **7 project kinds** — bin, staticlib, sharedlib, efi, elf, none, custom +- **Cross-compilation** — short names and full triples +- **Profiles** — debug / release with field overrides +- **Workspaces** — multi-package projects with topological sort +- **Registry + Git + Path** — three dependency mechanisms +- **IDE generation** — VS Code, CLion, compile_commands.json, JSON metadata +- **pkg-config** — automatic system library discovery diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md deleted file mode 100644 index 91abe29..0000000 --- a/docs/SUMMARY.md +++ /dev/null @@ -1,49 +0,0 @@ -# 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 add](commands/dcr-add.md) -* [dcr build](commands/dcr-build.md) -* [dcr run](commands/dcr-run.md) -* [dcr clean](commands/dcr-clean.md) -* [dcr gen](commands/dcr-gen.md) -* [dcr test](commands/dcr-test.md) -* [dcr tree](commands/dcr-tree.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) -* [Cross-compilation and targets](dependencies-and-build/cross-compilation.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) -* [Workspace guide](reference-and-help/workspace-guide.md) -* [Flags & environment](reference-and-help/flags-and-environment.md) -* [Troubleshooting map](reference-and-help/troubleshooting-map.md) -* [FAQ](reference-and-help/faq.md) -* [Contributing & Bug reports](reference-and-help/contributing-and-bug-reports.md) diff --git a/docs/changelog.mdx b/docs/changelog.mdx new file mode 100644 index 0000000..36cc191 --- /dev/null +++ b/docs/changelog.mdx @@ -0,0 +1,47 @@ +--- +sidebar_label: Changelog +--- + +# Changelog + +## 0.7.0 (2026-06-01) + +### Added + +- **OpenBSD and NetBSD target support** — full platform routing with dynamic target triples using `std::env::consts::ARCH` and `std::env::consts::OS`. Affects `build`, `run`, `clean` commands and the platform module. +- **`src/platform/bsd.rs`** — new BSD platform module (shared by FreeBSD, OpenBSD, NetBSD) providing `bin_path`, `lib_path`, `elf_path`, `efi_path`, `shared_lib_path`. +- **`build.out_dir` config option** — custom output directory that overrides the default `target//` path for final artifacts. Supported in `build`, `run`, and config validation. +- **`dcr fmt` command** — new CLI command that formats all C/C++ source files (`*.c`, `*.cpp`, `*.h`, `*.hpp`) in `src/` and `tests/` using `clang-format`. +- **Incremental linking** — `needs_link()` in `common.rs` checks if any object file is newer than the linked output, skipping unnecessary relinking. Implemented for all backends (`unix_cc`, `msvc`, `gas`, `nasm`). +- **`build.kind = "none"` and `"custom"`** — two new project kinds for special build scenarios that don't produce standard artifacts. +- **`install_bsd.sh`** — POSIX-compliant installation script for BSD systems (FreeBSD, OpenBSD, NetBSD) with binary download and source build modes. +- **Linux ARM64 support in `install.sh`** — added `Linux:aarch64|Linux:arm64` target detection for pre-built binary downloads. +- **BSD OS detection in `install.sh`** — detects FreeBSD, OpenBSD, NetBSD and determines target triple. +- **`rust-toolchain.toml`** — explicit toolchain pinning to `stable` channel. +- **Integration tests** — `build_with_target_config` (verifies `build.target = "linux"`) and `build_with_out_dir` (validates custom output directory). +- **`get_build_string_with_profile` made `pub`** — so `run.rs` can determine custom output directory configuration. + +### Changed + +- **`build.target` semantics changed** — now strictly contains a target triple (e.g., `x86_64-unknown-linux-gnu`) or short name (`linux`, `macos`, `windows`). No longer used as custom output directory — this functionality moved to `build.out_dir`. +- **`build.standard` made optional** — changed from `String` to `Option`. Validation only enforces non-empty for non-ASM languages. Skipped in `dcr.toml` output if empty. +- **`dcr run` with `out_dir`** — now determines target directory respecting `build.out_dir` via `get_build_string_with_profile()` from `build.rs`. +- **`collect_sources()` returns empty vector** instead of error when no sources are found, allowing `kind = "none"` or `kind = "custom"` projects with no source files. +- **CI/CD release workflow refactored** — `git2` made target-specific (no vendored-openssl on Windows), Zig-based cross-compilation for non-x86_64 Linux targets, Arch Linux package version cleanup (dashes → dots), `gmake` symlink for NetBSD. +- **README compatibility table** — FreeBSD, OpenBSD, NetBSD build/run status upgraded from "community/best-effort" to "officially supported". +- **Documentation updated** — `build-section.md` describes new `build.target` and `build.out_dir` fields. `target-directory.md` rewritten to clarify the distinction. + +### Fixed + +- **stdout/stderr not inherited in `dcr run`** — child process output was captured and manually printed, breaking interactive programs. Fixed by switching to `Command::status()`. +- **Race condition in release CI** — matrix build jobs could upload assets to a release that didn't exist yet. Fixed by adding a dedicated `create-release` job. +- **Release GHA — stable toolchain override** — fixed Rust toolchain override issues in CI. +- **Arch Linux package version sanitization** — version strings with dashes (e.g., `0.7.0-dev`) are invalid for `pkgver`. Fixed by replacing dashes with dots. +- **GPG permissions after Docker** — Docker operations changed GPG directory ownership. Fixed by running `chown` after Docker commands. +- **RPM artifact paths** — RPM artifacts were placed in `rpm/x86_64/` instead of `fedora/x86_64/`. Fixed in Dexoron Packages Index workflow. +- **JSON parsing reliability in `install.sh`** — added `jq` as primary parser with `python3` fallback for dev channel release lookup. + +### Removed + +- **`format_roots()` helper function** — removed from `common.rs`. Was only used by the old error handling path in `collect_sources()`. +- **Per-distribution artifact download steps** — three separate `actions/download-artifact` steps replaced with unified `gh release download --clobber`. diff --git a/docs/commands/build-commands.mdx b/docs/commands/build-commands.mdx new file mode 100644 index 0000000..5c5e4e4 --- /dev/null +++ b/docs/commands/build-commands.mdx @@ -0,0 +1,42 @@ +--- +sidebar_label: Build commands (build, run, clean) +--- + +# Build Commands + +## `dcr build` + +Builds the project according to `dcr.toml`. + +```bash +dcr build # debug profile +dcr build --release # release build +dcr build --debug # explicit debug +dcr build --target aarch64-unknown-linux-gnu +dcr build --force # full rebuild +dcr build --clean # clean + build +dcr build --verbose # show compilation commands +dcr build --workspace pkg-a # build specific workspace package +``` + +Artifacts: `target///` (Linux with explicit target). + +## `dcr run` + +Builds (if sources are newer than artifacts) and runs the binary. + +```bash +dcr run +dcr run --release +``` + +## `dcr clean` + +Removes `target/` directory (or `target//`). + +```bash +dcr clean +dcr clean --release # target/release/ only +dcr clean --target windows # target/x86_64-pc-windows-msvc/ +dcr clean --all # clean all workspace packages +``` diff --git a/docs/commands/dcr-add.md b/docs/commands/dcr-add.md deleted file mode 100644 index 701184f..0000000 --- a/docs/commands/dcr-add.md +++ /dev/null @@ -1,37 +0,0 @@ -# dcr add - -Add a dependency to `dcr.toml`. - -## Usage - -```bash -dcr add [source] [options] -``` - -If `` is omitted and a registry is configured, DCR will look up the -package by name in the registry and add it as a version dependency. - -## Sources - -- *omitted*: Look up in the configured registry. -- `path:./path/to/lib`: Local directory. -- `github:user/repo`: GitHub repository. -- `gitlab:user/repo`: GitLab repository. -- `git:host.com/user/repo`: Generic Git repository (HTTPS). -- `https://...`: Full Git URL. - -## Options - -- `--branch `: Use a specific branch. -- `--tag `: Use a specific tag. -- `--rev `: Use a specific commit hash. - -## Examples - -```bash -dcr add my_lib path:./libs/my_lib -dcr add cool_lib github:user/cool_lib -dcr add shared_lib gitlab:org/shared --branch develop -dcr add custom_lib git:git.internal.com/r/lib --tag v1.0.0 -dcr add mylib # Looks up in registry -``` diff --git a/docs/commands/dcr-build.md b/docs/commands/dcr-build.md deleted file mode 100644 index d812bd8..0000000 --- a/docs/commands/dcr-build.md +++ /dev/null @@ -1,76 +0,0 @@ -# dcr build - -Builds the project in `debug` or `release` profile. - -## Usage - -```sh -dcr build -dcr build --debug -dcr build --release -dcr build --target linux --release -dcr build --release --force -dcr build --debug --clean -``` - -## 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 library). - -## Config values used - -- `package.name` -- `build.filename` -- `build.extension` -- `build.compiler` -- `build.language` -- `build.standard` -- `build.kind` -- `build.target` -- `build.platform` -- `build.cflags` -- `build.ldflags` -- `build.ldscript` -- `build.debug` / `build.release` -- `build.exclude` -- `build.include` -- `build.pkg_config` -- `build.steps` -- `build.post_steps` -- `build.generated` -- `build.expect` -- `build.clean` - -## Source selection - -- `language = "c"` -> `*.c` -- `language = "c++" | "cpp" | "cxx"` -> `*.cpp`, `*.cxx`, `*.cc` -- `language = "asm"` -> `*.s`, `*.S`, `*.asm` -- Mixed languages are supported with arrays, for example `language = ["c", "asm"]`. -- By default sources are searched in `src/`; use `build.roots` and `build.src_disable` to override. - -## Notes - -- Profile flag (`--debug` / `--release`) can appear in any argument position (duplicates are rejected). -- Unknown profile flags return an error. -- `--target ` builds for specified target (short names: `linux`, `macos`, `windows`). -- `--verbose` prints the compiler/linker command lines to stderr (also works via `DCR_DEBUG` env var). -- If no `--target`, builds for `build.targets` or native. -- Incremental rebuild checks source/object mtime and tracked header dependencies. -- `--force` skips build cache checks and recompiles. -- `--clean` removes `target/` and `build.clean` paths before building. -- `build.filename` + `build.extension` allow full control over the final artifact name (e.g. `KERNEL.BIN` instead of using `package.name`). When `build.kind = "efi"`, the output is a PE32+ executable with `.efi` extension. -- `build.kind = "efi"` links with `-shared -nostdlib -Wl,-dll -Wl,--subsystem,10` for UEFI PE32+ format. Use `build.filename` and `build.extension` for full control over the artifact name. -- `build.kind = "elf"` produces a bare-metal ELF executable. Linking flags are user-controlled via `build.ldflags` (no PIE/CRT defaults are added). -- Default GCC/Clang profile flags: `debug` -> `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDCR_DEBUG`, `release` -> `-O3 -DNDEBUG`. - These defaults are **not applied** for bare-metal targets (e.g. `aarch64-none-elf`, targets containing `none` / `-elf` / `eabi`). -- For `language = "asm"` with `compiler = "as"`/`"gas"`, use `.s` files (no preprocessing). For `.S`, use `gcc` or `clang`. -- In workspace root, `dcr build` builds all members in dependency order. -- `build.exclude` removes paths from source/header collection; `build.include` re-allows matching paths and has priority over `exclude`. -- `build.steps` run before compilation; `build.post_steps` run after linking. -- `build.generated` is cleaned when `build.steps` need to rerun; `build.expect` is verified after post-steps. diff --git a/docs/commands/dcr-clean.md b/docs/commands/dcr-clean.md deleted file mode 100644 index 81e8254..0000000 --- a/docs/commands/dcr-clean.md +++ /dev/null @@ -1,27 +0,0 @@ -# dcr clean - -Removes build artifacts in `target/`. - -## Usage - -```sh -dcr clean -dcr clean --debug -dcr clean --release -dcr clean --all -dcr clean --release --all -``` - -## Behavior - -- Without arguments: removes entire `target/`. -- With profile: removes only the profile-specific directory. Respects `build.target` from config: if `build.target = "aarch64-unknown-linux-gnu"`, cleans `target/aarch64-unknown-linux-gnu//`. -- With `--all`: also cleans all workspace members. -- Additionally removes paths from `build.clean` if configured. -- `build.clean` supports `{profile}` and version placeholders. - -## Validation - -- `dcr.toml` must exist. -- Unknown flags are treated as error. -- If `target` or selected profile directory does not exist, command prints a warning. diff --git a/docs/commands/dcr-gen.md b/docs/commands/dcr-gen.md deleted file mode 100644 index 2215551..0000000 --- a/docs/commands/dcr-gen.md +++ /dev/null @@ -1,170 +0,0 @@ -# dcr gen - -Generates IDE and build tool integration files for C/C++ development environments. - -## Usage - -```sh -dcr gen project-info -dcr gen project-info --release -dcr gen compile-commands -dcr gen compile-commands --debug -dcr gen vscode -dcr gen vscode --release -dcr gen clion -dcr gen clion --debug -``` - -## Subcommands - -### `dcr gen project-info` - -Outputs project metadata as JSON array. - -```sh -dcr gen project-info [--debug | --release] -``` - -Outputs structured information about the project (root project + all workspace members if present): - -```json -[ - { - "name": "my-project", - "version": "1.0.0", - "root": "/path/to/root", - "profile": "debug", - "language": "c++", - "standard": "c++17", - "compiler": "g++", - "kind": "bin", - "sources": ["/path/to/root/src/main.cpp", ...], - "include_dirs": ["/path/to/dep/include", ...], - "lib_dirs": ["/path/to/dep/lib", ...], - "libs": ["somelib", ...], - "cflags": ["-Wall", ...], - "ldflags": ["-lm", ...] - } -] -``` - -This is useful for integrating DCR projects with custom build tools or scripts. - -### `dcr gen compile-commands` - -Generates `compile_commands.json` for use by `clangd`, `clang-tidy`, and other tools. - -```sh -dcr gen compile-commands [--debug | --release] -``` - -Writes `./compile_commands.json` containing compilation database entries for all source files. This file is recognized by: -- LSP servers (`clangd`, `clang-tools-extra`) -- Linters (`clang-tidy`) -- Format tools (`clang-format`) - -The entries include: -- Full compiler command with flags -- Source file path -- Object file output path -- Project root as working directory - -### `dcr gen vscode` - -Generates Visual Studio Code integration files. - -```sh -dcr gen vscode [--debug | --release] -``` - -Creates `.vscode/` directory with: - -- **`launch.json`**: Debug configurations (one per binary target, debug + release variants) -- **`tasks.json`**: Build/run/clean tasks using `dcr` commands -- **`settings.json`**: Clangd configuration pointing to `compile_commands.json` -- **`extensions.json`**: Recommends `clangd`, disables `cpptools` -- **`compile_commands.json`**: Compilation database (same as `dcr gen compile-commands`) - -Usage in VSCode: -- Open the Command Palette (`Ctrl+Shift+P`) and select **"Debug: Start Debugging"** to run debugger -- Press `Ctrl+Shift+B` to run the build task -- Clangd will provide IntelliSense and diagnostics based on `compile_commands.json` -- Generated `launch.json` uses CodeLLDB (`type: "lldb"`), so install `vadimcn.vscode-lldb` - -### `dcr gen clion` - -Generates JetBrains CLion integration files. - -```sh -dcr gen clion [--debug | --release] -``` - -Creates `.idea/` directory with: - -- **`externalTools.xml`**: Registers DCR build/clean/gen commands as external tools -- **`customTargets.xml`**: Defines build targets for debug and release -- **`misc.xml`**: Points CLion to `compile_commands.json` for compilation database -- **`.idea/.gitignore`**: Ignores auto-generated files -- **`runConfigurations/*.xml`**: Debug run configs (one per binary target) -- **`compile_commands.json`**: Compilation database (same as `dcr gen compile-commands`) - -Usage in CLion: -- Build/clean via **Tools → DCR → Build Debug/Release/Clean** -- Run/debug via **Run → Run Configurations** (dropdown) → select generated config -- Code completion and diagnostics come from the compilation database - -## Config values used - -- `package.name` -- `build.compiler` -- `build.language` -- `build.standard` -- `build.kind` -- `build.target` -- `build.platform` -- `build.cflags` -- `build.ldflags` -- `build.debug` / `build.release` -- `build.exclude` -- `build.include` -- `build.pkg_config` -- `build.roots` -- `build.src_disable` -- Workspace members (if `[workspace]` is present) - -## Workspace support - -When running `dcr gen` in a workspace root, all commands process both the root project and all workspace members: - -- `project-info` returns an array with entries for each member + root -- `compile-commands` includes entries from all members -- `vscode` and `clion` generate unified configurations that work across all members - -## Troubleshooting - -### Clangd not picking up includes - -- Ensure `compile_commands.json` exists in the workspace root -- In VSCode settings, verify `clangd.arguments` includes `--compile-commands-dir=` -- Rebuild via `dcr gen compile-commands` if sources or dependencies changed - -### Debug configuration not working - -- Verify binary paths in `launch.json` match actual build output (`target//binary-name`) -- For workspace projects, each member's debug config uses its own `target/` directory -- Ensure GDB/LLDB is installed: `gdb --version` or `lldb --version` -- If VSCode reports unsupported debugger type, install the extension that matches `launch.json` type (`vadimcn.vscode-lldb` for `lldb`) - -### CLion not recognizing includes - -- Regenerate via `dcr gen clion --debug` -- File → Invalidate Caches → Invalidate and Restart -- Verify `.idea/misc.xml` points to correct `compile_commands.json` path - -## Notes - -- Profiles default to `debug` if not specified -- Generation does not require the project to be built first -- Generated files are safe to commit; they are generated from `dcr.toml` and thus repeatable -- IDE configurations may be customized after generation, but changes will be overwritten on next `dcr gen` run -- For multi-binary projects, `vscode` and `clion` generate debug configs for all binaries (both debug + release variants) diff --git a/docs/commands/dcr-init-or-new.md b/docs/commands/dcr-init-or-new.md deleted file mode 100644 index 905ca0d..0000000 --- a/docs/commands/dcr-init-or-new.md +++ /dev/null @@ -1,43 +0,0 @@ -# dcr init/new - -## `dcr new ` - -Creates a new project directory and initializes it. - -```sh -dcr new hello -``` - -Behavior: - -1. Validates arguments (`` is required, only one name is allowed). -2. Creates `/`. -3. Creates `/dcr.toml`. -4. Sets `package.name = ""`. -5. Creates `/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. diff --git a/docs/commands/dcr-run.md b/docs/commands/dcr-run.md deleted file mode 100644 index f5902db..0000000 --- a/docs/commands/dcr-run.md +++ /dev/null @@ -1,40 +0,0 @@ -# dcr run - -Builds the project and runs the resulting binary. - -## Usage - -```sh -dcr run -dcr run --debug -dcr run --release -dcr run --target linux --release -dcr run --release --force -dcr run --debug --clean -``` - -## 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. -5. If `[run].cmd` is set, runs that command instead of the built binary. - -## Restrictions - -- If `build.kind` (or `build.{profile}.kind`) is `"staticlib"` or `"sharedlib"`, `run` exits with error. -- The profile is selected from the first argument. -- `--target ` runs the binary for specified target (short names: `linux`, `macos`, `windows`). -- `--force` skips build cache checks and recompiles. -- `--clean` removes `target/` and `build.clean` paths before building. - -## `run.cmd` variables - -`run.cmd` supports the same variables as build steps: `{profile}`, `{version}`, `{version_major}`, -`{version_minor}`, `{version_patch}`, `{version_suffix}`, `{version_suffix_dash}`. -The command runs via `sh -c` on Unix and `cmd /C` on Windows. - -## 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. diff --git a/docs/commands/dcr-test.md b/docs/commands/dcr-test.md deleted file mode 100644 index 19766c1..0000000 --- a/docs/commands/dcr-test.md +++ /dev/null @@ -1,45 +0,0 @@ -# dcr test - -Runs the project's test suite. - -## Usage - -```sh -dcr test -dcr test --debug -dcr test --release -dcr test --target linux -dcr test --init -``` - -## What `test` does - -1. Builds the project with the specified profile/target. -2. Compiles test files in `tests/` (e.g., `tests/test.c`) into a test binary. -3. Runs the test binary and parses output for PASS/SKIP/FAIL results. -4. Reports summary with colored output. - -## Test Structure - -DCR uses a simple test framework: - -- Header: `tests/dcr_test.h` (generated by `dcr test --init`) -- Test file: `tests/test.c` (template generated by `dcr test --init`) -- Macros: `TEST(name)`, `TEST_CASE(name)`, `EXPECT(condition)`, `SKIP(reason)` -- Output: `[PASS] test_name`, `[FAIL] test_name`, or `[SKIP] test_name` - -## Config values used - -- `package.name` -- `build.compiler`, `build.language`, `build.standard` -- `build.cflags`, `build.ldflags` -- `build.debug` / `build.release` -- `build.targets` (if specified) - -## Notes - -- Test binary is linked with the main project (for lib projects) or standalone. -- `--init` creates `tests/dcr_test.h` and `tests/test.c` if missing. -- Tests run in debug mode by default. Use `--release` for release mode. -- Custom test logic can be added by editing `tests/test.c`. -- Fails if no `tests/test.c` exists (run `dcr test --init` first). \ No newline at end of file diff --git a/docs/commands/dcr-tree.md b/docs/commands/dcr-tree.md deleted file mode 100644 index 066e3b6..0000000 --- a/docs/commands/dcr-tree.md +++ /dev/null @@ -1,22 +0,0 @@ -# dcr tree - -Displays a visual dependency tree for the current project (similar to `cargo tree`). - -## Usage - -```sh -dcr tree -dcr tree --invert -dcr tree -p some-package -``` - -## What it shows - -- All direct and transitive dependencies -- Version of each dependency -- Whether a dependency is a registry, git, or path dependency - -## Notes - -- Useful for debugging dependency issues and understanding the build graph. -- Output format is inspired by `cargo tree`. diff --git a/docs/commands/dependency-commands.mdx b/docs/commands/dependency-commands.mdx new file mode 100644 index 0000000..8e48d9a --- /dev/null +++ b/docs/commands/dependency-commands.mdx @@ -0,0 +1,51 @@ +--- +sidebar_label: Dependency commands (add, tree) +--- + +# Dependency Commands + +## `dcr add [source]` + +Adds a dependency to `dcr.toml`. + +```bash +dcr add fmt # registry lookup +dcr add mylib ../path/to/lib # path as source +dcr add mylib path:./lib # explicit path prefix +dcr add mylib git:https://github.com/user/repo # explicit git prefix +dcr add mylib github:user/repo # GitHub shorthand +dcr add mylib gitlab:user/repo # GitLab shorthand +``` + +Source prefixes: +- `path:` — local path +- `git:` — generic git URL +- `github:` — expands to `https://github.com//` +- `gitlab:` — expands to `https://gitlab.com//` +- `http://` / `https://` / `git@` — full URL + +Flags: +- `--branch ` — git branch +- `--tag ` — git tag +- `--rev ` — git commit + +If source is omitted — DCR searches connected registries. + +## `dcr tree` + +Displays the project dependency tree. + +```bash +dcr tree +``` + +Example output: + +``` +my-app v0.1.0 +├── fmt (registry) +│ └── spdlog (registry) +└── catch2 (registry) +``` + +For path dependencies, recursively shows their own dependencies (from their `dcr.toml`). diff --git a/docs/commands/gen-commands.mdx b/docs/commands/gen-commands.mdx new file mode 100644 index 0000000..da05111 --- /dev/null +++ b/docs/commands/gen-commands.mdx @@ -0,0 +1,71 @@ +--- +sidebar_label: Gen commands (vscode, clion, ...) +--- + +# Gen Commands + +## `dcr gen ` + +Generates IDE integration files. + +### vscode + +```bash +dcr gen vscode +``` + +Creates: +- `.vscode/tasks.json` — `build` task (dcr build) +- `.vscode/launch.json` — debug launch configuration +- `.vscode/settings.json` — C/C++ settings (clangd paths, includes) +- `.vscode/extensions.json` — recommended extensions (vscode-clangd, vscode-lldb) + +### clion + +```bash +dcr gen clion +``` + +Creates: +- `.idea/externalTools.xml` — external tools (build, run, clean, test) +- `.idea/customTargets.xml` — custom build targets +- `.idea/misc.xml` — C/C++ project settings +- `.idea/runConfigurations/.xml` — per-binary run configurations + +### compile-commands + +```bash +dcr gen compile-commands +``` + +Generates `compile_commands.json` — standard format for clangd, cpptools, static analyzers. + +### project-info + +```bash +dcr gen project-info +``` + +Outputs JSON array with project metadata: + +```json +[ + { + "name": "my-app", + "version": "0.1.0", + "root": "/path/to/project", + "profile": "debug", + "language": "c", + "standard": "c17", + "cxx_standard": null, + "compiler": "/usr/bin/clang", + "kind": "bin", + "sources": ["src/main.c"], + "include_dirs": ["src"], + "lib_dirs": [], + "libs": [], + "cflags": ["-std=c17", "-O0", "-g"], + "ldflags": [] + } +] +``` diff --git a/docs/commands/global-options.md b/docs/commands/global-options.md deleted file mode 100644 index a00144b..0000000 --- a/docs/commands/global-options.md +++ /dev/null @@ -1,44 +0,0 @@ -# Global options - -## `dcr --help` - -```sh -dcr --help -``` - -Prints top-level CLI usage, commands, flags, and examples. - -## `dcr --version` - -```sh -dcr --version -``` - -Prints: - -```text -dcr () -``` - -## `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. diff --git a/docs/commands/project-commands.mdx b/docs/commands/project-commands.mdx new file mode 100644 index 0000000..6a03020 --- /dev/null +++ b/docs/commands/project-commands.mdx @@ -0,0 +1,28 @@ +--- +sidebar_label: Project commands (new, init) +--- + +# Project Commands + +## `dcr new ` + +Creates a new project with a standard structure and `dcr.toml`. The `name` argument is required. + +```bash +dcr new my-app +``` + +Generates: +- `dcr.toml` with basic fields +- `src/main.c` with a `main` template + +## `dcr init` + +Initializes a DCR project in the current (empty) directory. + +```bash +mkdir app && cd app +dcr init +``` + +The project name is taken from the current directory name. diff --git a/docs/commands/quality-commands.mdx b/docs/commands/quality-commands.mdx new file mode 100644 index 0000000..c8a702b --- /dev/null +++ b/docs/commands/quality-commands.mdx @@ -0,0 +1,44 @@ +--- +sidebar_label: Quality commands (test, fmt) +--- + +# Quality Commands + +## `dcr test` + +Runs tests. + +```bash +dcr test # debug profile +dcr test --release # release profile +dcr test --debug # explicit debug +dcr test --help # detailed help +``` + +Before first use, initialize tests: + +```bash +dcr test --init +``` + +This creates `tests/dcr_test.h` (framework) and `tests/test.c` (template). + +What `dcr test` does: +1. Builds the project +2. Collects `tests/*.c` files (`.c` only, not `.cpp`) +3. Compiles and links each test file +4. Runs each test binary +5. Prints summary: TOTAL, PASS, SKIP, FAIL +6. Returns non-zero exit code on any FAIL + +## `dcr fmt` + +Formats C/C++ source files using `clang-format`. + +```bash +dcr fmt +``` + +Processes: `src/**/*.{c,cpp,cxx,cc,h,hpp,hxx,hh}` and `tests/**/*.{c,cpp,cxx,cc,h,hpp,hxx,hh}`. + +Uses `.clang-format` at the project root (if present), otherwise default clang-format style. diff --git a/docs/commands/system-commands.mdx b/docs/commands/system-commands.mdx new file mode 100644 index 0000000..df85226 --- /dev/null +++ b/docs/commands/system-commands.mdx @@ -0,0 +1,50 @@ +--- +sidebar_label: System commands (setup, --help, ...) +--- + +# System Commands + +## `dcr setup` + +Shows configured registries from `~/.dcr/config.toml`. + +```bash +dcr setup +``` + +If `~/.dcr/config.toml` is not found, DCR returns an error. Create it manually: + +```toml +[[registry]] +name = "default" +url = "https://index.dcr.pm" +``` + +## `dcr --help` + +Shows help for all commands. + +```bash +dcr --help +``` + +## `dcr --version` + +Shows version and target triple. + +```bash +dcr --version # dcr 0.7.0 (x86_64-unknown-linux-gnu) +``` + +## `dcr --update` + +Self-update. Downloads the latest release binary from GitHub Releases and replaces the current one. + +```bash +dcr --update +``` + +Features: +- Auto-detects platform and architecture +- Warns if installed via AUR (use package manager instead) +- Works on Linux, macOS, Windows diff --git a/docs/configuration/build-profiles.md b/docs/configuration/build-profiles.md deleted file mode 100644 index b7e9a08..0000000 --- a/docs/configuration/build-profiles.md +++ /dev/null @@ -1,74 +0,0 @@ -# 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 -``` - -You can also add `--force` or `--clean` to `build`/`run`. - -## Default profile flags - -### GCC/Clang-like toolchains - -- `debug`: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDCR_DEBUG` -- `release`: `-O3 -DNDEBUG` - -### MSVC toolchain - -- `debug`: `/Od /Zi /W4 /DDCR_DEBUG /Oy-` -- `release`: `/O2 /DNDEBUG` - -## Artifacts - -By default: - -- `target/debug/` (or `.exe` on Windows) -- `target/release/` (or `.exe` on Windows) - -Default compiler flags: - -GCC/Clang: - -- `debug`: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDCR_DEBUG` -- `release`: `-O3 -DNDEBUG` - -MSVC: - -- `debug`: `/Od /Zi /W4 /DDCR_DEBUG /Oy-` -- `release`: `/O2 /DNDEBUG` - -Static library mode (`kind = "staticlib"`): - -- Linux/macOS: `lib.a` -- Windows: `.lib` - -Shared library mode (`kind = "sharedlib"`): - -- Linux: `lib.so` -- macOS: `lib.dylib` -- Windows: `.dll` - -## Profile overrides - -Use `[build.debug]` and `[build.release]` to override build settings per profile. -All values inherit from `[build]`. If a field is present in the profile table, it replaces the base value. -For arrays (like `cflags`/`ldflags`), the profile value is appended to the base array. - -```toml -[build.debug] -cflags = ["-g3"] - -[build.release] -cflags = ["-O3"] -ldflags = ["-s"] -``` diff --git a/docs/configuration/build-section.md b/docs/configuration/build-section.md deleted file mode 100644 index 18790d7..0000000 --- a/docs/configuration/build-section.md +++ /dev/null @@ -1,179 +0,0 @@ -# Build section - -## Schema - -```toml -[build] -language = "c" -standard = "c11" -compiler = "clang" -kind = "bin" -# filename = "KERNEL" -# extension = "BIN" -# optional: -# inherit = true # Inherit from base (default true) -# targets = ["linux", "macos"] # Multiple targets to build -# target = "./dist" -# platform = "x86_64" -# cflags = ["-Wall"] -# ldflags = ["-lm"] -# exclude = ["src/vendor", "src/legacy/**"] -# include = ["src/legacy/boot/**"] -# roots = ["kernel", "drivers"] -# src_disable = true -# pkg_config = ["Qt6Core", "Qt6Widgets"] -# generated = ["src/ui/*.h"] -# expect = ["./target/{profile}/boot/*.bin"] -# clean = ["./target/{profile}/boot", "/tmp/image/*.img"] -``` - -## Fields - -- `language` (string or array, required): `c`, `c++`, `cpp`, `cxx`, or `asm`. - Mixed languages can be specified as an array, for example `["c", "c++", "asm"]`. -- `standard` (string, required): C language standard passed to compiler (e.g. `c11`, `c17`, `gnu11`). -- `cxx_standard` (string, optional): C++ language standard passed to compiler for `.cpp`/`.cxx`/`.cc` files - (e.g. `c++17`, `gnu++17`, `c++20`). When set, overrides `standard` for C++ sources. -- `compiler` (string, required): compiler command (for example `clang`, `gcc`, `cl`). -- `kind` (string, required): `bin`, `staticlib`, `sharedlib`, `efi`, or `elf`. -- `filename` (string, optional): custom output filename (without extension). Overrides `package.name` for the final artifact. -- `extension` (string, optional): custom file extension without the leading dot (e.g. `BIN`, `efi`, `EFI`). Combined with `filename`. -- `inherit` (bool, optional): inherit settings from base `[build]` (default `true`). If `false`, only use target/profile specific settings. -- `targets` (string array, optional): list of targets to build simultaneously. Supports short names (`linux`, `macos`, `windows`). -- `target` (string, optional): custom output directory for final artifact. - When set, DCR automatically injects `--target=` into `cflags` (useful for clang cross-compilation). -- `platform` (string, optional): architecture hint for compiler (used for `-march` or `/arch`). -- `cflags` (string array, optional): extra compile flags. - Supports variable substitution — see [Variable substitution](#variable-substitution) below. -- `ldflags` (string array, optional): extra link flags. - Supports variable substitution — see [Variable substitution](#variable-substitution) below. -- `ldscript` (string, optional): linker script path. Passed as `-T ` to the linker. Useful for bare-metal/embedded/freestanding targets. -- `exclude` (string array, optional): paths or glob patterns to skip during source/header collection. -- `include` (string array, optional): allowlist paths or globs that override `exclude`. -- `include` directory entries (non-glob) are also passed to the compiler as `-I` include paths. -- `roots` (string array, optional): additional source roots to scan instead of `src/`. -- `src_disable` (bool, optional): disables default `src/` root when true. -- `pkg_config` (string array, optional): packages used to append `pkg-config --cflags/--libs`. -- `generated` (string array, optional): generated files to delete when build steps rerun. -- `expect` (string array, optional): artifacts that must exist after build/post-steps. -- `clean` (string array, optional): additional paths removed by `dcr clean` and `--clean`. - -Notes for `exclude`/`include`: -- Supports `*` and `**` glob patterns. -- If `include` is set, it has priority over `exclude`. -- Use `include` to re-allow nested paths, for example exclude `src/boot` but allow `src/boot/arch/**`. -When using glob patterns in `exclude`, DCR converts them internally, so `exclude` globs still work as expected. - -### Variable substitution - -`cflags`, `ldflags`, and `include` directory entries support the same `{placeholder}` variables -as build/post steps: - -| Variable | Description | -|---|---| -| `{profile}` | Build profile (`debug` / `release`) | -| `{name}` | Package name | -| `{version}` | Full package version (e.g. `0.2.1`) | -| `{version_major}` | Major version number | -| `{version_minor}` | Minor version number | -| `{version_patch}` | Patch version number | -| `{version_suffix}` | Version suffix (e.g. `-rc1`) | -| `{version_suffix_dash}` | Suffix with leading dash (or empty) | - -Example: - -```toml -[build] -cflags = ['-DPROJECT_VERSION="{version}"', '-DVERSION_MAJOR={version_major}'] -``` - -## Build steps - -```toml -[[build.steps]] -name = "uic" -in = "src/ui/*.ui" -out = "src/ui/{stem}.h" -cmd = "{uic} {in} -o {out}" - -[[build.post_steps]] -name = "image" -in = "target/{profile}/boot/*.bin" -out = "/tmp/image/os-{version}.img" -cmd = "dd if=/dev/zero of={out} bs=1M count=8" -``` - -Step notes: -- `in` supports glob patterns. -- If `in` expands to multiple files, `out` must include `{stem}`. -- Steps run only when inputs are newer than outputs. -- Variables: `{in}`, `{out}`, `{stem}`, `{cflags}`, `{uic}`, `{moc}`, `{rcc}`, `{profile}`, - `{version}`, `{version_major}`, `{version_minor}`, `{version_patch}`, `{version_suffix}`, `{version_suffix_dash}`. - -`build.clean` supports `{profile}` and version placeholders (`{version}`, `{version_major}`, ...). - -### Profile overrides - -Profile tables inherit all values from `[build]`. Any field present in the profile table replaces the base value. -Array fields (like `cflags`/`ldflags`) are appended to the base array. - -Target tables override profile and base settings for specific targets. Full inheritance order: -1. `[build..]` -2. `[build..]` -3. `[build.]` -4. `[build.]` -5. `[build]` - -If custom `cflags` are set (non-empty), default compiler flags are disabled. - -```toml -[build.debug] -cflags = ["-g3"] - -[build.release] -cflags = ["-O3"] -ldflags = ["-s"] - -# Target-specific overrides (applied after profile) -[build.linux] -compiler = "gcc" -cflags = ["-march=x86_64"] - -[build.macos] -compiler = "clang" -cflags = ["-arch", "x86_64"] - -# Full inheritance example -[build.linux.release] -cflags = ["-O3", "-march=native"] # Overrides profile and base - -[build.release.linux] -ldflags = ["-static"] # Alternative order - -[build.windows.debug] -compiler = "x86_64-w64-mingw32-gcc" -cflags = [] # Empty to disable defaults - -[build.release] -inherit = false # No inheritance, only explicit settings -``` - -## Toolchain section - -```toml -[toolchain] -cc = "clang" -cxx = "clang++" -as = "as" -ar = "ar" -ld = "ld" -uic = "uic" -moc = "moc" -rcc = "rcc" -``` - -## 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 library kinds (`staticlib`, `sharedlib`), `efi`, or `elf`. diff --git a/docs/configuration/dcr.toml-overview.md b/docs/configuration/dcr.toml-overview.md deleted file mode 100644 index 13b8fba..0000000 --- a/docs/configuration/dcr.toml-overview.md +++ /dev/null @@ -1,71 +0,0 @@ -# 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]` - -Workspace-only root: -- `[workspace]` can be added to a normal root config to define members and dependency order. -- Root config still requires `[package]`, `[build]`, and `[dependencies]`. - -## Required keys - -- `package.name` -- `package.version` -- `build.language` -- `build.standard` -- `build.compiler` -- `build.kind` - -`build.kind` must be either `bin`, `staticlib`, or `sharedlib`. - -## Optional keys - -- `build.inherit` -- `build.targets` -- `build.target` -- `build.platform` -- `build.cflags` -- `build.ldflags` -- `build.exclude` -- `build.include` -- `build.roots` -- `build.src_disable` -- `build.pkg_config` -- `build.steps` -- `build.post_steps` -- `build.generated` -- `build.expect` -- `build.clean` -- `build.debug` -- `build.release` -- `build.` (target-specific overrides) -- dependency fields (`include`, `lib`, `libs`, `system`) -- `[toolchain]` overrides (`cc`, `cxx`, `as`, `ar`, `ld`, `uic`, `moc`, `rcc`) -- `[toolchain.]` (target-specific toolchain) -- `[workspace]` members -- `[workspace.]` (target-specific workspace) -- `[run]` overrides (`cmd`) -- `[run.]` (target-specific run) diff --git a/docs/configuration/dependencies-section.md b/docs/configuration/dependencies-section.md deleted file mode 100644 index 16c8d90..0000000 --- a/docs/configuration/dependencies-section.md +++ /dev/null @@ -1,44 +0,0 @@ -# Dependencies section - -DCR supports registry-based dependencies and path dependencies. - -## Example - -```toml -[dependencies] -# Registry dependency -mylib = "0.1.0" -# Git dependency -json = { git = "https://github.com/nlohmann/json", tag = "v3.11.2" } -# Path dependency -frecli = { path = "./lib/frecli", include = ["."], lib = ["."], libs = ["frecli"] } -``` - -## Supported dependency types - -### Registry dependencies -Defined by name and version string. DCR automatically resolves the package from the configured registry index. - -### Git dependencies -Defined by repository URL and optionally branch, tag, or revision. -- `git` (string, required): repository URL. -- `branch`, `tag`, `rev` (string, optional): Git reference. - -### Path dependencies -- `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. - -## Defaults for path dependencies - -- If `include` is omitted, DCR tries `/include`. -- If `lib` is omitted, DCR tries `/lib`, then `/lib64`. -- If `libs` is omitted, dependency key name is used. - -## Validation - -- Dependency value must be a string (registry) or a TOML table (path). -- Registry dependencies use the version string to match versions in the registry. -- `path` is mandatory for path dependencies. -- `include`/`lib`/`libs` must be arrays of strings if provided. diff --git a/docs/configuration/package-section.md b/docs/configuration/package-section.md deleted file mode 100644 index 0c37415..0000000 --- a/docs/configuration/package-section.md +++ /dev/null @@ -1,35 +0,0 @@ -# Package section - -## Schema - -```toml -[package] -name = "my-app" -version = "0.1.0" -type = "app" -description = "My application" -author = "John Doe" -license = "MIT" -``` - -## Fields - -- `name` (string, required): used as output artifact base name. -- `version` (string, required): used in `dcr.lock` project entry. -- `type` (string, optional): project type (`app`, `lib`, `none`). -- `description` (string, optional): human-readable project description. -- `author` (string, optional): single author name. -- `authors` (array of strings, optional): list of authors. -- `license` (string, optional): project license identifier (e.g. `MIT`, `GPL-3.0-or-later`). -- `homepage` (string, optional): project homepage URL. -- `repository` (string, optional): source repository URL. -- `readme` (string, optional): path to README file. -- `keywords` (array of strings, optional): project keywords. -- `categories` (array of strings, optional): project categories. - -## 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. -- If `type = "lib"`, DCR generates `include/` and `lib/` directories in the target path, copying public headers and built libraries. diff --git a/docs/contributing.mdx b/docs/contributing.mdx new file mode 100644 index 0000000..b363ed6 --- /dev/null +++ b/docs/contributing.mdx @@ -0,0 +1,50 @@ +--- +sidebar_label: Contributing +--- + +# Contributing + +## Setup + +```bash +git clone https://github.com/dexoron/dcr +cd dcr +cargo build +``` + +## Code style + +All code must be formatted with `cargo fmt`: + +```bash +cargo fmt +``` + +## Linting + +```bash +cargo clippy --all-targets -- -D warnings +``` + +## Tests + +```bash +cargo test --all-targets +``` + +## PR process + +1. Fork the repository +2. Create a branch: `git checkout -b feature/description` +3. Make changes +4. Run `cargo fmt && cargo clippy && cargo test` +5. Open a Pull Request + +## CI + +CI runs: +- `cargo fmt --check` +- `cargo clippy --all-targets -- -D warnings` +- `cargo test --all-targets` +- Build on Linux, macOS, Windows +- Integration tests diff --git a/docs/dependencies-and-build/compilers-and-linking.md b/docs/dependencies-and-build/compilers-and-linking.md deleted file mode 100644 index 94f5cca..0000000 --- a/docs/dependencies-and-build/compilers-and-linking.md +++ /dev/null @@ -1,78 +0,0 @@ -# Compilers & linking - -## Compiler backend selection - -DCR picks a backend from `build.compiler`: - -- contains `clang-cl` -> MSVC backend -- equals `as` or contains `gas` -> GAS backend (standalone assembler) -- contains `gcc` or `g++` -> GCC backend -- contains `clang` or `clang++` -> Clang backend -- equals `cl` or contains `msvc` -> MSVC backend -- contains `nasm` -> NASM backend -- otherwise -> Clang backend fallback - -## Compilation model - -- Source files are found recursively in `src/` based on `build.language`. -- `build.roots` and `build.src_disable` can replace the default `src/` root. -- Mixed language builds use arrays, for example `build.language = ["c", "asm"]`. -- Each source is compiled to `target///obj/.o` (`.obj` on MSVC, where `` is `native` or target triple). -- Recompile happens when source mtime is newer than object mtime. -- `build.exclude` removes paths from source/header collection; `build.include` re-allows matching paths and has priority over `exclude`. - -## Default build flags - -These flags are applied automatically based on profile and compiler backend. - -GCC/Clang: - -- `debug`: `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDCR_DEBUG` -- `release`: `-O3 -DNDEBUG` - -MSVC: - -- `debug`: `/Od /Zi /W4 /DDCR_DEBUG /Oy-` -- `release`: `/O2 /DNDEBUG` - -Note: If custom `cflags` are set in `dcr.toml`, default profile flags are disabled to allow full control. - -## Platform hint - -If `build.platform` is set, DCR passes it as an architecture hint: - -- GCC/Clang: `-march=` -- MSVC: maps to `/arch:*` for known values (`x86`, `i386`, `i486`, `i586`, `i686`, `sse2`, `avx`, `avx2`) - -## Toolchain overrides - -If `[toolchain]` is set, DCR uses its values to override compiler/linker tools: - -- `cc`, `cxx`, `as` override compilers for C/C++/ASM -- `ar` overrides the archiver (used for `staticlib`) -- `ld` overrides the linker (used by GCC/Clang/NASM/GAS backends) -- `uic`, `moc`, `rcc` override Qt tools used in `build.steps` - -Environment overrides (highest priority): -- `DCR_COMPILER` (all languages) -- `DCR_CC`, `DCR_CXX`, `DCR_AS`, `DCR_AR`, `DCR_LD` -- `DCR_DEBUG` enables verbose build logging - -## 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. - -For `kind = "sharedlib"`: - -- Linux (GCC/Clang): `-shared` with output `.so`. -- macOS (Clang): `-dynamiclib` with output `.dylib`. -- Windows (MSVC): `/LD` with output `.dll`. diff --git a/docs/dependencies-and-build/cross-compilation.md b/docs/dependencies-and-build/cross-compilation.md deleted file mode 100644 index a3cf9f0..0000000 --- a/docs/dependencies-and-build/cross-compilation.md +++ /dev/null @@ -1,203 +0,0 @@ -# Cross-compilation and Targets - -DCR supports cross-compilation to different platforms using the `--target` flag. This allows building your project for architectures and operating systems different from the host. - -## Basic Usage - -```bash -# Build for a specific target -dcr build --target x86_64-unknown-linux-gnu --release - -# Short names for common platforms -dcr build --target linux --release # x86_64-unknown-linux-gnu -dcr build --target macos --release # x86_64-apple-darwin -dcr build --target windows --release # x86_64-pc-windows-msvc - -# Run for a specific target -dcr run --target linux --release -``` - -## Supported Targets - -### Short Names -- `linux` → `x86_64-unknown-linux-gnu` -- `macos` → `x86_64-apple-darwin` -- `windows` → `x86_64-pc-windows-msvc` - -### Full Target Triples -DCR supports any valid target triple in the format `---`. Common examples: -- `x86_64-unknown-linux-gnu` -- `aarch64-linux-gnu` -- `x86_64-apple-darwin` -- `aarch64-apple-darwin` -- `x86_64-pc-windows-msvc` -- `i686-pc-windows-gnu` - -## Configuration - -### Multiple Targets - -Configure multiple targets to build simultaneously: - -```toml -[build.targets] -targets = ["linux", "macos", "windows"] - -# Or per profile -[build.release.targets] -targets = ["linux", "macos"] -``` - -If no `--target` is specified, DCR builds for all targets in `build.targets` (or native if empty). - -### Target-Specific Settings - -Override settings for specific targets: - -```toml -[build.linux] -compiler = "gcc" -cflags = ["-Wall", "-O2"] - -[build.macos] -compiler = "clang" -cflags = ["-Wall", "-O2", "-arch", "x86_64"] - -[build.windows] -compiler = "x86_64-w64-mingw32-gcc" -ldflags = ["-static"] -``` - -### Target-Specific Toolchain - -Configure toolchain per target: - -```toml -[toolchain.linux] -cc = "gcc" -ld = "ld" - -[toolchain.macos] -cc = "clang" -ld = "ld" - -[toolchain.windows] -cc = "x86_64-w64-mingw32-gcc" -ld = "x86_64-w64-mingw32-ld" -``` - -### Target-Specific Run Commands - -Use custom run commands per target: - -```toml -[run.linux] -cmd = "./target/linux/release/myapp" - -[run.macos] -cmd = "open ./target/macos/release/myapp.app" - -[run.windows] -cmd = "wine ./target/windows/release/myapp.exe" -``` - -## Workspace and Dependencies Inheritance - -Workspace and dependencies sections also support target/profile inheritance: - -```toml -[workspace.linux] -members = [ - { name = "lib1", path = "libs/lib1" }, -] - -[dependencies.linux] -sdl2 = { system = true, include = ["/usr/include/SDL2"] } - -[dependencies.windows] -sdl2 = { system = true, include = ["C:/SDL2/include"] } -``` - -Order: `workspace.target.profile` → `workspace.profile.target` → `workspace.target` → `workspace.profile` → `workspace`. - -Add `inherit = false` to disable inheritance in any section. - -Settings are applied in order: -1. `[build.]` -2. `[build.]` -3. `[build]` - -### Toolchain Configuration - -For cross-compilation, configure toolchains: - -```toml -[toolchain] -cc = "aarch64-linux-gnu-gcc" -cxx = "aarch64-linux-gnu-g++" -ar = "aarch64-linux-gnu-ar" -ld = "aarch64-linux-gnu-ld" -``` - -## Output Structure - -Build outputs are organized by target: - -``` -target/ -├── native/ -│ ├── debug/ -│ └── release/ -├── x86_64-unknown-linux-gnu/ -│ ├── debug/ -│ └── release/ -└── aarch64-linux-gnu/ - ├── debug/ - └── release/ -``` - -## Requirements - -- Cross-compilation requires appropriate toolchains installed (e.g., `aarch64-linux-gnu-gcc` on Arch Linux). -- For Windows targets on Linux, install MinGW: `pacman -S mingw-w64-gcc`. -- For macOS targets on Linux, use `osxcross` or similar. - -## Examples - -### ARM Linux Build - -```bash -# Install toolchain (Arch Linux) -pacman -S aarch64-linux-gnu-gcc - -# Configure -echo '[build.aarch64-linux-gnu] -compiler = "aarch64-linux-gnu-gcc"' >> dcr.toml - -# Build -dcr build --target aarch64-linux-gnu --release -``` - -**Note:** If you set `target = "aarch64-linux-gnu"` (or any value) directly under `[build]`, DCR will automatically add `--target=...` to cflags when using clang. You usually don't need to repeat it manually. - -### Windows Build on Linux - -```bash -# Install toolchain (Arch Linux) -pacman -S mingw-w64-gcc - -# Configure -echo '[build.windows] -compiler = "x86_64-w64-mingw32-gcc"' >> dcr.toml - -# Build -dcr build --target windows --release -``` - -## Troubleshooting - -- **Toolchain not found**: Ensure the compiler is installed and in PATH, or configure `[toolchain]` in `dcr.toml`. For Arch Linux: `pacman -S aarch64-linux-gnu-gcc` for ARM, `pacman -S mingw-w64-gcc` for Windows cross-compilation. -- **Linking errors**: Check `ldflags` and library paths for cross-compilation. -- **Header issues**: Include paths may differ; use target-specific `cflags`. - -For more help, see [Troubleshooting map](troubleshooting-map.md). \ No newline at end of file diff --git a/docs/dependencies-and-build/dependency-format.md b/docs/dependencies-and-build/dependency-format.md deleted file mode 100644 index 4e57da0..0000000 --- a/docs/dependencies-and-build/dependency-format.md +++ /dev/null @@ -1,40 +0,0 @@ -# Dependency format - -Dependencies are defined in `dcr.toml` under `[dependencies]`. - -## Full example (Path) - -```toml -[dependencies] -fmt = { path = "./third_party/fmt", include = ["include"], lib = ["lib"], libs = ["fmt"] } -``` - -## Full example (Git) - -```toml -[dependencies] -json = { git = "https://github.com/nlohmann/json", tag = "v3.11.2" } -``` - -## Field reference - -- `path`: local path to dependency root. -- `git`: URL of Git repository. -- `branch`: Git branch name. -- `tag`: Git tag name. -- `rev`: Git commit SHA. -- `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 forms - -```toml -[dependencies] -mylib = { path = "./libs/mylib" } -gitlib = { git = "https://github.com/user/repo" } -# Shortest form for path -simple = "./libs/simple" -``` - -In these forms DCR will try defaults for include/lib dirs and use the dependency name as the linker library name. diff --git a/docs/dependencies-and-build/local-dependencies.md b/docs/dependencies-and-build/local-dependencies.md deleted file mode 100644 index 42d5704..0000000 --- a/docs/dependencies-and-build/local-dependencies.md +++ /dev/null @@ -1,24 +0,0 @@ -# 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//deps//`. -6. Adds include/lib/link options to compile/link commands. - -### Profile placeholders - -`path`, `include`, and `lib` entries may use `{profile}` which expands to the active profile -(`debug` or `release`). - -## 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. diff --git a/docs/dependencies-and-build/target-directory.md b/docs/dependencies-and-build/target-directory.md deleted file mode 100644 index 18c9ff9..0000000 --- a/docs/dependencies-and-build/target-directory.md +++ /dev/null @@ -1,23 +0,0 @@ -# Target directory - -By default, DCR writes final artifacts to `target///` (where `` is `native` or target triple). - -You can override this with `build.target`: - -```toml -[build] -target = "./dist" -``` - -## Behavior - -- Binary mode: - - Linux/macOS: `/` - - Windows: `/.exe` -- Static library mode: - - Linux/macOS: `/lib.a` - - Windows: `/.lib` - -## Important detail - -`build.target` changes only the final artifact location. Object cache and dependency sync directories still use `target///...`. diff --git a/docs/dependencies-and-build/versioning-and-lock-file.md b/docs/dependencies-and-build/versioning-and-lock-file.md deleted file mode 100644 index 22ede17..0000000 --- a/docs/dependencies-and-build/versioning-and-lock-file.md +++ /dev/null @@ -1,32 +0,0 @@ -# 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. diff --git a/docs/faq.mdx b/docs/faq.mdx new file mode 100644 index 0000000..75e1036 --- /dev/null +++ b/docs/faq.mdx @@ -0,0 +1,81 @@ +--- +sidebar_label: FAQ +--- + +# FAQ + +## Registry not found + +``` +error: registry not found +``` + +**Solution:** Make sure `~/.dcr/config.toml` exists: + +```toml +[[registry]] +name = "default" +url = "https://index.dcr.pm" +``` + +And check `DCR_INDEX_PATH`: + +```bash +echo $DCR_INDEX_PATH +``` + +## Compiler not found + +``` +error: compiler not found +``` + +**Solution:** Ensure a compiler is installed and available in PATH. + +```bash +which gcc +which clang +``` + +Or specify explicitly via `[toolchain]` in `dcr.toml`. + +## openssl-sys build failed + +When building DCR from source: + +``` +error: failed to run custom build command for openssl-sys +``` + +**Solution:** Install OpenSSL development headers: + +```bash +# Ubuntu/Debian +sudo apt install libssl-dev + +# Fedora +sudo dnf install openssl-devel + +# macOS +brew install openssl +``` + +## Ctrl+C during build + +DCR handles SIGINT: interrupts the current compilation and exits with non-zero code. + +## How to create a library? + +See [Library Recipe](/docs/recipes/library-project). + +## How to cross-compile to Windows? + +See [Cross-Compile Recipe](/docs/recipes/cross-to-windows). + +## How to create a multi-package project? + +See [Workspace Recipe](/docs/recipes/multi-package-workspace). + +## Lock file + +`dcr.lock` is created during builds (`dcr build`) when registry dependencies are present. To force an update — delete `dcr.lock` and run `dcr build`. diff --git a/docs/getting-started/build-and-run.md b/docs/getting-started/build-and-run.md deleted file mode 100644 index 731cf68..0000000 --- a/docs/getting-started/build-and-run.md +++ /dev/null @@ -1,57 +0,0 @@ -# Build and run - -## Build - -Debug (default): - -```sh -dcr build -# or -dcr build --debug -dcr build --target linux --debug -dcr build --debug --clean -``` - -Release: - -```sh -dcr build --release -dcr build --target windows --release -``` - -## Run - -```sh -dcr run -# or -dcr run --target macos -dcr run --release -dcr run --target linux --release -dcr run --release --force -``` - -`dcr run` first builds, then launches the produced binary. - -## Clean artifacts - -```sh -dcr clean -``` - -Profile-only cleanup: - -```sh -dcr clean --debug -dcr clean --release -dcr clean --all -dcr clean --release --all -``` - -## Notes - -- `run` is unavailable for `build.kind = "staticlib"`, `build.kind = "sharedlib"`, `build.kind = "efi"`, and `build.kind = "elf"`. -- Build profile flag (`--debug` / `--release`) can be passed in any argument position. -- Unknown profile flags produce an error. -- In workspace root, `clean --all` cleans all member projects. -- `--target` builds/runs for specified target (short names: `linux`, `macos`, `windows`). -- `--clean` for `build`/`run` removes `target//` and paths from `build.clean`. diff --git a/docs/getting-started/create-your-first-project.md b/docs/getting-started/create-your-first-project.md deleted file mode 100644 index a6bcf95..0000000 --- a/docs/getting-started/create-your-first-project.md +++ /dev/null @@ -1,41 +0,0 @@ -# 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 -``` diff --git a/docs/getting-started/first-steps.mdx b/docs/getting-started/first-steps.mdx new file mode 100644 index 0000000..9dc5624 --- /dev/null +++ b/docs/getting-started/first-steps.mdx @@ -0,0 +1,70 @@ +--- +sidebar_label: First steps +--- + +# First Steps + +## Create a project + +```bash +dcr new my-app +cd my-app +``` + +Structure: + +``` +my-app/ +├── dcr.toml +└── src/ + └── main.c +``` + +`dcr.toml`: +```toml +[package] +name = "my-app" +version = "0.1.0" +type = "none" + +[build] +language = "c" +standard = "c11" +compiler = "clang" +kind = "bin" +``` + +## Build + +```bash +dcr build +``` + +Output — `target//debug/my-app` (Linux) or `target/debug/my-app.exe` (Windows). + +Build profiles: +```bash +dcr build --release # release build +dcr build --debug # debug (default) +``` + +## Run + +```bash +dcr run +``` + +Builds (if needed) and runs the binary. + +## First test + +```bash +dcr test --init # create test template +dcr test # run tests +``` + +## Formatting + +```bash +dcr fmt # clang-format with .clang-format +``` diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md deleted file mode 100644 index 14e3e10..0000000 --- a/docs/getting-started/installation.md +++ /dev/null @@ -1,56 +0,0 @@ -# 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 () -``` - -## 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. diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx new file mode 100644 index 0000000..f666819 --- /dev/null +++ b/docs/getting-started/installation.mdx @@ -0,0 +1,93 @@ +--- +sidebar_label: Installation +--- + +# Installation + +## Linux (Dexoron Packages) + +Configure your package manager at https://dcr.dexoron.su and install: + +**Arch Linux** +```sh +sudo pacman -Sy dcr +``` + +**Debian/Ubuntu** +```sh +sudo apt update && sudo apt install dcr +``` + +**Fedora/RHEL** +```sh +sudo dnf install dcr +``` + +## Arch Linux (AUR) + +```sh +yay -S dcr +``` + +## macOS / Linux (Homebrew) + +```sh +brew tap dexoron/dexoron +brew install dcr +``` + +## Nix (flake) + +```sh +nix run github:dexoron/dcr +# or install to profile: +nix profile install github:dexoron/dcr +``` + +## Cargo (crates.io) + +```sh +cargo install dcr +``` + +## Linux / macOS (script) + +```sh +curl -fsSL https://dcr.dexoron.su/install.sh | bash +``` + +## BSD (script) + +```sh +curl -fsSL https://dcr.dexoron.su/install_bsd.sh | bash +``` + +## Windows (PowerShell) + +```powershell +irm https://dcr.dexoron.su/install.ps1 | iex +``` + +## From source + +```sh +git clone https://github.com/dexoron/dcr.git +cd dcr && cargo build --release +ln -sf "$PWD/target/release/dcr" ~/.local/bin/dcr +``` + +## Post-install + +Verify the installation: + +```bash +dcr --version +``` + +To use the registry, create `~/.dcr/config.toml`: + +```toml +[[registry]] +name = "default" +url = "https://index.dcr.pm" +``` diff --git a/docs/getting-started/project-structure.md b/docs/getting-started/project-structure.md deleted file mode 100644 index 9292a71..0000000 --- a/docs/getting-started/project-structure.md +++ /dev/null @@ -1,40 +0,0 @@ -# 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///obj/`: cached object files for incremental rebuild (where `` is `native` or target triple). -- `target///deps/`: synchronized copies of path dependencies. -- `target///` (or `.exe` on Windows): output for `kind = "bin"`. -- `target///lib.a` (or `.lib` on Windows): output for `kind = "staticlib"`. -- `target///lib.so` (or `.dylib` on macOS, `.dll` on Windows): output for `kind = "sharedlib"`. - -If `build.target` is set, the final artifact is written to that custom directory, while object cache still stays in `target///obj`. diff --git a/docs/ide-integration.mdx b/docs/ide-integration.mdx new file mode 100644 index 0000000..ba08f23 --- /dev/null +++ b/docs/ide-integration.mdx @@ -0,0 +1,51 @@ +--- +sidebar_label: IDE Integration +--- + +# IDE Integration + +## VS Code + +```bash +dcr gen vscode +``` + +Generates in `.vscode/`: + +| File | Purpose | +|------|---------| +| `tasks.json` | `build` task (dcr build) | +| `launch.json` | Debug launch configuration | +| `settings.json` | clangd/IntelliSense: include paths, standard | +| `extensions.json` | Recommends vscode-clangd, vscode-lldb | + +## CLion + +```bash +dcr gen clion +``` + +Generates in `.idea/`: + +| File | Purpose | +|------|---------| +| `externalTools.xml` | Build, Run, Clean, Test as external tools | +| `customTargets.xml` | Custom build targets | +| `misc.xml` | C/C++ project settings | +| `runConfigurations/.xml` | Per-binary run configurations | + +## compile_commands.json + +```bash +dcr gen compile-commands +``` + +Generates `compile_commands.json` at project root. Standard format for clangd, C/C++ IntelliSense, static analyzers. + +## project-info + +```bash +dcr gen project-info +``` + +Outputs JSON array with project metadata (see [gen-commands](/docs/commands/gen-commands)). diff --git a/docs/recipes/cross-to-windows.mdx b/docs/recipes/cross-to-windows.mdx new file mode 100644 index 0000000..1250349 --- /dev/null +++ b/docs/recipes/cross-to-windows.mdx @@ -0,0 +1,49 @@ +--- +sidebar_label: Cross-compile to Windows +--- + +# Cross-Compile to Windows from Linux + +Building a Windows binary on Linux using mingw-w64. + +## Install toolchain + +```bash +# Ubuntu/Debian +sudo apt install mingw-w64 + +# Fedora +sudo dnf install mingw64-gcc mingw64-binutils +``` + +## Configuration + +```toml +[package] +name = "my-app" +version = "0.1.0" +type = "none" + +[build] +language = "c" +standard = "c11" +compiler = "clang" +kind = "bin" +target = "x86_64-pc-windows-gnu" # explicit mingw, not msvc +``` + +## Build + +```bash +dcr build --target x86_64-pc-windows-gnu --release +``` + +Artifact: `target/x86_64-pc-windows-gnu/release/my-app.exe`. + +## Custom toolchain + +```toml +[toolchain] +cc = "x86_64-w64-mingw32-gcc" +cxx = "x86_64-w64-mingw32-g++" +``` diff --git a/docs/recipes/library-project.mdx b/docs/recipes/library-project.mdx new file mode 100644 index 0000000..b718fcc --- /dev/null +++ b/docs/recipes/library-project.mdx @@ -0,0 +1,65 @@ +--- +sidebar_label: Library project +--- + +# Library Project + +Creating a static library and using it in another project. + +## Step 1: Create the library + +```bash +dcr new my-lib +cd my-lib +``` + +`dcr.toml`: +```toml +[package] +name = "my-lib" +version = "0.1.0" +type = "none" + +[build] +language = "c" +standard = "c11" +kind = "staticlib" +``` + +`src/my_lib.h`: +```c +#ifndef MY_LIB_H +#define MY_LIB_H +int add(int a, int b); +#endif +``` + +`src/my_lib.c`: +```c +#include "my_lib.h" +int add(int a, int b) { return a + b; } +``` + +## Step 2: Build + +```bash +dcr build --release +``` + +Artifacts: +- `target//release/libmy-lib.a` (Linux) +- `target/release/my-lib.lib` (Windows) +- `target/include/` — header files + +## Step 3: Use in another project + +```bash +dcr new my-app +cd my-app +dcr add my-lib ../my-lib +``` + +Automatically: +- Adds include path to `target/include/` of the library +- Adds lib path to `target//release/` +- Links `libmy-lib.a` / `my-lib.lib` diff --git a/docs/recipes/multi-package-workspace.mdx b/docs/recipes/multi-package-workspace.mdx new file mode 100644 index 0000000..cd4b5cd --- /dev/null +++ b/docs/recipes/multi-package-workspace.mdx @@ -0,0 +1,98 @@ +--- +sidebar_label: Multi-package workspace +--- + +# Multi-Package Workspace + +A project with three packages: two libraries and a binary. + +## Structure + +``` +workspace/ +├── dcr.toml # root workspace +├── lib-core/ +│ ├── dcr.toml +│ └── src/core.c +├── lib-utils/ +│ ├── dcr.toml +│ └── src/utils.c +└── app/ + ├── dcr.toml + └── src/main.c +``` + +## Root dcr.toml + +```toml +[package] +name = "my-workspace" +version = "0.1.0" +type = "none" + +[build] +inherit = true +language = "c" +standard = "c11" + +[workspace.lib-core] +path = "lib-core" + +[workspace.lib-utils] +path = "lib-utils" +deps = ["lib-core"] + +[workspace.app] +path = "app" +deps = ["lib-core", "lib-utils"] +main = true +``` + +## Packages + +`lib-core/dcr.toml`: +```toml +[package] +name = "lib-core" +version = "0.1.0" +type = "none" + +[build] +kind = "staticlib" +``` + +`lib-utils/dcr.toml`: +```toml +[package] +name = "lib-utils" +version = "0.1.0" +type = "none" + +[build] +kind = "staticlib" +``` + +`app/dcr.toml`: +```toml +[package] +name = "app" +version = "0.1.0" +type = "none" + +[build] +kind = "bin" +``` + +## Build + +```bash +cd workspace +dcr build # builds everything in correct order +dcr build --workspace app # only app (lib-core and lib-utils built as deps) +dcr run # builds and runs main package +``` + +Build order (topological sort): +1. `lib-core` +2. `lib-utils` (depends on lib-core) +3. `app` (depends on lib-core, lib-utils) diff --git a/docs/reference-and-help/cli-reference.md b/docs/reference-and-help/cli-reference.md deleted file mode 100644 index 43d0449..0000000 --- a/docs/reference-and-help/cli-reference.md +++ /dev/null @@ -1,34 +0,0 @@ -# CLI reference - -## Command list - -```text -dcr new -dcr init -dcr setup -dcr add (optional) -dcr build [--debug|--release] [--target ] -dcr run [--debug|--release] -dcr clean [--debug|--release] [--all] -dcr tree -dcr test -dcr gen -dcr --help -dcr --version -dcr --update -``` - -## Notes on argument parsing - -- `build`/`run` parse flags in any order (`--debug|--release`, `--force`, `--clean`, `--verbose`) and reject duplicates. -- `new` requires exactly one argument. -- `init` and `--update` do not accept extra arguments. -- `clean` accepts `--debug|--release` and optional `--all`. -- `gen` supports `project-info`, `compile-commands`, `vscode`, `clion`. -- `tree` shows a dependency tree (similar to `cargo tree`). -- `test` / `tests` runs the project's tests. - -## Exit behavior overview - -- Successful command execution returns `0`. -- Validation/build/runtime failures return non-zero status. diff --git a/docs/reference-and-help/config-reference.md b/docs/reference-and-help/config-reference.md deleted file mode 100644 index e88dcf7..0000000 --- a/docs/reference-and-help/config-reference.md +++ /dev/null @@ -1,149 +0,0 @@ -# Config reference - -## Full schema - -```toml -[package] -name = "string" # required -version = "string" # required -type = "string" # optional: "app", "lib", "none" -description = "string" # optional -author = "string" # optional -authors = ["string", "..."] # optional -license = "string" # optional -homepage = "string" # optional -repository = "string" # optional -readme = "string" # optional -keywords = ["string", "..."] # optional -categories = ["string", "..."] # optional - -[build] -language = "c|c++|cpp|cxx|asm" # required (string or array) -standard = "string" # required (e.g. "c11", "gnu11") -cxx_standard = "string" # optional (e.g. "c++17", "gnu++17") -compiler = "string" # required (e.g. "clang", "gcc") -kind = "bin|staticlib|sharedlib|efi|elf" # required -target = "string" # optional (cross-compilation target triple) -platform = "string" # optional (architecture hint, -march) -type = "string" # optional -cflags = ["string", "..."] # optional (supports {version} etc.) -ldflags = ["string", "..."] # optional (supports {version} etc.) -ldscript = "string" # optional (linker script path) -exclude = ["string", "..."] # optional (glob patterns) -include = ["string", "..."] # optional (allowlist + -I dirs) -roots = ["string", "..."] # optional (source roots) -src_disable = false # optional (disable default src/) -pkg_config = ["string", "..."] # optional (pkg-config packages) -generated = ["string", "..."] # optional (generated file patterns) -expect = ["string", "..."] # optional (expected artifact patterns) -clean = ["string", "..."] # optional (extra clean paths) -targets = ["string", "..."] # optional (build targets) -filename = "string" # optional (custom output name) -extension = "string" # optional (custom extension) -inherit = true # optional (inherit base settings) - -[[build.steps]] -name = "string" # required -in = "glob" # required -out = "path" # required -cmd = "string" # required - -# Inline steps (equivalent to [[build.steps]]) -steps = [ - { name = "string", in = "glob", out = "path", cmd = "string" }, -] - -[[build.post_steps]] -name = "string" # required -in = "glob" # required (or "target/...") -out = "path" # required -cmd = "string" # required - -# Inline post_steps (equivalent to [[build.post_steps]]) -post_steps = [ - { name = "string", in = "glob", out = "path", cmd = "string" }, -] - -# Profile overrides (inherit all from [build]) -[build.debug] -cflags = ["string", "..."] # optional -ldflags = ["string", "..."] # optional - -[build.release] -cflags = ["string", "..."] # optional -ldflags = ["string", "..."] # optional - -# Target-specific overrides -[build.linux] -compiler = "string" -cflags = ["string", "..."] - -[build.windows] -compiler = "string" - -# Target + profile override -[build.linux.release] -cflags = ["string", "..."] - -[toolchain] -cc = "string" # optional (C compiler override) -cxx = "string" # optional (C++ compiler override) -as = "string" # optional (assembler override) -ar = "string" # optional (archiver override) -ld = "string" # optional (linker override) -uic = "string" # optional (Qt uic) -moc = "string" # optional (Qt moc) -rcc = "string" # optional (Qt rcc) - -[run] -cmd = "string" # required for `dcr run` - -# Debug run variant -[run.debug] -cmd = "string" - -[workspace] -[workspace.member_name] -path = "string" # required -deps = ["string", "..."] # optional - -[dependencies] -[dependencies.dep_name] -path = "string" # local path -# or -version = "string" # registry version -# or -git = "string" # git URL -branch = "string" # optional (git branch) -tag = "string" # optional (git tag) -rev = "string" # optional (git commit) -# common fields: -include = ["string", "..."] # optional (include dirs) -lib = ["string", "..."] # optional (lib dirs) -libs = ["string", "..."] # optional (link libs) -features = ["string", "..."] # optional (registry features) -``` - -## Validation rules - -- `[package]`, `[build]`, `[dependencies]` must exist. -- Required string fields must be non-empty. -- `build.kind` must be `bin`, `staticlib`, `sharedlib`, `efi`, or `elf`. -- Dependency fields `include/lib/libs` must be string arrays when provided. -- `build.exclude`/`build.include` must be string arrays when provided. -- `build.roots` must be a string array when provided. -- `build.src_disable` must be boolean when provided. -- `build.clean`/`build.generated`/`build.pkg_config`/`build.expect` must be string arrays when provided. -- `build.debug`/`build.release` must be tables; their `cflags`/`ldflags` must be string arrays. -- `build.steps`/`build.post_steps` entries must include `name`, `in`, `out`, `cmd`. -- `build.language` may be a string or array (for example `["c", "c++", "asm"]`). -- `[build.]` tables inherit all base values and override any fields they specify. - Array fields (like `cflags`/`ldflags`) are appended to the base array. - -## Generated defaults (`dcr new` / `dcr init`) - -- `package.version = "0.1.0"` -- `build.language = "c"` -- `build.standard = "c11"` -- `build.compiler = "clang"` -- `build.kind = "bin"` diff --git a/docs/reference-and-help/contributing-and-bug-reports.md b/docs/reference-and-help/contributing-and-bug-reports.md deleted file mode 100644 index 74ef824..0000000 --- a/docs/reference-and-help/contributing-and-bug-reports.md +++ /dev/null @@ -1,34 +0,0 @@ -# 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: - -- -- diff --git a/docs/reference-and-help/faq.md b/docs/reference-and-help/faq.md deleted file mode 100644 index 65a0ab2..0000000 --- a/docs/reference-and-help/faq.md +++ /dev/null @@ -1,35 +0,0 @@ -# FAQ - -## What commands are available? - -`new`, `init`, `build`, `run`, `clean`, `gen`, `--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 dependencies are tracked too: if an included header changes (or disappears), rebuild is triggered. - -## 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. diff --git a/docs/reference-and-help/flags-and-environment.md b/docs/reference-and-help/flags-and-environment.md deleted file mode 100644 index d776410..0000000 --- a/docs/reference-and-help/flags-and-environment.md +++ /dev/null @@ -1,48 +0,0 @@ -# Flags & environment - -This page summarizes runtime flags and environment variables that affect DCR behavior. - -## Build/run flags - -Used with `dcr build` and `dcr run`: - -- `--debug`: select debug profile. -- `--release`: select release profile. -- `--force`: ignore incremental cache checks and rebuild. -- `--clean`: remove `target/` and `build.clean` paths before build. - -Notes: - -- Flags can be passed in any order. -- Duplicate profile flags are rejected. - -## Clean flags - -Used with `dcr clean`: - -- `--debug` / `--release`: clean only selected profile directory. -- `--all`: in workspace root, also clean all members. - -## Environment variables - -Tool selection overrides: - -- `DCR_COMPILER` (all languages) -- `DCR_CC`, `DCR_CXX`, `DCR_AS`, `DCR_AR`, `DCR_LD` - -Diagnostics: - -- `DCR_DEBUG=1` enables verbose build logging. - -## Quick examples - -```sh -# Force full release rebuild -dcr build --release --force - -# Clean before debug run -dcr run --clean --debug - -# Use custom compiler from env -DCR_CC=clang-18 dcr build --debug -``` diff --git a/docs/reference-and-help/troubleshooting-map.md b/docs/reference-and-help/troubleshooting-map.md deleted file mode 100644 index c8f9cf9..0000000 --- a/docs/reference-and-help/troubleshooting-map.md +++ /dev/null @@ -1,75 +0,0 @@ -# Troubleshooting map - -Fast mapping from symptom to likely cause and first action. - -## `dcr.toml file not found` - -Likely cause: -- you are outside project root (or member root). - -First action: -```sh -pwd -ls -``` -Run DCR from directory that contains `dcr.toml`. - -## `Invalid config: missing [package]` / `missing [build]` - -Likely cause: -- incomplete config in root project. - -First action: -- ensure root `dcr.toml` includes `[package]`, `[build]`, and `[dependencies]`. -- for workspace setups, keep these sections in root and add `[workspace]` additionally. - -## `Unknown build flag` or profile-flag errors - -Likely cause: -- typo in flag or duplicate profile flag. - -First action: -```sh -dcr --help -``` -Use only supported flags and at most one of `--debug` / `--release`. - -## Dependency include/lib path errors - -Likely cause: -- path in `[dependencies]` does not exist. - -First action: -- verify `path`, `include`, `lib` values. -- if using profile placeholders, confirm expanded paths exist for selected profile. - -## `Cannot run library build` - -Likely cause: -- `build.kind` is `staticlib` or `sharedlib`. - -First action: -- switch `build.kind` to `bin`, or set `[run].cmd` if you intentionally need custom run command. - -## Build succeeds but output is stale - -Likely cause: -- stale artifacts or generated files from previous runs. - -First action: -```sh -dcr clean --all -dcr build --force -``` - -## `dcr --update` suggests package manager update - -Likely cause: -- DCR binary is managed by pacman/AUR. - -First action: -```sh -yay -Syu dcr -# or -paru -Syu dcr -``` diff --git a/docs/reference-and-help/workspace-guide.md b/docs/reference-and-help/workspace-guide.md deleted file mode 100644 index 55f7eae..0000000 --- a/docs/reference-and-help/workspace-guide.md +++ /dev/null @@ -1,53 +0,0 @@ -# Workspace guide - -`[workspace]` lets you build related DCR projects in dependency order from one root. - -## Important rule - -Workspace root still needs a valid root project config: - -- `[package]` -- `[build]` -- `[dependencies]` - -`[workspace]` augments that root config; it does not replace required root sections. - -## Minimal example - -```toml -[package] -name = "root-app" -version = "0.1.0" - -[build] -language = "c" -standard = "c11" -compiler = "clang" -kind = "bin" - -[dependencies] - -[workspace] -core = { path = "./modules/core", deps = [] } -net = { path = "./modules/net", deps = ["core"] } -app = { path = "./modules/app", deps = ["core", "net"] } -``` - -Each member path must point to a directory containing its own `dcr.toml`. - -## Build behavior - -- Running `dcr build` in workspace root builds members in topological dependency order, then builds the root project. - -- Running `dcr clean --all` in workspace root cleans all members too. - -- `dcr gen` in workspace root includes root + members in generated outputs. - -## Common errors - -- `workspace..path does not contain dcr.toml`: - member path is wrong or config is missing. -- `workspace dependency '' not found`: - `deps` references unknown member. -- `workspace dependency cycle at `: - cyclic dependencies in member graph. diff --git a/docs/reference/build-profiles.mdx b/docs/reference/build-profiles.mdx new file mode 100644 index 0000000..140e0fe --- /dev/null +++ b/docs/reference/build-profiles.mdx @@ -0,0 +1,55 @@ +--- +sidebar_label: Build profiles +--- + +# Build Profiles + +Profiles allow overriding `[build]` fields for specific build modes. + +## Configuration + +```toml +[build] +language = "c" +standard = "c17" +cflags = ["-Wall"] + +[build.debug] +cflags = ["-O0", "-g"] + +[build.release] +cflags = ["-O3", "-DNDEBUG"] +``` + +## Merge rules + +Fields from `[build.]` are merged on top of `[build]`: + +- **Scalar fields** (strings, numbers, bools) — replaced +- **Arrays** (`cflags`, `ldflags`, ...) — **appended** (extend the `[build]` array) + +Set `inherit = false` to disable array inheritance (only profile's own arrays are used). + +## Built-in profiles + +| Profile | Default cflags | +|---------|---------------| +| `debug` | `-O0 -g -Wall -Wextra -fno-omit-frame-pointer -DDCR_DEBUG` | +| `release` | `-O3 -DNDEBUG` | + +## Target-specific profiles + +```toml +[build.linux] +cflags = ["-DLINUX"] + +[build.windows.debug] +cflags = ["-DWIN32", "-O0", "-g"] +``` + +Application order (highest priority first): +1. `[build..]` +2. `[build..]` +3. `[build.]` +4. `[build.]` +5. `[build]` diff --git a/docs/reference/build-system.mdx b/docs/reference/build-system.mdx new file mode 100644 index 0000000..7786944 --- /dev/null +++ b/docs/reference/build-system.mdx @@ -0,0 +1,101 @@ +--- +sidebar_label: Build system +--- + +# Build System + +## Compiler Backends + +DCR supports 4 compilation backends. Selection is automatic based on file extension. + +| Backend | Files | When used | +|---------|-------|-----------| +| `unix_cc` | `.c`, `.cpp`, `.cxx`, `.cc`, `.S` | gcc/clang on Linux/macOS/BSD | +| `msvc` | `.c`, `.cpp`, `.cxx`, `.cc` | Windows (cl, clang-cl) | +| `gas` | `.s` | ARM/ARM64 assembler (no preprocessor) | +| `nasm` | `.asm` | x86/x86_64 assembler | + +### Unix CC + +- Compiler resolved via `resolve_compiler()`: `DCR_COMPILER` > `DCR_CC` > `[toolchain]` > `build.compiler` > `PATH` +- Supports `.d` files for header dependency tracking +- Flags: `-std=`, `-MMD -MF`, `-c -o`, `-I`, `-L`, `-l` + +### MSVC + +- Supports cl.exe and clang-cl.exe +- Flags: `/std:`, `/Fo:`, `/Fe:`, `/I`, `/link` + +### GAS / NASM + +- GAS: `-I`, `-c -o`, `--defsym` +- NASM: `-I`, `-o`, `-D`, `-f` (format: win64/elf64/macho64/macho32/elf32) + +## Incremental Builds + +Three levels of incrementality: + +1. **mtime** — if output is newer than all inputs, skip +2. **`.d` files** — header change tracking (including transitive) +3. **SHA256 fingerprint** — recompile if compiler flags changed (stored in `.dcr_fingerprint`) + +## Parallel Compilation + +- `thread::scope` for thread pool +- Atomic task queue (`AtomicU64`) +- Mutex on stdout (`OUTPUT_MUTEX`) +- Thread count = `available_parallelism()` + +## Build Kinds + +| Kind | Type | Path (Linux example) | +|------|------|---------------------| +| `bin` | Executable | `target///` (.exe on Windows) | +| `staticlib` | Static library | `target///lib.a` (.lib) | +| `sharedlib` | Dynamic library | `target///lib.so` (.dll/.dylib) | +| `efi` | UEFI application | `target///.efi` | +| `elf` | ELF without stdlib | `target///` | +| `none` | Compile only, no link | — | +| `custom` | Full filename+extension control | `target///.` | + +## Build Steps + +DCR supports pre-build and post-build steps: + +- `build.steps` — commands before compilation +- `build.post_steps` — commands after compilation + +Substitutions: `{stem}`, `{in}`, `{out}`, `{profile}`, `{version}`, `{name}`. + +Example Qt codegen via build steps: + +```toml +[build.steps] +moc = "moc {in} -o {out}" +``` + +## pkg-config + +Automatic lookup (read from raw config): + +```toml +[build] +pkg_config = ["sdl2", "gl"] +``` + +DCR runs `pkg-config --cflags sdl2 gl` and `pkg-config --libs sdl2 gl` and adds results to compiler/linker flags. + +## Variable Substitution + +Supported variables: + +| Variable | Description | +|----------|-------------| +| `{version}` | Package version | +| `{version_major}` | Major version part | +| `{version_minor}` | Minor version part | +| `{version_patch}` | Patch version | +| `{version_suffix}` | Suffix (e.g., `-rc1`) | +| `{version_suffix_dash}` | Suffix with dash | +| `{profile}` | Profile name (debug/release) | +| `{name}` | Package name | diff --git a/docs/reference/cross-compilation.mdx b/docs/reference/cross-compilation.mdx new file mode 100644 index 0000000..24b1c2e --- /dev/null +++ b/docs/reference/cross-compilation.mdx @@ -0,0 +1,60 @@ +--- +sidebar_label: Cross-compilation +--- + +# Cross-Compilation + +## Short Names + +DCR supports short platform names: + +| Short Name | Full Triple | +|-----------|-------------| +| `linux` | `x86_64-unknown-linux-gnu` | +| `macos` | `x86_64-apple-darwin` | +| `windows` | `x86_64-pc-windows-msvc` | + +```bash +dcr build --target windows +``` + +## Full Triples + +```bash +dcr build --target aarch64-unknown-linux-gnu +dcr build --target x86_64-pc-windows-gnu # mingw +dcr build --target armv7-unknown-linux-gnueabihf +``` + +## clang --target + +When using clang, DCR injects `--target=` into CFLAGS. + +```toml +[build] +compiler = "clang" +target = "aarch64-unknown-linux-gnu" +# Auto: cflags += ["--target=aarch64-unknown-linux-gnu"] +``` + +## Bare-Metal + +For targets containing `none`, `-elf`, `eabi`, or `baremetal`, DCR default flags are disabled (no system include paths, no `-l` libc). + +```bash +dcr build --target aarch64-none-elf +``` + +## Target Directory + +On Linux with explicit target: + +``` +target/// +``` + +On macOS/Windows or without target: + +``` +target// +``` diff --git a/docs/reference/dcr-toml.mdx b/docs/reference/dcr-toml.mdx new file mode 100644 index 0000000..e127923 --- /dev/null +++ b/docs/reference/dcr-toml.mdx @@ -0,0 +1,132 @@ +--- +sidebar_label: dcr.toml overview +--- + +# dcr.toml + +Main project configuration file. Located at the project root. + +## Structure + +```toml +[package] +# required fields + +[build] +# build settings + +[build.debug] # optional: debug override +[build.release] # optional: release override + +[build.linux] # optional: Linux override +[build.windows] # optional: Windows override +[build.windows.debug] # target + profile combination + +[toolchain] +# compiler/linker paths + +[dependencies] +# project dependencies + +[workspace] +# multi-package configuration + +[run] +# run settings +``` + +## [package] + +| Field | Required | Description | +|-------|----------|-------------| +| `name` | yes | Project name | +| `version` | yes | Semantic version | +| `type` | yes | `app`, `lib`, `none` | +| `license` | no | SPDX license identifier | +| `author` | no | Author | + +```toml +[package] +name = "my-app" +version = "0.1.0" +type = "app" +license = "MIT" +author = "John Doe" +``` + +## [build] + +| Field | Default | Description | +|-------|---------|-------------| +| `language` | `"c"` | `"c"`, `"c++"`, `"cpp"`, `"cxx"`, `"asm"` | +| `standard` | `"c11"` | C standard (`c11`, `c17`, `c23`) | +| `cxx_standard` | `"c++20"` | C++ standard (`c++17`, `c++20`, `c++23`) | +| `compiler` | `"clang"` | Preferred compiler | +| `kind` | `"bin"` | `bin`, `staticlib`, `sharedlib`, `efi`, `elf`, `none`, `custom` | +| `target` | host | Target triple for cross-compilation | +| `platform` | `"native"` | `native`, `efi`, `freestanding` | +| `cflags` | `[]` | Additional C/C++/ASM flags | +| `ldflags` | `[]` | Additional linker flags | +| `filename` | `""` | Custom output file name | +| `extension` | `""` | Custom file extension | +| `roots` | `["src"]` | Source root directories | +| `exclude` | `[]` | Exclude patterns | +| `include` | `[]` | Additional include directories | +| `src_disable` | `false` | Disable auto source discovery | +| `inherit` | `false` | Inherit build from workspace root | +| `clean` | `[]` | Glob patterns for custom clean paths | +| `out_dir` | `""` | Custom output directory | +| `workspace_only` | `false` | Workspace-only, not built standalone | + +Settings from raw config (not in typed struct): +- `pkg_config` — list of pkg-config packages +- `ldscript` — linker script path +- `build.steps` / `build.post_steps` — codegen steps + +Example: + +```toml +[build] +language = "c++" +standard = "c23" +cxx_standard = "c++23" +compiler = "clang" +kind = "sharedlib" +cflags = ["-Wall", "-Wextra"] +``` + +## [toolchain] + +```toml +[toolchain] +cc = "/usr/bin/clang" +cxx = "/usr/bin/clang++" +as = "/usr/bin/as" +ar = "/usr/bin/ar" +ld = "/usr/bin/ld.lld" +``` + +Raw config also supports `uic`, `moc`, `rcc` for Qt codegen. + +## [dependencies] + +See [dependencies](/docs/reference/dependencies). + +## [run] + +```toml +[run] +cmd = "./target/{profile}/{name}" +``` + +Substitutions: +- `{version}` — package version +- `{version_major}`, `{version_minor}`, `{version_patch}`, `{version_suffix}`, `{version_suffix_dash}` — version parts +- `{profile}` — debug / release +- `{name}` — package name + +Default `cmd` = `./target/{profile}/{name}` (macOS/Windows) or `./target///` (Linux). + +## [workspace] + +See [workspaces](/docs/reference/workspaces). diff --git a/docs/reference/dependencies.mdx b/docs/reference/dependencies.mdx new file mode 100644 index 0000000..d96f707 --- /dev/null +++ b/docs/reference/dependencies.mdx @@ -0,0 +1,84 @@ +--- +sidebar_label: Dependencies +--- + +# Dependencies + +## Formats + +The `[dependencies]` section supports three formats: + +### String (registry) + +```toml +[dependencies] +fmt = "10.1.1" +spdlog = "1.12" +catch2 = "3.4.0" +``` + +The version string is used as-is for registry lookup. + +### Table (git) + +```toml +[dependencies] +fmt = { git = "https://github.com/fmtlib/fmt", tag = "10.1.1" } +``` + +Fields: `git`, `branch`, `tag`, `rev`. + +### Table (path) + +```toml +[dependencies] +mylib = { path = "../mylib" } +``` + +## Registry + +DCR uses a package registry for dependency lookup by name. + +```toml +# ~/.dcr/config.toml +[[registry]] +name = "default" +url = "https://index.dcr.pm" +``` + +Registry priority: order in `config.toml`. The `DCR_INDEX_PATH` variable overrides the path to `index.json`. + +## Git dependencies + +DCR clones git repositories via `git2`: + +- `branch` — switch to a branch +- `tag` — switch to a tag +- `rev` — switch to a specific commit +- `features` — feature flags (parsed, but does not affect build) + +Cache path: `~/.dcr/git//`. + +## Path dependencies + +Local paths. DCR automatically discovers include and lib directories from the neighbor's `dcr.toml`. + +```toml +[dependencies] +mylib = { path = "/abs/path/to/lib" } +mylib = { path = "../relative/path" } +``` + +## dcr.lock + +Dependency lock file. Contains package names and sources. + +Created during `dcr build` when registry dependencies are present. Not updated during `dcr add` — only on the next `dcr build`. + +## Resolution process + +1. Load all dependencies (registry → git → path) +2. For path deps: recursively read their `dcr.toml` +3. For registry deps: search `index.json` +4. For git deps: clone to cache +5. Collect `include_dirs`, `lib_dirs`, `libs` for the compiler diff --git a/docs/reference/environment-variables.mdx b/docs/reference/environment-variables.mdx new file mode 100644 index 0000000..1c70f9e --- /dev/null +++ b/docs/reference/environment-variables.mdx @@ -0,0 +1,59 @@ +--- +sidebar_label: Environment variables +--- + +# Environment Variables + +## DCR_COMPILER + +Overrides the compiler for all languages. **Highest priority.** + +```bash +export DCR_COMPILER=clang +dcr build +``` + +Compiler resolution priority: +1. `DCR_COMPILER` (env) +2. `DCR_CC` / `DCR_CXX` / `DCR_AS` (env) +3. `[toolchain]` (dcr.toml) +4. `build.compiler` (dcr.toml) +5. `PATH` + +## DCR_CC / DCR_CXX / DCR_AS + +Per-language override (lower priority than `DCR_COMPILER`, higher than `[toolchain]`). + +```bash +export DCR_CC=gcc-14 +export DCR_CXX=g++-14 +export DCR_AS=arm-linux-gnueabihf-as +``` + +## DCR_LD / DCR_AR + +Override linker and archiver. + +```bash +export DCR_LD=ld.lld +export DCR_AR=llvm-ar +``` + +## DCR_DEBUG + +Enables debug mode — prints all compilation commands to stderr before execution. + +```bash +export DCR_DEBUG=1 +dcr build +``` + +## DCR_INDEX_PATH + +Overrides the path to the registry `index.json`. + +```bash +export DCR_INDEX_PATH=/custom/path/index.json +``` + +Default: `~/.dcr/index.json`. diff --git a/docs/reference/platform-support.mdx b/docs/reference/platform-support.mdx new file mode 100644 index 0000000..cc63c00 --- /dev/null +++ b/docs/reference/platform-support.mdx @@ -0,0 +1,51 @@ +--- +sidebar_label: Platform support +--- + +# Platform Support + +## Target Triples + +DCR normalizes target triples. Short platform names are expanded to full triples. + +### Linux + +``` +target/-unknown-linux-gnu// +``` + +Architectures: `x86_64`, `aarch64` (host-detected). + +Artifact type: ELF. Extensions: `.so` (sharedlib), `.a` (staticlib). + +### macOS + +``` +target// +``` + +Architectures: `x86_64`, `aarch64` (host-detected). + +Extensions: `.dylib` (sharedlib), `.a` (staticlib). + +### Windows + +``` +target// +``` + +Architectures: `x86_64`, `aarch64`. + +Extensions: `.exe` (bin), `.lib` (staticlib), `.dll` (sharedlib), `.efi` (UEFI). + +### BSD + +``` +target/-unknown-// +``` + +Supported systems: `freebsd`, `openbsd`, `netbsd`, `dragonfly`. + +## Host Detection + +DCR uses `std::env::consts::ARCH` and `std::env::consts::OS` for host platform detection. Used as fallback when `target` is not specified. diff --git a/docs/reference/workspaces.mdx b/docs/reference/workspaces.mdx new file mode 100644 index 0000000..5730d33 --- /dev/null +++ b/docs/reference/workspaces.mdx @@ -0,0 +1,67 @@ +--- +sidebar_label: Workspaces +--- + +# Workspaces + +Workspaces allow managing multiple packages in a single repository. + +## Configuration + +```toml +[workspace.lib-core] +path = "lib-core" + +[workspace.lib-utils] +path = "lib-utils" +deps = ["lib-core"] + +[workspace.app] +path = "app" +deps = ["lib-core", "lib-utils"] +main = true +``` + +### Member fields + +| Field | Description | +|-------|-------------| +| `path` | Path to the package (relative to workspace root) | +| `deps` | Dependencies on other members | +| `main` | Mark as the main package | + +## Topological sort + +DCR automatically sorts packages by dependencies: package A is built before B if B depends on A. + +Cyclic dependencies are detected and cause an error. + +## Build + +```bash +dcr build # build all packages in dependency order +dcr build --workspace app # build only app (dependencies built automatically) +``` + +When building a workspace, member outputs (libraries) are automatically added to include/lib paths of dependent packages. + +## Clean + +```bash +dcr clean # clean only root target/ +dcr clean --all # clean target/ of all packages +``` + +## Inheritance + +If a member has `inherit = true` in its `[build]` section, fields from the root `[build]` are merged into the member: + +```toml +# root dcr.toml +[build] +inherit = true +language = "c" +standard = "c17" + +# member inherits language and standard +``` diff --git a/docs/self-update.mdx b/docs/self-update.mdx new file mode 100644 index 0000000..e8d7d21 --- /dev/null +++ b/docs/self-update.mdx @@ -0,0 +1,46 @@ +--- +sidebar_label: Self Update +--- + +# Self Update + +## dcr --update + +Automatic update to the latest version. Downloads a binary (not an archive) from GitHub Releases and replaces the current executable. + +```bash +dcr --update +``` + +## How it works + +1. DCR detects the current platform and architecture +2. Fetches the latest release from `api.github.com/repos/dexoron/dcr/releases/latest` +3. Compares versions +4. Downloads the matching asset (direct binary URL, not archive) +5. Replaces the current executable via `self_replace` + +## Asset naming + +Pattern: `dcr-` or `dcr-.exe` + +| Platform | Asset name | +|----------|-----------| +| Linux x86_64 | `dcr-x86_64-unknown-linux-gnu` | +| macOS x86_64 | `dcr-x86_64-apple-darwin` | +| macOS ARM64 | `dcr-aarch64-apple-darwin` | +| Windows x86_64 | `dcr-x86_64-pc-windows-msvc.exe` | + +## AUR + +If DCR was installed via AUR, `--update` shows a warning: + +``` +Update via package manager: yay/paru -Syu {package_name} or sudo pacman -Syu {package_name} +``` + +## Errors + +- Cannot detect platform — error +- Cannot fetch release — error with URL +- No write permission — error (use `sudo` or manual install) diff --git a/docs/testing/running-tests.mdx b/docs/testing/running-tests.mdx new file mode 100644 index 0000000..f0d0bf8 --- /dev/null +++ b/docs/testing/running-tests.mdx @@ -0,0 +1,45 @@ +--- +sidebar_label: Running tests +--- + +# Running Tests + +## Execution + +```bash +dcr test +``` + +Builds the project, then compiles and runs test files from `tests/`. + +## Profiles + +```bash +dcr test # debug (default) +dcr test --release # release +dcr test --debug # explicit debug +``` + +## Output + +``` +===================== + Testsuite summary +===================== +TOTAL: 5 +PASS: 3 +SKIP: 1 +FAIL: 1 +===================== +``` + +## Exit code + +- 0 — all tests passed (FAIL = 0) +- 1 — test failures or build error + +## What gets built + +- All `.c` files from `tests/` (`.cpp` not supported) +- Include path: `tests/` (for `dcr_test.h`) +- Linked with project if `package.type = "lib"` or `kind = "staticlib"`/`"sharedlib"` diff --git a/docs/testing/test-framework.mdx b/docs/testing/test-framework.mdx new file mode 100644 index 0000000..af6069a --- /dev/null +++ b/docs/testing/test-framework.mdx @@ -0,0 +1,68 @@ +--- +sidebar_label: Test framework (EXPECT, TEST, ...) +--- + +# Test Framework + +DCR has a built-in minimal test framework for C. + +## Macros + +### `EXPECT(expr)` + +Asserts that an expression is true. + +```c +EXPECT(1 + 1 == 2); +EXPECT(ptr != NULL); +``` + +### `SKIP(reason)` + +Skips a test with a message. + +```c +SKIP("not implemented on Windows"); +``` + +### `TEST(name)` + +Defines a test. + +```c +TEST(addition) { + EXPECT(1 + 1 == 2); + EXPECT(2 + 2 == 4); +} +``` + +### `TEST_CASE(name)` + +Registers a test case. + +```c +TEST_CASE(math) { + EXPECT(1 + 1 == 2); +} +``` + +## Initialization + +```bash +dcr test --init +``` + +Creates: +- `tests/dcr_test.h` — framework header (do not edit) +- `tests/test.c` — template with example test + +## Structure + +``` +tests/ +├── dcr_test.h # framework (do not edit) +├── test.c # main tests +└── ... # additional .c test files +``` + +Only `.c` files are compiled (`.cpp` is not supported). diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..84c8fc9 --- /dev/null +++ b/flake.lock @@ -0,0 +1,135 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1780218205, + "narHash": "sha256-c4MSlBQw5MIDRkad9UNUUnBaOHAHnhuCXrDt90FDVrg=", + "owner": "nix-community", + "repo": "fenix", + "rev": "96e0fc9f1a9b37f6477fa11c3fd48575354773ed", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1779560665, + "narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1770107345, + "narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "fenix": "fenix", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "treefmt-nix": "treefmt-nix" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1780179631, + "narHash": "sha256-61A3gj4V1DyPP6lVHTdui4+dvG66pkMZSMd1Kke3Rz8=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "cce33f2f1565958787bb763ae751a6a5f56b95e3", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1780220602, + "narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "db947814a175b7ca6ded66e21383d938df01c227", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..0e24749 --- /dev/null +++ b/flake.nix @@ -0,0 +1,111 @@ +{ + description = "DCR — Cargo-like utility for managing C/C++ projects"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + flake-utils.url = "github:numtide/flake-utils"; + + treefmt-nix.url = "github:numtide/treefmt-nix"; + + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + treefmt-nix, + fenix, + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + inherit system; + }; + + cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); + packageName = cargoToml.package.name; + packageVersion = cargoToml.package.version; + + rustToolchain = fenix.packages.${system}.stable.toolchain; + + rustPlatform = pkgs.makeRustPlatform { + cargo = rustToolchain; + rustc = rustToolchain; + }; + + treefmtEval = treefmt-nix.lib.evalModule pkgs { + projectRootFile = "flake.nix"; + + programs.alejandra.enable = true; + programs.rustfmt.enable = true; + programs.taplo.enable = true; + }; + + app = rustPlatform.buildRustPackage { + pname = packageName; + version = packageVersion; + + src = ./.; + + cargoLock.lockFile = ./Cargo.lock; + + nativeBuildInputs = [ + pkgs.pkg-config + pkgs.cmake + pkgs.perl + ]; + + buildInputs = pkgs.lib.optionals pkgs.stdenv.isDarwin [ + pkgs.darwin.apple_sdk.frameworks.Security + pkgs.darwin.apple_sdk.frameworks.SystemConfiguration + ]; + + # Tests require external services; run separately. + doCheck = false; + }; + in { + packages = { + default = app; + dcr = app; + }; + + apps = let + defaultApp = + (flake-utils.lib.mkApp { + drv = app; + }) + // { + meta.description = "Run ${packageName}"; + }; + in { + default = defaultApp; + dcr = defaultApp; + }; + + checks = { + dcr = app; + formatting = treefmtEval.config.build.check self; + }; + + formatter = treefmtEval.config.build.wrapper; + + devShells.default = pkgs.mkShell { + inputsFrom = [app]; + + packages = [ + rustToolchain + pkgs.rust-analyzer + + treefmtEval.config.build.wrapper + ]; + + shellHook = '' + export RUST_SRC_PATH="${rustToolchain}/lib/rustlib/src/rust/library" + ''; + }; + }); +} diff --git a/install.sh b/install.sh index 54c6b0a..1d8d6ea 100755 --- a/install.sh +++ b/install.sh @@ -30,8 +30,8 @@ CHANNEL="" check_os() { case "$(uname -s)" in - Linux|Darwin) ;; - *) error "Only Linux and macOS are supported"; exit 1 ;; + Linux|Darwin|FreeBSD|OpenBSD|NetBSD) ;; + *) error "Only Linux, macOS, and BSD systems are supported"; exit 1 ;; esac } @@ -41,15 +41,26 @@ detect_target() { arch="$(uname -m)" case "$os:$arch" in - Linux:x86_64) TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;; - Darwin:x86_64) TARGET_TRIPLE="x86_64-apple-darwin" ;; - Darwin:arm64|Darwin:aarch64) TARGET_TRIPLE="aarch64-apple-darwin" ;; + Linux:x86_64) TARGET_TRIPLE="x86_64-unknown-linux-gnu" ;; + Linux:aarch64|Linux:arm64) TARGET_TRIPLE="aarch64-unknown-linux-gnu" ;; + Darwin:x86_64) TARGET_TRIPLE="x86_64-apple-darwin" ;; + Darwin:arm64|Darwin:aarch64) TARGET_TRIPLE="aarch64-apple-darwin" ;; + FreeBSD:x86_64|FreeBSD:amd64) TARGET_TRIPLE="x86_64-unknown-freebsd" ;; + OpenBSD:x86_64|OpenBSD:amd64) TARGET_TRIPLE="x86_64-unknown-openbsd" ;; + NetBSD:x86_64|NetBSD:amd64) TARGET_TRIPLE="x86_64-unknown-netbsd" ;; + *) error "Unsupported platform: $os/$arch"; exit 1 ;; esac } check_common_dependencies() { command -v curl >/dev/null 2>&1 || { error "curl is not installed"; exit 1; } + if [[ "$CHANNEL" == "dev" ]]; then + if ! command -v python3 >/dev/null 2>&1 && ! command -v jq >/dev/null 2>&1; then + error "For dev installations, either 'python3' or 'jq' must be installed to parse GitHub API response." + exit 1 + fi + fi } check_build_dependencies() { @@ -83,15 +94,16 @@ select_install_mode() { esac } -# Возвращает JSON нужного релиза в stdout +# Returns JSON of the requested release to stdout fetch_release_json() { if [[ "$CHANNEL" == "dev" ]]; then log "Looking for latest dev (pre-release)..." - local json + local json result json="$(curl -fsSL "$GITHUB_API_ALL")" - # Первый pre-release в списке - local result - result="$(printf '%s' "$json" | python3 - <<'EOF' + if command -v jq >/dev/null 2>&1; then + result="$(printf '%s' "$json" | jq -e -c 'map(select(.prerelease == true))[0]')" + else + result="$(printf '%s' "$json" | python3 - <<'EOF' import sys, json releases = json.load(sys.stdin) pre = [r for r in releases if r.get("prerelease", False)] @@ -101,7 +113,9 @@ else: print(json.dumps(pre[0]), end="") EOF )" - if [[ -z "$result" || "$result" == "{}" ]]; then + fi + + if [[ -z "$result" || "$result" == "{}" || "$result" == "null" ]]; then error "No dev (pre-release) found on GitHub" exit 1 fi @@ -123,9 +137,9 @@ download_binary() { exit 1 fi - # Версия без ведущего 'v' + # Version without leading 'v' version="${tag#v}" - # Имя бинарника: dcr-- + # Binary name: dcr-- asset_name="dcr-${TARGET_TRIPLE}-${version}" log "Fetching release ${tag} (channel: ${CHANNEL})..." @@ -149,7 +163,7 @@ prepare_sources() { rm -rf "$TMPDIR" git clone --depth 1 "$REPO_URL" "$TMPDIR" if [[ "$CHANNEL" == "dev" ]]; then - # Клонируем dev ветку, если она есть + # Clone dev branch if it exists git clone --depth 1 --branch dev "$REPO_URL" "$TMPDIR" 2>/dev/null || \ git clone --depth 1 "$REPO_URL" "$TMPDIR" fi @@ -193,8 +207,8 @@ main() { check_os detect_target - check_common_dependencies select_channel + check_common_dependencies select_install_mode cleanup diff --git a/install_bsd.sh b/install_bsd.sh new file mode 100755 index 0000000..867805f --- /dev/null +++ b/install_bsd.sh @@ -0,0 +1,223 @@ +#!/bin/sh +set -eu + +TMPDIR="/tmp/dcr-install" +INSTALL_PATH="$HOME/.local/share/dcr" +BINPATH="$HOME/.local/bin" +LOGFILE="$HOME/.cache/dcr-install.log" +REPO_URL="https://github.com/dexoron/dcr" +GITHUB_API_LATEST="https://api.github.com/repos/dexoron/dcr/releases/latest" +GITHUB_API_ALL="https://api.github.com/repos/dexoron/dcr/releases" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +mkdir -p "$(dirname "$LOGFILE")" + +log() { printf "${BLUE}[%s]${NC} %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" | tee -a "$LOGFILE"; } +success() { printf "${GREEN}✔ %s${NC}\n" "$1" | tee -a "$LOGFILE"; } +warn() { printf "${YELLOW}⚠ %s${NC}\n" "$1" | tee -a "$LOGFILE"; } +error() { printf "${RED}✖ %s${NC}\n" "$1" | tee -a "$LOGFILE" >&2; } + +INSTALL_MODE="" +CHANNEL="" + +check_os() { + case "$(uname -s)" in + FreeBSD|OpenBSD|NetBSD|DragonFly) ;; + *) error "Only BSD systems (FreeBSD, OpenBSD, NetBSD, DragonFly) are supported by this script"; exit 1 ;; + esac +} + +detect_target() { + local os arch + os="$(uname -s)" + arch="$(uname -m)" + + case "$os:$arch" in + FreeBSD:x86_64|FreeBSD:amd64) TARGET_TRIPLE="x86_64-unknown-freebsd" ;; + OpenBSD:x86_64|OpenBSD:amd64) TARGET_TRIPLE="x86_64-unknown-openbsd" ;; + NetBSD:x86_64|NetBSD:amd64) TARGET_TRIPLE="x86_64-unknown-netbsd" ;; + DragonFly:x86_64|DragonFly:amd64) TARGET_TRIPLE="x86_64-unknown-dragonfly" ;; + *) error "Unsupported BSD platform: $os/$arch"; exit 1 ;; + esac +} + +check_common_dependencies() { + command -v curl >/dev/null 2>&1 || { error "curl is not installed"; exit 1; } + if [ "$CHANNEL" = "dev" ]; then + if ! command -v python3 >/dev/null 2>&1 && ! command -v jq >/dev/null 2>&1; then + error "For dev installations, either 'python3' or 'jq' must be installed to parse GitHub API response." + exit 1 + fi + fi +} + +check_build_dependencies() { + command -v git >/dev/null 2>&1 || { error "git is not installed"; exit 1; } + command -v cargo >/dev/null 2>&1 || { error "cargo is not installed"; exit 1; } +} + +select_channel() { + echo "Choose channel:" + echo " 1) Latest stable release (default)" + echo " 2) Latest dev (pre-release)" + printf "Enter 1 or 2 [1]: " + read -r choice + + case "${choice:-1}" in + 1) CHANNEL="stable" ;; + 2) CHANNEL="dev" ;; + *) error "Unknown option"; exit 1 ;; + esac +} + +select_install_mode() { + echo "Choose installation mode:" + echo " 1) Download prebuilt binary from GitHub Release (recommended)" + echo " 2) Build from git" + printf "Enter 1 or 2 [1]: " + read -r choice + + case "${choice:-1}" in + 1) INSTALL_MODE="release" ;; + 2) INSTALL_MODE="build" ;; + *) error "Unknown option"; exit 1 ;; + esac +} + +fetch_release_json() { + if [ "$CHANNEL" = "dev" ]; then + log "Looking for latest dev (pre-release)..." + local json result + json="$(curl -fsSL "$GITHUB_API_ALL")" + if command -v jq >/dev/null 2>&1; then + result="$(printf '%s' "$json" | jq -e -c 'map(select(.prerelease == true))[0]')" + else + result="$(printf '%s' "$json" | python3 - <<'EOF' +import sys, json +releases = json.load(sys.stdin) +pre = [r for r in releases if r.get("prerelease", False)] +if not pre: + print("{}", end="") +else: + print(json.dumps(pre[0]), end="") +EOF +)" + fi + + if [ -z "$result" ] || [ "$result" = "{}" ] || [ "$result" = "null" ]; then + error "No dev (pre-release) found on GitHub" + exit 1 + fi + printf '%s' "$result" + else + curl -fsSL "$GITHUB_API_LATEST" + fi +} + +download_binary() { + local release_json tag version asset_name download_url + + release_json="$(fetch_release_json)" + + tag="$(printf '%s\n' "$release_json" | \ + sed -n 's/.*"tag_name": "\([^"]*\)".*/\1/p' | head -n1)" + if [ -z "$tag" ]; then + error "Failed to determine release version" + exit 1 + fi + + version="${tag#v}" + asset_name="dcr-${TARGET_TRIPLE}-${version}" + + log "Fetching release ${tag} (channel: ${CHANNEL})..." + + download_url="$(printf '%s\n' "$release_json" | \ + sed -n "s#.*\"browser_download_url\": \"\([^\"]*/${asset_name}\)\".*#\1#p" | head -n1)" + + if [ -z "$download_url" ]; then + error "Asset ${asset_name} not found in release ${tag}" + exit 1 + fi + + mkdir -p "$INSTALL_PATH" + curl -fL "$download_url" -o "$INSTALL_PATH/dcr" + chmod +x "$INSTALL_PATH/dcr" + success "Binary ${asset_name} downloaded (${tag})" +} + +prepare_sources() { + log "Fetching sources..." + rm -rf "$TMPDIR" + git clone --depth 1 "$REPO_URL" "$TMPDIR" + if [ "$CHANNEL" = "dev" ]; then + git clone --depth 1 --branch dev "$REPO_URL" "$TMPDIR" 2>/dev/null || \ + git clone --depth 1 "$REPO_URL" "$TMPDIR" + fi + success "Sources fetched" +} + +build_binary() { + log "Building release binary..." + (cd "$TMPDIR" && cargo build --release) + success "Build completed" +} + +install_built_binary() { + mkdir -p "$INSTALL_PATH" + cp "$TMPDIR/target/release/dcr" "$INSTALL_PATH/dcr" + chmod +x "$INSTALL_PATH/dcr" + success "Binary installed from source" +} + +install_link() { + log "Creating symlink..." + mkdir -p "$BINPATH" + ln -sf "$INSTALL_PATH/dcr" "$BINPATH/dcr" + success "Command 'dcr' added to $BINPATH" +} + +check_path() { + if ! echo "$PATH" | grep -q "$BINPATH"; then + warn "Directory $BINPATH not found in PATH" + echo "Add this to ~/.bashrc, ~/.zshrc or ~/.profile:" + echo "export PATH=\"$BINPATH:\$PATH\"" + fi +} + +cleanup() { + rm -rf "$TMPDIR" 2>/dev/null || true +} + +main() { + log "Starting DCR installation for BSD" + + check_os + select_channel + check_common_dependencies + detect_target + select_install_mode + cleanup + + if [ "$INSTALL_MODE" = "build" ]; then + check_build_dependencies + prepare_sources + build_binary + install_built_binary + else + download_binary + fi + + install_link + check_path + cleanup + + success "Installation completed successfully" + log "Log saved to $LOGFILE" +} + +main "$@" diff --git a/packaging/snap/snapcraft.yaml b/packaging/snap/snapcraft.yaml index 9d29037..3cf1a5e 100644 --- a/packaging/snap/snapcraft.yaml +++ b/packaging/snap/snapcraft.yaml @@ -1,4 +1,4 @@ -name: dcr +name: dcrup base: core22 version: '0.6.9' summary: Cargo-like utility to manage C/C++ projects diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..292fe49 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable" diff --git a/scripts/sync-releases-to-gitlab.py b/scripts/sync-releases-to-gitlab.py new file mode 100644 index 0000000..d1e5bed --- /dev/null +++ b/scripts/sync-releases-to-gitlab.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +"""Sync all GitHub Releases (with assets) to GitLab Releases.""" + +import json +import os +import sys +import time +import urllib.error +import urllib.request +import uuid + +GL_TOKEN = os.environ.get("GL_TOKEN") +if not GL_TOKEN: + print("FATAL: GL_TOKEN environment variable not set", file=sys.stderr) + sys.exit(1) + +GL_PROJECT = "dexoron-studio%2Fdcr" +GL_PROJECT_RAW = "dexoron-studio/dcr" +GL_API = "https://gitlab.com/api/v4" +GH_REPO = "dexoron/dcr" + + +def gl_api(method, path, data=None, filepath=None, retries=5): + url = f"{GL_API}/{path}" + headers = {"PRIVATE-TOKEN": GL_TOKEN} + + if data is not None and filepath is None: + headers["Content-Type"] = "application/json" + body = json.dumps(data).encode() + elif filepath: + boundary = uuid.uuid4().hex + with open(filepath, "rb") as f: + fdata = f.read() + fname = os.path.basename(filepath) + parts = [] + parts.append(f"--{boundary}".encode()) + parts.append(f'Content-Disposition: form-data; name="file"; filename="{fname}"'.encode()) + parts.append(b"Content-Type: application/octet-stream") + parts.append(b"") + parts.append(fdata) + parts.append(f"--{boundary}--".encode()) + parts.append(b"") + body = b"\r\n".join(parts) + headers["Content-Type"] = f"multipart/form-data; boundary={boundary}" + else: + body = None + + for attempt in range(retries): + try: + req = urllib.request.Request(url, data=body, headers=headers, method=method) + with urllib.request.urlopen(req) as resp: + text = resp.read().decode() + return json.loads(text) if text else None + except urllib.error.HTTPError as e: + body_text = e.read().decode() if e.fp else "" + if e.code in (409, 429) and attempt < retries - 1: + time.sleep(3) + continue + if attempt < retries - 1: + time.sleep(1) + continue + print(f" HTTP {e.code}: {body_text[:300]}", file=sys.stderr) + return None + except Exception as e: + if attempt < retries - 1: + time.sleep(1) + continue + print(f" Error: {e}", file=sys.stderr) + return None + return None + + +def download_file(url, dest): + with urllib.request.urlopen(url) as resp: + with open(dest, "wb") as f: + f.write(resp.read()) + + +# --- MAIN --- +print("Fetching GitHub releases...") +with urllib.request.urlopen(f"https://api.github.com/repos/{GH_REPO}/releases?per_page=50") as r: + gh_releases = json.loads(r.read().decode()) + +print(f"Found {len(gh_releases)} releases on GitHub") + +# Reverse to process oldest first (GitHub returns newest first) +gh_releases.reverse() + +print("Fetching existing GitLab releases and their assets...") +existing = gl_api("GET", f"projects/{GL_PROJECT}/releases?per_page=100") or [] +existing = existing if isinstance(existing, list) else [] + +# Build map: tag -> set of existing asset names +gl_assets = {} +for rel in existing: + tag = rel["tag_name"] + links = rel.get("assets", {}).get("links", []) or rel.get("assets", {}).get("sources", []) or [] + gl_assets[tag] = {l.get("name", "") for l in links if isinstance(l, dict)} + # Also get the release description to check if it needs updating + gl_assets[tag + "__desc"] = rel.get("description", "") + +print(f"Existing GitLab releases: {len(existing)}") + +download_dir = "/tmp/gh-assets" +os.makedirs(download_dir, exist_ok=True) + +# Reverse: process older first so newer releases with many assets get their description too +# Actually, process in original order +total = len(gh_releases) +for i, rel in enumerate(gh_releases): + tag = rel["tag_name"] + body = rel.get("body", "") or "" + assets = rel.get("assets", []) + if isinstance(assets, dict): + assets = assets.get("nodes", []) or [] + + print(f"\n{'='*60}") + print(f"[{i+1}/{total}] {tag} ({len(assets)} assets)") + + # Create or update release + existing_tag = tag in gl_assets + if not existing_tag: + print(f" Creating release...") + result = gl_api("POST", f"projects/{GL_PROJECT}/releases", data={ + "tag_name": tag, + "name": rel.get("name", tag), + "description": body, + "ref": "master", + }) + if result is None: + print(f" FAILED — skip") + continue + print(f" OK") + else: + # Update description if needed + existing_desc = gl_assets.get(tag + "__desc", "") + if body and body != existing_desc: + print(f" Updating description...") + gl_api("PUT", f"projects/{GL_PROJECT}/releases/{urllib.request.quote(tag, safe='')}", + data={"description": body}) + + existing_links = gl_assets.get(tag, set()) + + for j, asset in enumerate(assets): + aname = asset.get("name", "") + aurl = asset.get("browser_download_url", "") + if not aurl: + continue + + if aname in existing_links: + print(f" [{j+1}/{len(assets)}] {aname} — already exists") + continue + + fpath = os.path.join(download_dir, aname) + print(f" [{j+1}/{len(assets)}] {aname}...", end=" ", flush=True) + + # Download from GitHub + try: + download_file(aurl, fpath) + except Exception as e: + print(f"download failed: {e}") + continue + + # Upload to GitLab + up = gl_api("POST", f"projects/{GL_PROJECT}/uploads", filepath=fpath) + if not up or "url" not in up: + size_mb = os.path.getsize(fpath) / (1024 * 1024) + print(f"upload failed ({size_mb:.1f} MB)") + os.remove(fpath) + continue + + file_url = up["url"] + full_url = f"https://gitlab.com/{GL_PROJECT_RAW}{file_url}" + + # Link asset to release + encoded_tag = urllib.request.quote(tag, safe='') + link = gl_api("POST", + f"projects/{GL_PROJECT}/releases/{encoded_tag}/assets/links", + data={"name": aname, "url": full_url}, + retries=5) + if link: + print(f"linked") + existing_links.add(aname) + else: + print(f"link failed") + + os.remove(fpath) + + time.sleep(0.3) + +print(f"\n{'='*60}") +print("Done!") \ No newline at end of file diff --git a/src/cli/build.rs b/src/cli/build.rs index f16e511..53d7691 100644 --- a/src/cli/build.rs +++ b/src/cli/build.rs @@ -80,15 +80,26 @@ pub fn build(args: &[String]) -> i32 { } if flags.target.is_none() { let default_target = if cfg!(target_os = "linux") { - "x86_64-unknown-linux-gnu" + format!("{}-unknown-linux-gnu", std::env::consts::ARCH) } else if cfg!(target_os = "macos") { - "x86_64-apple-darwin" + "x86_64-apple-darwin".to_string() } else if cfg!(target_os = "windows") { - "x86_64-pc-windows-msvc" + "x86_64-pc-windows-msvc".to_string() + } else if cfg!(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )) { + format!( + "{}-unknown-{}", + std::env::consts::ARCH, + std::env::consts::OS + ) } else { - "unknown" + "unknown".to_string() }; - flags.target = Some(default_target.to_string()); + flags.target = Some(default_target); } if flags.clean { let mut clean_args = Vec::new(); @@ -200,7 +211,7 @@ fn get_string_with_profile_and_target( } } -fn get_build_string_with_profile(config: &Config, field: &str, profile: &str) -> String { +pub fn get_build_string_with_profile(config: &Config, field: &str, profile: &str) -> String { get_string_with_profile_and_target(config, field, profile, None) } @@ -390,6 +401,15 @@ fn ensure_target_dirs( let default_dir = if cfg!(target_os = "linux") { let arch = std::env::consts::ARCH; format!("{arch}-unknown-linux-gnu/{profile}") + } else if cfg!(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )) { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + format!("{arch}-unknown-{os}/{profile}") } else { profile.to_string() }; @@ -692,26 +712,31 @@ fn build_project_at( let resolved_linker = resolve_tool("DCR_LD", tc_ld.as_deref()); let resolved_archiver = resolve_tool("DCR_AR", tc_ar.as_deref()); - let target_dir_binding = match workspace_root { - Some(root) => { - let target_str = build_target - .map(normalize_target_os) - .filter(|t| !t.is_empty()); - let rel: PathBuf = match target_str { - Some(ref t) => Path::new("target").join(t).join(profile), - None => { - let default_dir = if cfg!(target_os = "linux") { - let arch = std::env::consts::ARCH; - format!("{arch}-unknown-linux-gnu/{profile}") - } else { - profile.to_string() - }; - Path::new("target").join(&default_dir) - } - }; - root.join(&rel).to_string_lossy().to_string() + let out_dir_config = get_build_string_with_profile(&config, "out_dir", profile); + let target_dir_binding = if !out_dir_config.is_empty() { + out_dir_config + } else { + match workspace_root { + Some(root) => { + let target_str = build_target + .map(normalize_target_os) + .filter(|t| !t.is_empty()); + let rel: PathBuf = match target_str { + Some(ref t) => Path::new("target").join(t).join(profile), + None => { + let default_dir = if cfg!(target_os = "linux") { + let arch = std::env::consts::ARCH; + format!("{arch}-unknown-linux-gnu/{profile}") + } else { + profile.to_string() + }; + Path::new("target").join(&default_dir) + } + }; + root.join(&rel).to_string_lossy().to_string() + } + None => normalize_target(build_target.unwrap_or(""), profile).unwrap_or_default(), } - None => normalize_target(build_target.unwrap_or(""), profile).unwrap_or_default(), }; let target_dir = if target_dir_binding.is_empty() { None diff --git a/src/cli/clean.rs b/src/cli/clean.rs index 521eb65..73e82bc 100644 --- a/src/cli/clean.rs +++ b/src/cli/clean.rs @@ -120,11 +120,22 @@ fn clean_from_root(root: &Path, flags: &CleanFlags) -> Result<(), String> { }) .or_else(|| { Some(if cfg!(target_os = "linux") { - "x86_64-unknown-linux-gnu".to_string() + format!("{}-unknown-linux-gnu", std::env::consts::ARCH) } else if cfg!(target_os = "macos") { "x86_64-apple-darwin".to_string() } else if cfg!(target_os = "windows") { "x86_64-pc-windows-msvc".to_string() + } else if cfg!(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )) { + format!( + "{}-unknown-{}", + std::env::consts::ARCH, + std::env::consts::OS + ) } else { "unknown".to_string() }) diff --git a/src/cli/fmt.rs b/src/cli/fmt.rs new file mode 100644 index 0000000..6517fa8 --- /dev/null +++ b/src/cli/fmt.rs @@ -0,0 +1,81 @@ +// DCR — Cargo-like C/C++ project manager. +// +// Copyright (C) 2026 Dexoron (Bezotechestvo Vladimir) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::utils::log::error; +use crate::utils::text::{BOLD_GREEN, colored}; +use glob::glob; +use std::process::Command; + +pub fn fmt(_args: &[String]) -> i32 { + let patterns = [ + "src/**/*.c", + "src/**/*.cpp", + "src/**/*.cxx", + "src/**/*.cc", + "src/**/*.h", + "src/**/*.hpp", + "src/**/*.hxx", + "src/**/*.hh", + "tests/**/*.c", + "tests/**/*.cpp", + "tests/**/*.cxx", + "tests/**/*.cc", + "tests/**/*.h", + "tests/**/*.hpp", + "tests/**/*.hxx", + "tests/**/*.hh", + ]; + + let mut files = Vec::new(); + for pattern in patterns { + if let Ok(paths) = glob(pattern) { + for path in paths.flatten() { + if let Some(s) = path.to_str() { + files.push(s.to_string()); + } + } + } + } + + if files.is_empty() { + println!(" {} No files to format", colored("Format", BOLD_GREEN)); + return 0; + } + + println!( + " {} {} files", + colored("Formatting", BOLD_GREEN), + files.len() + ); + + let status = Command::new("clang-format").arg("-i").args(&files).status(); + + match status { + Ok(s) if s.success() => { + println!(" {} successful", colored("Format", BOLD_GREEN)); + 0 + } + Ok(s) => { + error(&format!("clang-format failed with status: {}", s)); + 1 + } + Err(e) => { + error(&format!("Failed to execute clang-format: {}", e)); + 1 + } + } +} diff --git a/src/cli/help.rs b/src/cli/help.rs index 10ee2ba..eb791a1 100644 --- a/src/cli/help.rs +++ b/src/cli/help.rs @@ -31,6 +31,7 @@ pub fn help() -> i32 { println!(" run [--profile] Build and run the project (default: --debug)"); println!(" tree Display the dependency tree"); println!(" test Run project tests (alias: tests)"); + println!(" fmt Format all C/C++ source files using clang-format"); println!(" clean Remove the target directory"); println!(" gen Generate IDE integration files"); printc("FLAGS:", BOLD_GREEN); diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 9528ea1..389d98c 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -20,6 +20,7 @@ pub mod build; pub mod clean; pub mod flag_update; pub mod flags; +pub mod fmt; pub mod r#gen; pub mod help; pub mod init; diff --git a/src/cli/run.rs b/src/cli/run.rs index a7ca498..cd6b858 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -83,7 +83,6 @@ pub fn run(args: &[String]) -> i32 { return 1; } }; - let flags = match parse_build_run_flags(args) { Ok(v) => v, Err(_) => return 1, @@ -160,15 +159,26 @@ fn run_project( let mut target = flags.target.clone(); if target.is_none() { let default_target = if cfg!(target_os = "linux") { - "x86_64-unknown-linux-gnu" + format!("{}-unknown-linux-gnu", std::env::consts::ARCH) } else if cfg!(target_os = "macos") { - "x86_64-apple-darwin" + "x86_64-apple-darwin".to_string() } else if cfg!(target_os = "windows") { - "x86_64-pc-windows-msvc" + "x86_64-pc-windows-msvc".to_string() + } else if cfg!(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )) { + format!( + "{}-unknown-{}", + std::env::consts::ARCH, + std::env::consts::OS + ) } else { - "unknown" + "unknown".to_string() }; - target = Some(default_target.to_string()); + target = Some(default_target); } let build_kind = config @@ -177,14 +187,20 @@ fn run_project( .or_else(|| config.get("build.kind").and_then(|v| v.as_str())) .unwrap_or(""); - let normalized_target_dir = match workspace_root { - Some(wr) => target - .as_ref() - .and_then(|t| crate::cli::build::normalize_target(t, &flags.profile)) - .map(|rel| wr.join(&rel).to_string_lossy().to_string()), - None => target - .as_ref() - .and_then(|t| crate::cli::build::normalize_target(t, &flags.profile)), + let out_dir = + crate::cli::build::get_build_string_with_profile(&config, "out_dir", &flags.profile); + let normalized_target_dir = if !out_dir.is_empty() { + Some(out_dir) + } else { + match workspace_root { + Some(wr) => target + .as_ref() + .and_then(|t| crate::cli::build::normalize_target(t, &flags.profile)) + .map(|rel| wr.join(&rel).to_string_lossy().to_string()), + None => target + .as_ref() + .and_then(|t| crate::cli::build::normalize_target(t, &flags.profile)), + } }; let version = config diff --git a/src/core/builder/common.rs b/src/core/builder/common.rs index af956ce..7527748 100644 --- a/src/core/builder/common.rs +++ b/src/core/builder/common.rs @@ -37,9 +37,6 @@ pub fn collect_sources( collect_sources_rec(root, extensions, &mut sources, exclude_dirs, include_paths)?; } sources.sort(); - if sources.is_empty() { - return Err(format!("No source files found in {}", format_roots(roots))); - } Ok(sources) } @@ -89,17 +86,6 @@ fn collect_sources_rec( Ok(()) } -fn format_roots(roots: &[PathBuf]) -> String { - if roots.is_empty() { - return "".to_string(); - } - let mut out = Vec::new(); - for root in roots { - out.push(root.to_string_lossy().to_string()); - } - out.join(", ") -} - pub fn is_excluded(path: &Path, exclude_dirs: &[PathBuf], include_paths: &[String]) -> bool { if matches_patterns(path, include_paths, true) { return false; @@ -316,6 +302,31 @@ pub fn needs_rebuild(source: &str, object: &str) -> bool { false } +pub fn needs_link(objects: &[String], output_path: &str) -> bool { + let out_meta = match fs::metadata(output_path) { + Ok(m) => m, + Err(_) => return true, + }; + let out_time = match out_meta.modified() { + Ok(t) => t, + Err(_) => return true, + }; + for obj in objects { + let obj_meta = match fs::metadata(obj) { + Ok(m) => m, + Err(_) => return true, + }; + let obj_time = match obj_meta.modified() { + Ok(t) => t, + Err(_) => return true, + }; + if obj_time > out_time { + return true; + } + } + false +} + fn parse_d_file(content: &str) -> Vec { let mut deps = Vec::new(); let text = content.replace("\\\n", " ").replace("\\\r\n", " "); @@ -418,6 +429,55 @@ mod tests { assert_eq!(result, "target/debug/obj/main.c.obj"); } + #[test] + fn needs_link_no_output() { + let dir = temp_dir("link_no_out"); + let obj1 = dir.join("test1.o"); + let obj2 = dir.join("test2.o"); + let out = dir.join("app"); + fs::write(&obj1, "").unwrap(); + fs::write(&obj2, "").unwrap(); + let objs = vec![ + obj1.to_string_lossy().to_string(), + obj2.to_string_lossy().to_string(), + ]; + assert!(needs_link(&objs, &out.to_string_lossy())); + } + + #[test] + fn needs_link_fresh() { + let dir = temp_dir("link_fresh"); + let obj1 = dir.join("test1.o"); + let obj2 = dir.join("test2.o"); + let out = dir.join("app"); + fs::write(&obj1, "").unwrap(); + fs::write(&obj2, "").unwrap(); + std::thread::sleep(std::time::Duration::from_millis(50)); + fs::write(&out, "").unwrap(); + let objs = vec![ + obj1.to_string_lossy().to_string(), + obj2.to_string_lossy().to_string(), + ]; + assert!(!needs_link(&objs, &out.to_string_lossy())); + } + + #[test] + fn needs_link_stale() { + let dir = temp_dir("link_stale"); + let obj1 = dir.join("test1.o"); + let obj2 = dir.join("test2.o"); + let out = dir.join("app"); + fs::write(&obj1, "").unwrap(); + fs::write(&out, "").unwrap(); + std::thread::sleep(std::time::Duration::from_millis(50)); + fs::write(&obj2, "").unwrap(); + let objs = vec![ + obj1.to_string_lossy().to_string(), + obj2.to_string_lossy().to_string(), + ]; + assert!(needs_link(&objs, &out.to_string_lossy())); + } + #[test] fn needs_rebuild_no_object() { let dir = temp_dir("rebuild_no_obj"); @@ -550,7 +610,8 @@ mod tests { let result = collect_sources(&roots, &["c"], &[], &include); std::env::set_current_dir(prev).unwrap(); - assert!(result.is_err(), "empty src should return error"); + let sources = result.expect("empty src should return Ok"); + assert!(sources.is_empty(), "empty src should return empty vec"); } #[test] diff --git a/src/core/builder/gas.rs b/src/core/builder/gas.rs index 26f82a5..23406d5 100644 --- a/src/core/builder/gas.rs +++ b/src/core/builder/gas.rs @@ -43,6 +43,10 @@ pub fn build(ctx: &BuildContext) -> Result { if ctx.kind == "staticlib" { let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir); + if !common::needs_link(&objects, &lib_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } let archiver = ctx.archiver.unwrap_or(if cfg!(target_os = "windows") { "lib" } else { @@ -105,6 +109,11 @@ pub fn build(ctx: &BuildContext) -> Result { } else { platform::bin_path(ctx.profile, &final_name, ctx.target_dir) }; + + if !common::needs_link(&objects, &out_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } cmd.arg("-o").arg(out_path); if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() { diff --git a/src/core/builder/msvc.rs b/src/core/builder/msvc.rs index 55be925..110d61b 100644 --- a/src/core/builder/msvc.rs +++ b/src/core/builder/msvc.rs @@ -43,6 +43,10 @@ pub fn build(ctx: &BuildContext) -> Result { if ctx.kind == "staticlib" { let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir); + if !common::needs_link(&objects, &lib_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } let mut cmd = Command::new(ctx.archiver.unwrap_or("lib")); cmd.arg("/nologo").arg(format!("/OUT:{lib_path}")); for obj in &objects { @@ -117,6 +121,11 @@ pub fn build(ctx: &BuildContext) -> Result { } else { platform::bin_path(ctx.profile, ctx.project_name, ctx.target_dir) }; + + if !common::needs_link(&objects, &out_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } cmd.arg(format!("/Fe:{out_path}")); if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() { diff --git a/src/core/builder/nasm.rs b/src/core/builder/nasm.rs index b4c7458..0e4dc05 100644 --- a/src/core/builder/nasm.rs +++ b/src/core/builder/nasm.rs @@ -43,6 +43,10 @@ pub fn build(ctx: &BuildContext) -> Result { if ctx.kind == "staticlib" { let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir); + if !common::needs_link(&objects, &lib_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } let archiver = ctx.archiver.unwrap_or(if cfg!(target_os = "windows") { "lib" } else { @@ -105,6 +109,11 @@ pub fn build(ctx: &BuildContext) -> Result { } else { platform::bin_path(ctx.profile, &final_name, ctx.target_dir) }; + + if !common::needs_link(&objects, &out_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } cmd.arg("-o").arg(out_path); if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() { diff --git a/src/core/builder/unix_cc.rs b/src/core/builder/unix_cc.rs index 7f11d8f..eacc37f 100644 --- a/src/core/builder/unix_cc.rs +++ b/src/core/builder/unix_cc.rs @@ -45,6 +45,10 @@ pub fn build(ctx: &BuildContext) -> Result { if ctx.kind == "staticlib" { let lib_path = platform::lib_path(ctx.profile, ctx.project_name, ctx.target_dir); + if !common::needs_link(&objects, &lib_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } let mut cmd = Command::new(ctx.archiver.unwrap_or("ar")); cmd.arg("rcs").arg(&lib_path); for obj in &objects { @@ -106,6 +110,11 @@ pub fn build(ctx: &BuildContext) -> Result { } else { platform::bin_path(ctx.profile, &final_name, ctx.target_dir) }; + + if !common::needs_link(&objects, &out_path) { + let elapsed = ((start_time.elapsed().as_secs_f64() * 100.0).trunc()) / 100.0; + return Ok(elapsed); + } cmd.arg("-o").arg(out_path); if ctx.verbose || std::env::var("DCR_DEBUG").is_ok() { diff --git a/src/core/config.rs b/src/core/config.rs index 4d76099..f0fd405 100644 --- a/src/core/config.rs +++ b/src/core/config.rs @@ -27,7 +27,15 @@ const DEFAULT_LANGUAGE: &str = "c"; const DEFAULT_STANDARD: &str = "c11"; const DEFAULT_COMPILER: &str = "clang"; const DEFAULT_KIND: &str = "bin"; -const VALID_KINDS: &[&str] = &["bin", "staticlib", "sharedlib", "efi", "elf"]; +const VALID_KINDS: &[&str] = &[ + "bin", + "staticlib", + "sharedlib", + "efi", + "elf", + "none", + "custom", +]; #[derive(Debug)] pub enum ConfigError { @@ -101,7 +109,8 @@ pub struct PackageConfig { #[derive(Debug, Clone, Deserialize)] pub struct BuildConfig { pub language: LanguageConfig, - pub standard: String, + #[serde(default)] + pub standard: Option, #[serde(default)] pub cxx_standard: Option, pub compiler: String, @@ -110,6 +119,8 @@ pub struct BuildConfig { #[serde(default)] pub target: Option, #[serde(default)] + pub out_dir: Option, + #[serde(default)] pub platform: Option, #[serde(default)] pub cflags: Vec, @@ -353,7 +364,14 @@ impl Config { } validate_language_config(&build.language, "build.language")?; - if build.standard.trim().is_empty() { + let lang_is_asm = match &build.language { + LanguageConfig::One(s) => s.trim().eq_ignore_ascii_case("asm"), + LanguageConfig::Many(v) => v.len() == 1 && v[0].trim().eq_ignore_ascii_case("asm"), + }; + if let Some(ref std) = build.standard + && std.trim().is_empty() + && !lang_is_asm + { return Err(ConfigError::Invalid("build.standard is empty".into())); } if build.compiler.trim().is_empty() { @@ -380,6 +398,9 @@ impl Config { if let Some(target) = &build.target { validate_non_empty_string(target, "build.target")?; } + if let Some(out_dir) = &build.out_dir { + validate_non_empty_string(out_dir, "build.out_dir")?; + } for profile in ["release", "debug"] { if let Some(section) = self .data @@ -523,7 +544,9 @@ impl Config { if let Some(lang) = table.get("language") { self.validate_language(lang)?; } - for key in ["standard", "compiler", "kind", "target", "platform"] { + for key in [ + "standard", "compiler", "kind", "target", "out_dir", "platform", + ] { if let Some(value) = table.get(key) { let s = value.as_str().unwrap_or(""); if s.trim().is_empty() { @@ -754,7 +777,9 @@ fn format_toml(value: &Value) -> Result { } else { out.push_str(&format!("language = \"{language}\"\n")); } - out.push_str(&format!("standard = \"{standard}\"\n")); + if !standard.is_empty() { + out.push_str(&format!("standard = \"{standard}\"\n")); + } out.push_str(&format!("compiler = \"{compiler}\"\n")); let kind = build .get("kind") @@ -766,6 +791,11 @@ fn format_toml(value: &Value) -> Result { { out.push_str(&format!("target = \"{target}\"\n")); } + if let Some(out_dir) = build.get("out_dir").and_then(|v| v.as_str()) + && !out_dir.trim().is_empty() + { + out.push_str(&format!("out_dir = \"{out_dir}\"\n")); + } if let Some(cflags) = build.get("cflags") { out.push_str(&format!("cflags = {}\n", format_string_array(cflags))); } diff --git a/src/core/runner.rs b/src/core/runner.rs index 5049c49..68d2778 100644 --- a/src/core/runner.rs +++ b/src/core/runner.rs @@ -22,12 +22,10 @@ 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() { - let output = Command::new(&bin_path).output(); - match output { - Ok(o) => { - print!("{}", String::from_utf8_lossy(&o.stdout)); - eprint!("{}", String::from_utf8_lossy(&o.stderr)); - return o.status.code().unwrap_or(0); + let status = Command::new(&bin_path).status(); + match status { + Ok(s) => { + return s.code().unwrap_or(0); } Err(_) => { return 1; diff --git a/src/main.rs b/src/main.rs index d0dc1dd..fcb0ae7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,6 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see . - use crate::utils::log::error; mod cli; mod config; @@ -41,6 +40,7 @@ fn main() { "run" => cli::run::run(rest), "tree" => cli::tree::tree(rest), "test" | "tests" => cli::test::test(rest), + "fmt" => cli::fmt::fmt(rest), "clean" => cli::clean::clean(rest), "gen" => cli::r#gen::r#gen(rest), "--version" => { diff --git a/src/platform/bsd.rs b/src/platform/bsd.rs new file mode 100644 index 0000000..122b786 --- /dev/null +++ b/src/platform/bsd.rs @@ -0,0 +1,105 @@ +// DCR — Cargo-like C/C++ project manager. +// +// Copyright (C) 2026 Dexoron (Bezotechestvo Vladimir) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pub fn bin_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { + match target_dir { + Some(dir) => format!("{}/{}", dir.trim_end_matches('/'), name), + None => { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let target = format!("{arch}-unknown-{os}"); + format!("./target/{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 => { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let target = format!("{arch}-unknown-{os}"); + format!("./target/{target}/{profile}/lib{name}.a") + } + } +} + +pub fn elf_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { + match target_dir { + Some(dir) => format!("{}/{}", dir.trim_end_matches('/'), name), + None => { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let target = format!("{arch}-unknown-{os}"); + format!("./target/{target}/{profile}/{name}") + } + } +} + +pub fn efi_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { + match target_dir { + Some(dir) => format!("{}/{}.efi", dir.trim_end_matches('/'), name), + None => { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let target = format!("{arch}-unknown-{os}"); + format!("./target/{target}/{profile}/{name}.efi") + } + } +} + +pub fn shared_lib_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { + match target_dir { + Some(dir) => format!("{}/lib{}.so", dir.trim_end_matches('/'), name), + None => { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let target = format!("{arch}-unknown-{os}"); + format!("./target/{target}/{profile}/lib{name}.so") + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bin_path_default() { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let expected = format!("./target/{arch}-unknown-{os}/debug/hello"); + assert_eq!(bin_path("debug", "hello", None), expected); + } + + #[test] + fn lib_path_default() { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let expected = format!("./target/{arch}-unknown-{os}/debug/libmylib.a"); + assert_eq!(lib_path("debug", "mylib", None), expected); + } + + #[test] + fn shared_lib_path_default() { + let arch = std::env::consts::ARCH; + let os = std::env::consts::OS; + let expected = format!("./target/{arch}-unknown-{os}/debug/libmylib.so"); + assert_eq!(shared_lib_path("debug", "mylib", None), expected); + } +} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index bde52b5..5465db5 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -15,6 +15,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" +))] +pub mod bsd; #[cfg(target_os = "linux")] pub mod linux; #[cfg(target_os = "macos")] @@ -35,7 +42,24 @@ pub fn bin_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { { return windows::bin_path(profile, name, target_dir); } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] + #[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + ))] + { + return bsd::bin_path(profile, name, target_dir); + } + #[cfg(not(any( + target_os = "linux", + target_os = "macos", + target_os = "windows", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )))] { match target_dir { Some(dir) => format!("{}/{}", dir.trim_end_matches('/'), name), @@ -57,7 +81,24 @@ pub fn elf_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { { return windows::elf_path(profile, name, target_dir); } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] + #[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + ))] + { + return bsd::elf_path(profile, name, target_dir); + } + #[cfg(not(any( + target_os = "linux", + target_os = "macos", + target_os = "windows", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )))] { match target_dir { Some(dir) => format!("{}/{}", dir.trim_end_matches('/'), name), @@ -79,7 +120,24 @@ pub fn efi_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { { return windows::efi_path(profile, name, target_dir); } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] + #[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + ))] + { + return bsd::efi_path(profile, name, target_dir); + } + #[cfg(not(any( + target_os = "linux", + target_os = "macos", + target_os = "windows", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )))] { match target_dir { Some(dir) => format!("{}/{}.efi", dir.trim_end_matches('/'), name), @@ -101,7 +159,24 @@ pub fn lib_path(profile: &str, name: &str, target_dir: Option<&str>) -> String { { return windows::lib_path(profile, name, target_dir); } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] + #[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + ))] + { + return bsd::lib_path(profile, name, target_dir); + } + #[cfg(not(any( + target_os = "linux", + target_os = "macos", + target_os = "windows", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )))] { match target_dir { Some(dir) => format!("{}/lib{}.a", dir.trim_end_matches('/'), name), @@ -123,7 +198,24 @@ pub fn shared_lib_path(profile: &str, name: &str, target_dir: Option<&str>) -> S { return windows::shared_lib_path(profile, name, target_dir); } - #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] + #[cfg(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + ))] + { + return bsd::shared_lib_path(profile, name, target_dir); + } + #[cfg(not(any( + target_os = "linux", + target_os = "macos", + target_os = "windows", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )))] { match target_dir { Some(dir) => format!("{}/lib{}.so", dir.trim_end_matches('/'), name), diff --git a/tests/cli_basic.rs b/tests/cli_basic.rs index ff494bd..fd55ce9 100644 --- a/tests/cli_basic.rs +++ b/tests/cli_basic.rs @@ -383,6 +383,96 @@ fn registry_dependency_is_built_from_cache() { ); } +fn parse_project_name(toml: &str) -> String { + toml.lines() + .find(|l| l.trim().starts_with("name =")) + .and_then(|l| l.split('=').nth(1)) + .map(|s| s.trim().trim_matches('"').to_string()) + .expect("could not parse project name from dcr.toml") +} + +fn default_artifact_path(project_root: &Path, project_name: &str) -> PathBuf { + project_root + .join("target") + .join("x86_64-unknown-linux-gnu") + .join("debug") + .join(project_name) +} + +#[test] +fn build_with_target_config() { + let Some(compiler) = available_compiler() else { + eprintln!("no compiler found; skipping target config test"); + return; + }; + + let dir = unique_sandbox_dir("target_cfg"); + let out = run_dcr(&["init"], &dir); + assert!(out.status.success(), "dcr init should succeed"); + + let toml_path = dir.join("dcr.toml"); + let toml = std::fs::read_to_string(&toml_path).expect("failed to read dcr.toml"); + let project_name = parse_project_name(&toml); + let updated = toml.replace("[build]", "[build]\ntarget = \"linux\""); + std::fs::write(&toml_path, updated).expect("failed to write dcr.toml"); + + let envs = [("DCR_COMPILER", compiler)]; + let out = run_dcr_env(&["build"], &dir, &envs); + assert!( + out.status.success(), + "dcr build with target = \"linux\" should succeed" + ); + + let artifact = default_artifact_path(&dir, &project_name); + assert!( + artifact.is_file(), + "artifact should be at default path target/x86_64-unknown-linux-gnu/debug/{}", + project_name + ); +} + +#[test] +fn build_with_out_dir() { + let Some(compiler) = available_compiler() else { + eprintln!("no compiler found; skipping out_dir test"); + return; + }; + + let dir = unique_sandbox_dir("out_dir"); + let out = run_dcr(&["init"], &dir); + assert!(out.status.success(), "dcr init should succeed"); + + let toml_path = dir.join("dcr.toml"); + let toml = std::fs::read_to_string(&toml_path).expect("failed to read dcr.toml"); + let project_name = parse_project_name(&toml); + let updated = toml.replace("[build]", "[build]\nout_dir = \"./_BUILD\""); + std::fs::write(&toml_path, updated).expect("failed to write dcr.toml"); + + let envs = [("DCR_COMPILER", compiler)]; + let out = run_dcr_env(&["build"], &dir, &envs); + if !out.status.success() { + eprintln!("stdout: {}", String::from_utf8_lossy(&out.stdout)); + eprintln!("stderr: {}", String::from_utf8_lossy(&out.stderr)); + } + assert!( + out.status.success(), + "dcr build with out_dir should succeed" + ); + + let artifact = dir.join("_BUILD").join(&project_name); + assert!( + artifact.is_file(), + "artifact should be at _BUILD/{} (custom out_dir)", + project_name + ); + + let default_path = default_artifact_path(&dir, &project_name); + assert!( + !default_path.exists(), + "artifact should NOT be at default path when out_dir is set" + ); +} + #[test] fn dcr_test_runs_without_sandbox_dependency() { let Some(compiler) = available_compiler() else {
Linux (Dexoron Packages) + +See https://dcr.dexoron.su for settings youre packages manager + +**Arch Linux:** + +```sh +sudo pacman -Sy dcr +``` + +**Debian/Ubuntu:** + +```sh +sudo apt update && sudo apt install dcr +``` + +**Fedora/RHEL:** + +```sh +sudo dnf install dcr +``` + +
Arch Linux (AUR) @@ -51,6 +77,18 @@ brew tap dexoron/dexoron brew install dcr ``` +
Nix (flake) + +```sh +nix run github:dexoron/dcr +# or install to profile: +nix profile install github:dexoron/dcr +``` +
BSD (script) + +```sh +curl -fsSL https://dcr.dexoron.su/install_bsd.sh | bash +``` +