feat: add cross-compilation support with --target flag

- Updated build and run commands to accept a --target option for specifying target platforms.
- Enhanced documentation to include cross-compilation usage and supported targets.
- Modified configuration to allow target-specific settings and toolchains.
- Introduced a new test command to run project tests with specified profiles and targets.
- Improved handling of target directories and output structure for different platforms.
- Added support for multiple targets in the configuration file.
- Implemented inheritance for workspace and dependencies based on target and profile.
This commit is contained in:
2026-04-11 13:36:18 +08:00
parent 613fbc6a6a
commit fd88e036ed
27 changed files with 749 additions and 120 deletions

View File

@@ -25,6 +25,7 @@
* [dcr run](commands/dcr-run.md)
* [dcr clean](commands/dcr-clean.md)
* [dcr gen](commands/dcr-gen.md)
* [dcr test](commands/dcr-test.md)
## Dependencies & Build
@@ -32,6 +33,7 @@
* [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

View File

@@ -8,6 +8,7 @@ Builds the project in `debug` or `release` profile.
dcr build
dcr build --debug
dcr build --release
dcr build --target linux --release
dcr build --release --force
dcr build --debug --clean
```
@@ -54,6 +55,8 @@ dcr build --debug --clean
- Profile flag (`--debug` / `--release`) can appear in any argument position (duplicates are rejected).
- Unknown profile flags return an error.
- `--target <triple>` builds for specified target (short names: `linux`, `macos`, `windows`).
- 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/<profile>` and `build.clean` paths before building.

View File

@@ -8,6 +8,7 @@ Builds the project and runs the resulting binary.
dcr run
dcr run --debug
dcr run --release
dcr run --target linux --release
dcr run --release --force
dcr run --debug --clean
```
@@ -24,6 +25,7 @@ dcr run --debug --clean
- If `build.kind = "staticlib"` or `build.kind = "sharedlib"`, `run` exits with error.
- The profile is selected from the first argument.
- `--target <triple>` runs the binary for specified target (short names: `linux`, `macos`, `windows`).
- `--force` skips build cache checks and recompiles.
- `--clean` removes `target/<profile>` and `build.clean` paths before building.

44
docs/commands/dcr-test.md Normal file
View File

@@ -0,0 +1,44 @@
# dcr test
Runs the project's test suite.
## Usage
```sh
dcr test
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 release mode by default for performance.
- Custom test logic can be added by editing `tests/test.c`.
- Fails if no `tests/test.c` exists (run `dcr test --init` first).

View File

@@ -9,6 +9,8 @@ standard = "c11"
compiler = "clang"
kind = "bin"
# optional:
# inherit = true # Inherit from base (default true)
# targets = ["linux", "macos"] # Multiple targets to build
# target = "./dist"
# platform = "x86_64"
# cflags = ["-Wall"]
@@ -30,6 +32,8 @@ kind = "bin"
- `standard` (string, required): language standard passed to compiler.
- `compiler` (string, required): compiler command (for example `clang`, `gcc`, `cl`).
- `kind` (string, required): `bin`, `staticlib`, or `sharedlib`.
- `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.
- `platform` (string, optional): architecture hint for compiler (used for `-march` or `/arch`).
- `cflags` (string array, optional): extra compile flags.
@@ -82,6 +86,15 @@ Step notes:
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.<target>.<profile>]`
2. `[build.<profile>.<target>]`
3. `[build.<target>]`
4. `[build.<profile>]`
5. `[build]`
If custom `cflags` are set (non-empty), default compiler flags are disabled.
```toml
[build.debug]
cflags = ["-g3"]
@@ -89,6 +102,29 @@ 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

View File

@@ -43,7 +43,10 @@ Workspace-only root:
## Optional keys
- `build.inherit`
- `build.targets`
- `build.target`
- `build.platform`
- `build.cflags`
- `build.ldflags`
- `build.exclude`
@@ -58,7 +61,11 @@ Workspace-only root:
- `build.clean`
- `build.debug`
- `build.release`
- `build.<target>` (target-specific overrides)
- dependency fields (`include`, `lib`, `libs`, `system`)
- `[toolchain]` overrides (`cc`, `cxx`, `as`, `ar`, `ld`, `uic`, `moc`, `rcc`)
- `[toolchain.<target>]` (target-specific toolchain)
- `[workspace]` members
- `[workspace.<target>]` (target-specific workspace)
- `[run]` overrides (`cmd`)
- `[run.<target>]` (target-specific run)

View File

@@ -17,7 +17,7 @@ DCR picks a backend from `build.compiler`:
- 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/<profile>/obj/<relative-path>.o` (`.obj` on MSVC).
- Each source is compiled to `target/<target>/<profile>/obj/<relative-path>.o` (`.obj` on MSVC, where `<target>` 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`.
@@ -35,6 +35,8 @@ 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:

View File

@@ -0,0 +1,201 @@
# 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 `<arch>-<vendor>-<os>-<abi>`. 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.<target>]`
2. `[build.<profile>]`
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
```
### 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).

View File

@@ -1,6 +1,6 @@
# Target directory
By default, DCR writes final artifacts to `target/<profile>/`.
By default, DCR writes final artifacts to `target/<target>/<profile>/` (where `<target>` is `native` or target triple).
You can override this with `build.target`:
@@ -20,4 +20,4 @@ target = "./dist"
## Important detail
`build.target` changes only the final artifact location. Object cache and dependency sync directories still use `target/<profile>/...`.
`build.target` changes only the final artifact location. Object cache and dependency sync directories still use `target/<target>/<profile>/...`.

View File

@@ -8,6 +8,7 @@ Debug (default):
dcr build
# or
dcr build --debug
dcr build --target linux --debug
dcr build --debug --clean
```
@@ -15,6 +16,7 @@ Release:
```sh
dcr build --release
dcr build --target windows --release
```
## Run
@@ -22,7 +24,9 @@ dcr build --release
```sh
dcr run
# or
dcr run --target macos
dcr run --release
dcr run --target linux --release
dcr run --release --force
```
@@ -49,4 +53,5 @@ dcr clean --release --all
- 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.
- `--clean` for `build`/`run` removes `target/<profile>` and paths from `build.clean`.
- `--target` builds/runs for specified target (short names: `linux`, `macos`, `windows`).
- `--clean` for `build`/`run` removes `target/<target>/<profile>` and paths from `build.clean`.

View File

@@ -31,10 +31,10 @@ project/
- `dcr.toml`: main project configuration.
- `dcr.lock`: generated lock file for resolved path dependencies.
- `src/`: recursively scanned source directory.
- `target/<profile>/obj/`: cached object files for incremental rebuild.
- `target/<profile>/deps/`: synchronized copies of path dependencies.
- `target/<profile>/<name>` (or `.exe` on Windows): output for `kind = "bin"`.
- `target/<profile>/lib<name>.a` (or `<name>.lib` on Windows): output for `kind = "staticlib"`.
- `target/<profile>/lib<name>.so` (or `.dylib` on macOS, `<name>.dll` on Windows): output for `kind = "sharedlib"`.
- `target/<target>/<profile>/obj/`: cached object files for incremental rebuild (where `<target>` is `native` or target triple).
- `target/<target>/<profile>/deps/`: synchronized copies of path dependencies.
- `target/<target>/<profile>/<name>` (or `.exe` on Windows): output for `kind = "bin"`.
- `target/<target>/<profile>/lib<name>.a` (or `<name>.lib` on Windows): output for `kind = "staticlib"`.
- `target/<target>/<profile>/lib<name>.so` (or `.dylib` on macOS, `<name>.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/<profile>/obj`.
If `build.target` is set, the final artifact is written to that custom directory, while object cache still stays in `target/<target>/<profile>/obj`.