# android-sdk-tools: rebuilding adb and aapt2 from AOSP source with CMake

> android-sdk-tools builds the Android platform-tools and build-tools from AOSP source with CMake instead of shipping Google's prebuilt binaries, producing fully statically linked executables for aarch64, arm, x86_64 and i686. It supports the NDK, zig, the host compilers or any custom toolchain file, and it publishes prebuilt archives through GitHub Actions for Termux and other environments that cannot use the official packages.

**lzhiyong/android-sdk-tools** — building android-sdk tools  for Android

- Repository: https://github.com/lzhiyong/android-sdk-tools
- Stars: 662 · Forks: 136
- Language: CMake
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/lzhiyong-android-sdk-tools

## Why rebuild the Android tools at all

android-sdk-tools builds the Android platform-tools and build-tools from the AOSP source with CMake, producing executables such as aapt, aapt2, aidl, zipalign, adb and fastboot. The framing of the README is a toolchain problem: Google's own prebuilt binaries are tied to a platform you might not have, and the repository's topic list includes termux, which is the tell.

On Termux, and on other systems where you cannot use a prebuilt Linux binary, the official adb and aapt2 are awkward or unusable. Building them from the same AOSP source that Google builds them from removes that constraint, and it does so in a way that is reproducible from a checkout.

The first design decision is that the executables are fully statically linked with no runtime dependencies. That matters more than it sounds. A dynamically linked aapt2 needs a matching glibc on the target, and on a non-glibc system or a different libc version the tool will not start. A static binary starts or it does not, which makes the artefact portable in a way that a shared build is not.

The second decision is that the build system accepts several toolchains, so the same source tree can produce Android executables, Linux executables or native ones, and the third is that it supports four architectures: aarch64, arm, x86_64 and i686. The Android abi names arm64-v8a, armeabi-v7a and x86 are accepted for the --arch option as well, which saves you from translating names when you move between the two vocabularies.

The licence is Apache-2.0, the primary language of the repository is CMake, and the last push was on 2026-10-15 with the project not archived.

## What actually gets built, and what each tool is for

The tools table is short and it maps onto three directories.

The build-tools directory holds aapt, aapt2, aidl, zipalign, dexdump and split-select. These are the resource and packaging tools: aapt and aapt2 compile and link resources, aidl is the Android interface definition compiler that generates the glue code between an app and a service, and zipalign aligns the uncompressed data in a package for faster loading at install time.

The platform-tools directory is larger: adb, fastboot, sqlite3, etc1tool, hprof-conv, e2fsdroid, sload_f2fs, mke2fs, make_f2fs and make_f2fs_casefold. adb and fastboot are the two everyone knows, and the presence of mke2fs and make_f2fs means the F2FS and ext filesystem tools are built too, which is what you need if you are pushing a filesystem image to a device rather than just running an app.

The others directory holds veridex, a tool for finding symbols in a native binary.

The README also tells you how to extend the set. If you need other tools, refer to the existing tools to add a CMake file, which is a short instruction and a fair one, because the per-tool build files are the pattern and copying one is the whole job.

Prebuilt binaries are built by GitHub Actions and published to the Releases page, so in practice you can either take the artefacts or build your own, and the artefacts are the same ones the CI produces from the same source.

## Four toolchains, and one of them is experimental

The toolchain table is the core of the project, and it is worth reading as a set of trade-offs rather than a list.

The ndk toolchain is the default and produces Android executables against bionic. The zig toolchain produces Linux executables with musl for the static ones and glibc for the shared ones, and the static ones also run on Android. The host toolchain uses the build machine's own compilers, $CC and $CXX, clang by default, and produces native executables. The custom option takes any CMake toolchain file, which is the escape hatch for cross gcc, clang, musl-cross and anything else.

The zig option is the interesting one and the README flags it honestly: it is experimental, the build system supports it, but some AOSP sources are only built for bionic or glibc upstream and may need extra patches for musl. That is a fair warning rather than a hedge, and it tells you that the zig path works for the standard tool set but that you may hit a source that assumes glibc.

The build arguments mirror this. NDK_VERSION defaults to r29 and ZIG_VERSION to 0.16.0, and you can set one to empty to skip it. The Dockerfile applies the same defaults as ARG NDK_VERSION=r29 and ARG ZIG_VERSION=0.16.0, and installs the NDK by downloading it from Google's repository and zig from ziglang.org, unzipping and untarring them into /opt.

One constraint in the Dockerfile is easy to miss and easy to hit. The NDK only provides linux-x86_64 binaries, so the image has to be built for linux/amd64, which is why every documented docker command carries the --platform linux/amd64 flag.

## Building with Docker, where the toolchain is already assembled

The Dockerfile provides a build environment with the NDK, zig and all the dependencies, and the project directory is mounted into the container, so the image holds toolchains rather than your source.

