"Pack everything before the developer leaves their chair for a break."
Kinetic is a standalone native Android build system written in C++.
No JVM. No Gradle. No daemon. One binary, invoked from your terminal.
- What Kinetic Does
- Requirements
- Installing on Termux (Android)
- Installing on Linux (Desktop)
- SDK & NDK Setup
- Building Kinetic from Source
- Deploying the Binary
- Your First Project
- kinetic.cmake Reference
- Build Pipeline (14 Phases)
- Command Reference
- How It Works Internally
- Troubleshooting
Kinetic builds Android APKs from C++, Java, and Kotlin sources. It replaces Gradle for projects that need fast, transparent, scriptable builds.
| Feature | Detail |
|---|---|
| Cold start | < 50 ms (native binary, no JVM) |
| Languages | C++20, Java, Kotlin |
| Architecture | aarch64 (arm64-v8a), armeabi-v7a, x86_64 |
| Hosts | Android/Termux (aarch64), Linux x86_64 |
| AAPT2 | Bundled aarch64 binary — no pkg install aapt2 needed |
| Kotlin stdlib | Auto-discovered and dexed into APK automatically |
| 16KB pages | -Wl,-z,max-page-size=16384 applied to all .so files |
| Error messages | Structured, phase-tagged, actionable |
| Telemetry | Built-in phase timing table on every build |
pkg install clang cmake git openjdk-21 kotlin
| Tool | Version | Install |
|---|---|---|
| clang++ | any | pkg install clang |
| cmake | 3.16+ | pkg install cmake |
| git | any | pkg install git |
| javac | 11+ | pkg install openjdk-21 |
| kotlinc | 1.9+ | pkg install kotlin |
sudo apt install build-essential cmake openjdk-21-jdk kotlin git
pkg update
pkg install clang cmake git openjdk-21 kotlincd ~
git clone https://github.com/yourname/kinetic # or extract the tar.gz
cd kinetic
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)The compiled binary lands at dist/kinetic with dist/assets/aapt2-aarch64 beside it.
bash deploy.shThis copies both kinetic and assets/aapt2-aarch64 to
$PREFIX/bin/ and $PREFIX/bin/assets/ so Kinetic can find its bundled
aapt2 no matter what directory you run it from.
Verify:
kinetic --version
kinetic --envcd kinetic
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
sudo cmake --install build # installs to /usr/local/bin by defaultOr without sudo:
cmake -B build -DCMAKE_INSTALL_PREFIX=$HOME/.local
cmake --build build -j$(nproc)
cmake --install build
export PATH="$HOME/.local/bin:$PATH"Kinetic auto-discovers the SDK and NDK by scanning $HOME.
No environment variables need to be set — just place the folders in the
right locations.
$HOME/
└── android-sdk/ ← SDK root (this exact name preferred)
├── build-tools/
│ └── 34.0.0/
│ ├── aapt2
│ ├── d8
│ ├── apksigner
│ └── zipalign
├── platforms/
│ └── android-34/
│ └── android.jar
└── platform-tools/
└── adb
How to get the SDK on Termux:
# Option A: Download SDK command-line tools from developer.android.com/studio
# and extract to ~/android-sdk/
# Option B: Use sdkmanager
cd ~/android-sdk
./cmdline-tools/latest/bin/sdkmanager "build-tools;34.0.0" "platforms;android-34"Kinetic also searches $HOME/Android/Sdk (Android Studio default).
$HOME/
└── android-ndk/ ← NDK root (or android-ndk-r26c, etc.)
├── toolchains/
│ └── llvm/
│ └── prebuilt/
│ └── linux-aarch64/ ← host platform
│ ├── bin/
│ │ └── aarch64-linux-android24-clang++
│ └── sysroot/
└── build/
How to get the NDK on Termux:
# Download NDK r26c (latest stable) from developer.android.com/ndk/downloads
# Extract to ~/android-ndk-r26c/ — Kinetic finds it automatically
cd ~
wget https://dl.google.com/android/repository/android-ndk-r26c-linux.zip
unzip android-ndk-r26c-linux.zip
# Now at ~/android-ndk-r26c/ — Kinetic discovers itKinetic accepts any NDK version from r21 onwards. It selects the highest
version found under $HOME.
$HOME/
├── android-sdk/ ← Android SDK
│ ├── build-tools/
│ ├── platforms/
│ └── platform-tools/
│
├── android-ndk/ ← Android NDK (any version name)
│ └── toolchains/llvm/
│
└── myapp/ ← Your project
├── kinetic ← kinetic binary (symlink or copy)
├── kinetic.cmake ← build config
└── src/
git clone https://github.com/yourname/kinetic
cd kinetic
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)After building, dist/ contains:
dist/
├── kinetic ← the binary
└── assets/
└── aapt2-aarch64 ← bundled aarch64 AAPT2 (no install needed)
The assets/ folder must always be next to the kinetic binary.
deploy.sh handles this automatically.
bash deploy.sh # auto-detects Termux ($PREFIX/bin) or ~/bin
bash deploy.sh /usr/local/bin # custom prefixWhat deploy.sh does:
- Copies
dist/kinetic→<prefix>/kinetic - Copies
dist/assets/aapt2-aarch64→<prefix>/assets/aapt2-aarch64 - Adds
<prefix>to PATH if not already present
myapp/
├── kinetic.cmake
└── src/main/
├── AndroidManifest.xml
├── cpp/
│ └── main.cpp
├── java/com/example/myapp/
│ └── MainActivity.java
├── kotlin/com/example/myapp/
│ └── App.kt
└── res/values/
└── strings.xml
set(KINETIC_APP_NAME "MyApp")
set(KINETIC_PACKAGE_NAME "com.example.myapp")
set(KINETIC_VERSION_CODE 1)
set(KINETIC_VERSION_NAME "1.0.0")
set(KINETIC_MIN_SDK 24)
set(KINETIC_TARGET_SDK 34)
set(KINETIC_COMPILE_SDK 34)
set(KINETIC_ABI_FILTERS arm64-v8a)
set(KINETIC_CPP_STANDARD 20)
set(KINETIC_CPP_FLAGS "-O2 -Wall -fPIC")
set(KINETIC_SOURCES src/main/cpp/main.cpp)
set(KINETIC_LINK_LIBS android log)
set(KINETIC_JAVA_SOURCES src/main/java)
set(KINETIC_KOTLIN_SOURCES src/main/kotlin)
set(KINETIC_KEYSTORE "~/.android/debug.keystore")
set(KINETIC_KEY_ALIAS "androiddebugkey")
set(KINETIC_KEY_PASSWORD "android")
set(KINETIC_STORE_PASSWORD "android")
set(KINETIC_OUTPUT_DIR build/outputs)
set(KINETIC_OUTPUT_NAME "myapp-debug")
set(KINETIC_TELEMETRY ON)
set(KINETIC_COLOR_OUTPUT ON)cd myapp
kinetic --build
# Output: build/outputs/myapp-debug-signed.apkkinetic --install # build + adb install
kinetic --run # build + adb install + launch| Variable | Required | Default | Description |
|---|---|---|---|
KINETIC_APP_NAME |
no | MyApplication |
Human-readable app name |
KINETIC_PACKAGE_NAME |
yes | — | Java package (e.g. com.example.app) |
KINETIC_VERSION_CODE |
no | 1 |
Integer version for Play Store |
KINETIC_VERSION_NAME |
no | 1.0.0 |
String version shown in Settings |
KINETIC_MIN_SDK |
no | 21 |
Minimum Android API level |
KINETIC_TARGET_SDK |
no | 34 |
Target Android API level |
KINETIC_COMPILE_SDK |
no | 34 |
API level to compile against |
KINETIC_BUILD_TOOLS_VER |
no | auto | e.g. 34.0.0 |
KINETIC_ABI_FILTERS |
no | arm64-v8a |
Space-separated ABI list |
KINETIC_CPP_STANDARD |
no | 17 |
C++ standard (17 or 20) |
KINETIC_CPP_FLAGS |
no | -O2 -Wall |
Extra clang++ flags |
KINETIC_SOURCES |
no | — | C++/C source files |
KINETIC_INCLUDE_DIRS |
no | — | Extra include directories |
KINETIC_LINK_LIBS |
no | — | NDK system libs (android, log, EGL…) |
KINETIC_PREBUILT_LIBS |
no | — | Pre-built .so files to bundle |
KINETIC_JAVA_SOURCES |
no | src/main/java |
Java source root |
KINETIC_KOTLIN_SOURCES |
no | src/main/kotlin |
Kotlin source root |
KINETIC_KEYSTORE |
no | ~/.android/debug.keystore |
Path to signing keystore |
KINETIC_KEY_ALIAS |
no | androiddebugkey |
Key alias in keystore |
KINETIC_KEY_PASSWORD |
no | android |
Key password |
KINETIC_STORE_PASSWORD |
no | android |
Keystore password |
KINETIC_OUTPUT_DIR |
no | build/outputs |
Where to write the APK |
KINETIC_OUTPUT_NAME |
no | app-debug |
APK filename (without .apk) |
KINETIC_TELEMETRY |
no | ON |
Show build report table |
KINETIC_VERBOSE_COPY |
no | ON |
Log every file copy |
KINETIC_COLOR_OUTPUT |
no | ON |
ANSI colour in terminal |
KINETIC_EXTRA_ASSETS |
no | — | Extra files to bundle in assets/ |
Kinetic executes these phases in strict order, each independently timed:
[01] ENV_SCAN Discover SDK, NDK, AAPT2, javac, kotlinc, kotlin-stdlib
[02] CMAKE_PARSE Read and validate kinetic.cmake
[03] RES_COMPILE Compile res/ → .flat files (SDK AAPT2, no --legacy for XML)
[04] LINK_APRS Link .flat → resources.aprs
[05] NDK_COMPILE Compile C++ with clang++ (-fPIC, -Wl,-z,max-page-size=16384)
[06] JAVA_COMPILE Compile .java → .class (javac)
[07] KOTLIN_COMPILE Compile .kt → .class (kotlinc -J-Djansi.passthrough=true)
[08] DEX_CONVERT d8: .class + kotlin-stdlib.jar → classes.dex
[09] SO_COPY Stage .so files with ABI mapping + SHA-256 validation
[10] ASSET_COPY Copy assets/, res/raw/, font files, libc++_shared.so
[11] MANIFEST_MERGE Validate + stage AndroidManifest.xml
[12] APK_PACK Package APK (aarch64 AAPT2 + zip for dex/libs/assets)
[13] SIGN_ALIGN zipalign + apksigner → single *-signed.apk (intermediates deleted)
[14] TELEMETRY Print phase breakdown + total time
After a successful build, build/outputs/ contains exactly one file:
build/outputs/myapp-debug-signed.apk
All intermediate files (*-aligned.apk, unsigned *.apk) are deleted automatically.
./kinetic Full debug build (default)
./kinetic --build Same as above
./kinetic --release Release build (optimized + signed)
./kinetic --clean Remove build/ directory
./kinetic --rebuild Clean + full build
./kinetic --install Build + adb install
./kinetic --run Build + install + launch app
./kinetic --check Validate kinetic.cmake only
./kinetic --env Show discovered SDK/NDK/tool paths
./kinetic --version Print Kinetic version + build date
Build options:
--abi arm64-v8a Build for one ABI only
--no-dex Skip DEX conversion (C++-only apps)
--no-sign Skip APK signing
--jobs 4 Parallel compile jobs
Output options:
--verbose Print every command + file operation
--quiet Suppress per-file output
--no-color Disable ANSI colours
--log build.log Write full log to file
Override discovery:
--sdk /path/to/sdk Override auto-discovered SDK
--ndk /path/to/ndk Override auto-discovered NDK
--aapt2 /path/to/aapt2 Override system AAPT2 path (file or directory)
Kinetic uses two AAPT2 binaries:
| Phase | Binary | Why |
|---|---|---|
| RES_COMPILE, LINK_APRS | Bundled assets/aapt2-aarch64 |
SDK aapt2 is x86_64 and crashes on ARM64 devices |
| APK_PACK | Same bundled binary | Consistent behaviour |
On x86_64 build machines the SDK aapt2 is used for all phases.
All .so files compiled by Kinetic include:
-Wl,-z,max-page-size=16384
This aligns ELF LOAD segments to 16KB boundaries, which is required for Android 15+ devices running on 16KB page-size kernels. The flag is harmless on traditional 4KB-page devices.
Kotlin runtime classes (kotlin.jvm.internal.Intrinsics, kotlin.collections.*,
etc.) are not present on Android devices. They must be inside the APK.
Kinetic's DEX phase passes kotlin-stdlib.jar as a positional input to d8:
d8 --min-api 24 --lib android.jar \
kotlin-stdlib.jar \ ← bundled into classes.dex
com/example/app/MainActivity.class ...
Without this, the app crashes on first launch with:
NoClassDefFoundError: Lkotlin/jvm/internal/Intrinsics;
All tool paths are resolved from environment variables:
$HOME— SDK, NDK, project root$PREFIX— Termux tools ($PREFIX/bin/aapt2,$PREFIX/lib/kotlinc/)$JAVA_HOME— alternative kotlinc stdlib location$PATH— fallback for javac, kotlinc, aapt2, adb
No path in Kinetic is hardcoded to a specific user or system layout.
Kinetic can't find an aarch64 aapt2. Make sure the assets/ folder is next
to the kinetic binary. Run bash deploy.sh to fix this.
Your kotlinc binary tries to use a glibc native library. Kinetic automatically
passes -J-Djansi.passthrough=true to suppress this. If you see it, you are
running an old kinetic binary — rebuild or redeploy.
The Kotlin stdlib was not bundled. Kinetic will warn during ENV_SCAN:
WARN kotlin-stdlib.jar not found
Check that kotlinc is on PATH and $PREFIX/lib/kotlinc/lib/kotlin-stdlib.jar
exists. On Termux: pkg install kotlin.
- Check that
KINETIC_SOURCESpaths are correct relative to the project root - Verify
KINETIC_INCLUDE_DIRSlists all needed include directories - Common fix: add
android_native_app_glue.ctoKINETIC_SOURCES
The .so was not compiled with 16KB page alignment. Rebuild — Kinetic adds
-Wl,-z,max-page-size=16384 automatically.
Old kinetic binary. The current version outputs only *-signed.apk.
Run kinetic --clean && kinetic --build to regenerate.
kinetic/
├── CMakeLists.txt
├── deploy.sh
├── assets/
│ └── aapt2-aarch64 ← bundled aarch64 AAPT2
├── dist/ ← compiled binary + assets
│ ├── kinetic
│ └── assets/
│ └── aapt2-aarch64
└── src/
├── main.cpp ← entry point
├── kinetic.hpp ← master header
├── core/ ← engine, phase_timer, telemetry
├── env/ ← env_scanner, aapt2_resolver
├── config/ ← cmake_parser, config_model
├── phases/ ← 11 build phase implementations
├── error/ ← error_reporter, error codes, hints
├── copy/ ← file_copier (SHA-256 validated), essential_manifest
├── cli/ ← cli_parser, help_printer
└── utils/ ← process (fork/exec), sha256
Kinetic v1.0.0 — Build date injected at compile time (kinetic --version)