cmkabe is a modular, cross-platform build helper framework designed to simplify the orchestration of hybrid Rust (Cargo) + C/C++ (CMake/Makefile) projects. It ensures compatibility with external toolchains and legacy environments, offering simulated POSIX commands on Windows, WSL sync tools, and Zig-based cross-compilation support.
- Basic Usage
- cmkabe Design Philosophy & Architecture
- Simulated Shell Commands (
shlutil.py) - Rsync-Based Remote WSL2 Development Flow
- Cross-Compilation & Toolchains (Zig & NDK)
- CMake APIs Reference
Run the build helper via the root Makefile:
make <make_target> [BIN=<binary>] [DEBUG=<debug>] [TARGET=<target_triple>]BIN=<binary>: Specify the Cargo binary name to build or run (e.g.,make build BIN=app).DEBUG=ON|OFFor1|0: Build inDebugmode ifONor1; build inReleasemode ifOFFor0(Default:OFF).TARGET=<target_triple>: Target triple for cross-compilation (e.g.,aarch64-unknown-linux-gnu,x86_64-pc-windows-msvc, ornativefor host; default isnative).
build: Build a Cargo binary. RequiresBIN=<binary>.<binary>: Short-hand to buildBIN=<binary>directly (e.g.,make app).clean: Clean all cargo and CMake target artifacts.cmake/cmake-build: Configure and build all CMake sub-projects.cmake-clean: Clean CMake build directory for the current active configuration.cmake-distclean: Delete all caches and artifacts of the current configuration.cmake-rebuild: Shortcut forcmake-cleanfollowed bycmake-build.lib/cargo-lib: Compile Rust cargo library crates.run: Run a Cargo binary. RequiresBIN=<binary>.
Hybrid projects often face friction when linking Rust static/dynamic libraries into C/C++ targets, or vice versa. cmkabe addresses this through a declarative, file-based synchronization workflow.
┌─────────────────────┐
│ Host Env Detection │
└────────┬────────────┘
▼
┌─────────────────────────────────┐
│ TargetParser (Python) │ ◄── Reads Target / OS / Env configs
└────────┬────────┬────────┬──────┘
│ │ │
▼ ▼ ▼
┌──────────────┐┌─────────────────┐┌───────────────────────┐
│ .settings.mk ││ .settings.cmake ││ .toolchain.cmake │
│ .environ.mk ││ .environ.cmake ││ (Zig CC/CXX wrappers) │
└──────────────┘└─────────────────┘└───────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────┐┌──────────────────┐
│ Makefile ││ CMake │ ◄── Source files, libraries
└──────────────────┘└──────────────────┘
cmkabe automatically inspects target triples, parses them into components (arch, vendor, os, env), and exports the discovered environment parameters to clean build configuration files:
makeenvironment files:.settings.mk,.environ.mkcmakeenvironment files:.settings.cmake,.environ.cmake,.toolchain.cmake
These generated files bridge the variable-passing gap between GNU Make and CMake, ensuring compiler paths, flags (CFLAGS, CXXFLAGS, LDFLAGS), and architecture options match exactly.
When TARGET=native is specified, cmkabe queries registry values (on Windows), probes environment variables (such as Android NDK path, Zig location), and maps host system properties:
- Windows MSVC/GNU detection
- WSL mount points discovery
- Unix OS tags mapping
To ensure that Unix-centric Makefiles can run seamlessly on native Windows host shells (without requiring MSYS2/Cygwin), cmkabe provides a portable shell utility simulator (shlutil.py).
| Command | Options | Description |
|---|---|---|
rm |
-f, -r |
Recursively removes files/folders, resolving Windows read-only locks natively. |
mkdir |
-p, -f |
Creates paths, with safety retries in case of concurrent directory creation. |
rmdir |
-e |
Removes empty subdirectories and automatically prunes empty parent folders. |
mv |
-f |
Moves/renames files/directories across different volumes. |
cp |
-r, -P, -f |
Copies files/directories. -P respects/creates symbolic links correctly. |
mklink |
-D, -f |
Creates directory or file symbolic links on Windows and POSIX. |
fix-symlink |
— | Fixes broken Windows directory junctions and WSL absolute symlinks. |
cwd / mydir |
— | Prints the current workspace path or cmk directory formatted in standard Unix slash format. |
relpath |
— | Prints the relative path from a start directory to a target. |
win2wsl-path |
— | Converts a Windows absolute path (e.g., C:\foo) to a WSL path (/mnt/c/foo). |
wsl2win-path |
— | Converts a WSL path back to a Windows drive path. |
is-wsl-win-path |
— | Checks whether a path points to a WSL Windows mount /mnt/[a-z]/. |
touch |
-f |
Updates file timestamps or creates empty files. |
timestamp |
— | Prints the current epoch timestamp. |
cmpver |
-f |
Compares version strings. Outputs + if v1 > v2, 0 if equal, - if v1 < v2. |
winreg |
— | Queries Windows registry values (reads HKLM, HKCU, etc.). |
ndk-root |
— | Discovers the root directory of the Android NDK. |
cargo-exec |
— | Sets up Cargo environment variables and executes subcommands. |
upload |
— | Uploads files to remote servers via SFTP or FTP dynamically. |
zig-patch |
— | Discovers Zig installation and injects dynamic patches for clean linking. |
If you are developing inside Windows but want the build to execute at Linux speed on a WSL2 distro, cmkabe supports the Rsync syncing helper (rmake.py).
- Source Syncing: It calls
rsyncover SSH/WSL execution to sync workspace changes incrementally to a.rmakeshadow folder in your WSL Linux distro. - Build Delegation: It invokes the build command on the Linux side.
- Artifact Back-Syncing: It syncs output libraries (
.so,.a) back to Windows to keep IDE autocompletions and debuggers updated.
Configure your target settings to use rmake in your local environment, or use python cmk/rmake.py to trigger remote compilation.
Cross-compiling C/C++ alongside Rust cargo libraries is typically error-prone. cmkabe automates this using Zig as a cross-compiler wrapper and Android NDK auto-detection.
cmkabe packages a custom wrapper binary that allows the Zig compiler to be used as a drop-in replacement for traditional compilers like gcc, clang, ar, and ld.lld.
- Modularization: The wrapper implementation is separated into modular parts (
zig-wrapper/):allocator.zig: High-safety buffered memory allocator.parser.zig: Parameter option scanner.command.zig: Compiler mode mapper (translates wrappers forar,cc,c++,ld, etc.).logger.zig: File logging tool for tracing parameters (ZIG_WRAPPER_LOG).filter.zig: Flag rewriting rules (translates system include flags, filters unsupported options, maps-fopenmpto-lomp).main.zig: Child process spawner with Windows shell boundary protection (checks command length and falls back to safe@flagsfiles).
- Compilation: The compiler wrapper is automatically recompiled from
cmk/zig-wrapper/main.zigusingzig build-exewhenever changes are detected.
When target OS is mapped to android, TargetParser automatically searches:
- Environment variables (
ANDROID_NDK_ROOT,ANDROID_NDK_HOME,NDK_ROOT). - Standard local paths (e.g.,
%LocalAppData%/Android/Sdk/ndk/*or~/Android/Sdk/ndk/*). It then extracts compiler executable paths and includes for the specified target ABI automatically.
cmkabe provides helper functions inside cmk/cmake/env.cmake (and standard cmk/rules.cmake legacy stub) to facilitate compilation in CMake.
Links target binaries against Rust dynamic library DLLs and automatically handles MSVC .lib wrapper file generation on Windows.
cmkabe_target_link_rust_dlls(
<target>
[DLLS <dll_name1> <dll_name2> ...]
)<target>: The CMake target to apply links to.DLLS: List of dynamic library names compiled from Rust (without extension).
Configures installation tasks for compiled Rust dynamic libraries, placing them in target executable directories.
cmkabe_install_rust_dlls(
<target>
[DLLS <dll_name1> <dll_name2> ...]
[DESTINATION <install_path>]
)DESTINATION: Target directory where the binaries should be installed alongside executable files.
Creates a CMake target that delegates execution to Makefile targets, allowing hybrid project setups.
cmkabe_add_make_target(
<target_name>
[MAKE_TARGET <makefile_target>]
[WORKING_DIRECTORY <dir>]
)