```bash
docker build --platform linux/amd64 -t android-sdk-tools .

# fetch the sources and build with the NDK
docker run --rm -it --platform linux/amd64 -u "$(id -u):$(id -g)" -v "$PWD:/work" android-sdk-tools \
    sh -c "python3 get_source.py && python3 build.py --arch aarch64"

# build with zig
docker run --rm -it --platform linux/amd64 -u "$(id -u):$(id -g)" -v "$PWD:/work" android-sdk-tools \
    python3 build.py --toolchain zig --arch aarch64
```

Two details in those invocations are deliberate. The --platform linux/amd64 flag is required because of the NDK binaries, and the -u "$(id -u):$(id -g)" flag makes the container write as your user, so the files in the mounted directory belong to you rather than to root.

The second command is worth reading closely, because it shows the two-phase shape of the whole build. python3 get_source.py fetches the AOSP sources and applies the patches, and then python3 build.py compiles and packages. Splitting the two means you can fetch once and rebuild many times, and the source tree is separate from the build directory.

The build.py invocation in the zig example is also shorter than the NDK one, because zig needs no NDK path. That is the practical argument for the zig toolchain beyond the linking: one less external dependency to install and keep current.

## Getting the sources, and the patches that only apply to some tags

get_source.py clones all the repositories listed in repository.json and applies the patches. The default tag is platform-tools-<PLATFORM_TOOLS_VERSION>, and the version itself comes from a header file, patches/misc/platform_tools_version.h.

```bash
python get_source.py

# specific branches or tags
# see available tags https://android.googlesource.com/platform/frameworks/base/+refs
python get_source.py --tags platform-tools-36.0.0

# other options: --jobs (parallel clones), --retries, --skip-patch
python get_source.py --help
```

The tag name in the release and the version in the header are the same thing, which is a nice property: the release asset is named after the source it was built from. The download instructions say to take android-sdk-tools-static-<arch>.zip from the Releases page, and the release tag is the PLATFORM_TOOLS_VERSION, for example 36.0.0.

The patch behaviour is deliberately forgiving. The source patches only apply to specific tags, and a patch which cannot be applied to the selected tag is skipped with a message. That is the right failure mode for a project that tracks an upstream whose tags move, since a hard failure on an unapplyable patch would make the build unusable on any tag the maintainer had not caught up with.

For the multiple repositories involved, --jobs parallelises the clones and --retries handles transient network failures, and --skip-patch lets you work with unmodified sources if you need to.

## build.py, and the CMake options underneath it

build.py builds the host protoc, which is used to generate the sources of aapt2 and adb, then compiles the tools and packages them as android-sdk-tools-<static|shared>-<arch>.zip. Building protoc first is a dependency you would otherwise hit as a confusing compile error, so the script handling it is a kindness.

```bash
# NDK (default toolchain), static link (default)
python build.py --ndk=/path/to/android-ndk-xxx --arch=aarch64

# zig, static musl executables
python build.py --toolchain=zig --arch=aarch64

# dynamic link
python build.py --ndk=/path/to/android-ndk-xxx --arch=aarch64 --link=shared

# the host compilers
python build.py --toolchain=host --arch=x86_64 --cc=clang --cxx=clang++

# any other toolchain with a CMake toolchain file
python build.py --toolchain=custom --toolchain-file=/path/to/toolchain.cmake --arch=aarch64

# use an existing host protoc
python build.py --ndk=/path/to/android-ndk-xxx --arch=aarch64 --protoc=/path/to/protoc

# build specified targets, recommended to locate errors
python build.py --ndk=/path/to/android-ndk-xxx --arch=aarch64 --target aapt2 adb

# extra cmake arguments after --
python build.py --toolchain=zig --arch=x86_64 -- -DSDK_STRIP=OFF

# all options
python build.py --help
```

The --target option is the debugging lever. Building a single target such as aapt2 adb is recommended to locate errors, because a full AOSP build has enough output to hide the actual failure. And the trailing -- separator passes extra CMake arguments through, which is how you override a default without editing anything.

The NDK path can also be set through ANDROID_NDK_HOME or ANDROID_NDK_ROOT, and the build directory is build/<toolchain>-<link>-<arch> with the executables in its bin directory. That naming scheme means each combination of toolchain, link mode and architecture gets its own tree, so switching between static and shared does not invalidate the other build.

Using CMake directly is supported too, with a small option set: SDK_STATIC defaults to ON for fully static executables, SDK_STRIP defaults to ON to strip at link time in Release, PROTOC_PATH points at a host protoc, and ZIG_TARGET and ZIG_CPU set the zig target and an optional -mcpu value such as cortex_a53.

## CI, the layout, and where the project stands

The GitHub Actions workflow builds all the architectures on every push with the NDK, and zig can be selected when running the workflow manually. The release mechanics are documented precisely enough to be worth reading, because they explain how the artefacts relate to the source.

The tag is PLATFORM_TOOLS_VERSION, for example 36.0.0, and the title is the v-prefixed form, v36.0.0. The release notes are the latest commit message, replaced rather than appended to. When PLATFORM_TOOLS_VERSION does not change, no new release is created: the assets of the existing release are overwritten and the tag is moved to the latest commit. The assets are split by architecture into android-sdk-tools-static-aarch64.zip, android-sdk-tools-static-arm.zip, android-sdk-tools-static-x86_64.zip and the rest of the set.

That tag-moves policy is a real design choice. It means there is exactly one release per source version, always pointing at the newest commit for that version, rather than a growing list of dated builds. The cost is that a release URL is not immutable in the way a content-addressed artefact would be.

The project layout explains the structure. There is a top-level CMakeLists.txt for the project and third-party libraries, a cmake/ directory with platform.cmake for static linking, stripping and system libraries, a bundled static zlib with a FindZLIB.cmake module that redirects find_package(ZLIB) to it, and the zig toolchain file. The lib/ directory holds AOSP libraries such as libbase, libutils and liblog, and there are build-tools/, platform-tools/ and others/ directories, a patches/ directory for source patches and generated files, repository.json listing the source repositories, get_source.py and build.py, the Dockerfile and the .github/workflows/ directory.

The release history is slower than the commit activity. The tagged versions are 35.0.2 from 2024-08-20, 34.0.3 from 2023-09-15 and 33.0.3 from 2022-10-18, while the last push was on 2026-10-15. So the source moves faster than the published tags, which is consistent with a project that tracks an upstream whose tags arrive when Google ships them.

For a first-time user, the Downloads section is the place to start, and the repository is the place to come when you need a tool the official packages do not offer, or a static build for a platform they do not support.

## Conclusion

Adopt android-sdk-tools if you need adb, fastboot, aapt2 or the rest of the Android platform and build tools on a system where Google's prebuilt binaries do not work, such as Termux, or if you need a fully static build with no runtime dependencies. Do not adopt it if the official prebuilt packages run on your platform, because building from AOSP source is a heavy operation with a patch set that tracks upstream tags and only applies to specific ones. Before you commit, check the PLATFORM_TOOLS_VERSION header and the corresponding release tag so that your source and your binaries match, download the prebuilt static archive for your architecture if it exists, and use the --target option when a full build fails so you can locate the actual error in a single tool.

## FAQ

### What does android-sdk-tools build?

It builds the Android platform-tools and build-tools from AOSP source with CMake. The build-tools directory produces aapt, aapt2, aidl, zipalign, dexdump and split-select, the platform-tools directory produces adb, fastboot, sqlite3, etc1tool, hprof-conv, e2fsdroid, sload_f2fs, mke2fs, make_f2fs and make_f2fs_casefold, and others/ produces veridex.

### Which toolchains and architectures does android-sdk-tools support?

The toolchains are the NDK by default, zig for musl static or glibc shared Linux executables, the host compilers through $CC and $CXX, or a custom CMake toolchain file. The architectures are aarch64, arm, x86_64 and i686, and the Android abi names arm64-v8a, armeabi-v7a and x86 are accepted for --arch as well.

### How do I build android-sdk-tools with Docker?

Build the image with docker build --platform linux/amd64 -t android-sdk-tools ., then run it with your project mounted, running python3 get_source.py to fetch and patch the AOSP sources and python3 build.py --arch aarch64 to compile and package. The Dockerfile supplies the NDK, zig and all the build dependencies.

### How do I pick a different source version when building?

get_source.py clones the repositories listed in repository.json and applies the patches, using a default tag of platform-tools-<PLATFORM_TOOLS_VERSION>. You can pass a specific tag with --tags, and other options include --jobs for parallel clones, --retries and --skip-patch, and a patch that cannot be applied to the selected tag is skipped with a message.

### What CMake options can I set when using CMake directly?

SDK_STATIC defaults to ON for fully static executables, SDK_STRIP defaults to ON to strip at link time in Release, PROTOC_PATH points at a host protoc, and ZIG_TARGET and ZIG_CPU set the zig target and an optional -mcpu value such as cortex_a53. The build directory is build/<toolchain>-<link>-<arch> with the executables in its bin directory.

## Sources

- [Issues](https://github.com/lzhiyong/android-sdk-tools/issues)
- [License: Apache-2.0](https://github.com/lzhiyong/android-sdk-tools/blob/master/LICENSE)
- [lzhiyong/android-sdk-tools on GitHub](https://github.com/lzhiyong/android-sdk-tools)
- [README](https://github.com/lzhiyong/android-sdk-tools/blob/master/README.md)
- [Releases](https://github.com/lzhiyong/android-sdk-tools/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lzhiyong-android-sdk-tools
