xrepo — Cross-Platform C++ Package Manager
xrepo package manager — searching and installing packages, CMake/Meson integration, private repositories, and cross-compilation.
TL;DR
xrepo ships with xmake but works as a standalone package manager for any build system. It indexes 5000+ C++ packages, runs identically on Linux, macOS, and Windows, and handles cross-compilation to Android, iOS, and bare-metal targets without requiring platform-specific package managers. You do not need to use xmake as your build system to benefit from xrepo — CMake and Meson projects can consume xrepo packages via generated flags or environment injection.
# Install a package, then ask for its CMake flags
xrepo install fmt
xrepo fetch --cmake fmt
# -DCMAKE_PREFIX_PATH=... -Dfmt_DIR=...
# Or just drop into a shell where everything is on PATH / in CMAKE_PREFIX_PATH
xrepo env cmake -B build -S .Key characteristics:
- Single binary — no Python runtime, no Ruby, no .NET; xmake/xrepo is self-contained
- Per-project installs by default — packages land in
~/.xmake/packages, keyed by version and configuration - Binary caching — previously built packages are reused across projects automatically
- Build-system neutral —
xrepo fetchoutputs flags for CMake, pkg-config, and raw compiler invocations
Installation
xrepo is bundled with xmake. Installing xmake gives you both commands.
Linux and macOS
curl -fsSL https://xmake.io/shget.text | bash
# Or with wget:
wget https://xmake.io/shget.text -O - | bashThe installer drops the binary into ~/.local/bin. Restart your shell or source ~/.bashrc (or ~/.zshrc) to pick it up.
Windows — winget
winget install xmake-io.xmakeWindows — Scoop
scoop install xmakeBoth options add xmake and xrepo to PATH automatically.
Verify the installation
xrepo --version
# xrepo v2.9.x, A cross-platform C/C++ package managerxrepo and xmake share the same version number — they ship as one release.
Searching and Installing Packages
Finding a package takes one command. xrepo searches the official registry (xmake-repo) by name and prints available versions.
xrepo search fmt
# Results from the official xmake-repo registry:
# fmt - A modern formatting library
# fmtlog - fmtlog is a performant fmtlib-style logging library...Install the latest compatible version:
xrepo install fmtPin to a specific version using a quoted version constraint:
xrepo install "fmt 10.x"
xrepo install "fmt 10.2.1"
xrepo install "openssl >=3.0"Build in release mode (the default for most packages, but explicit is safer in CI):
xrepo install --mode=release fmt
xrepo install --mode=debug fmtYou can have both modes installed simultaneously — xrepo keys the cache by build configuration.
List installed packages
xrepo list
# fmt 10.2.1 release linux x86_64
# boost 1.83.0 release linux x86_64Remove a package
xrepo remove fmt
xrepo remove "fmt 10.2.1" # remove a specific versionUpdate all installed packages to their latest allowed versions
xrepo updateUsing with CMake
xrepo does not require you to rewrite your CMakeLists.txt. The fetch subcommand prints the CMake variables needed to locate installed packages, and xrepo env injects those paths into the environment before invoking any command you pass.
Option 1 — fetch flags and pass them directly
# Install first
xrepo install fmt nlohmann_json openssl
# Ask for CMake-compatible flags
xrepo fetch --cmake fmt
# Outputs something like:
# -DCMAKE_PREFIX_PATH=/home/user/.xmake/packages/f/fmt/10.2.1/... -Dfmt_DIR=...Pass those flags to CMake:
cmake -B build $(xrepo fetch --cmake fmt) $(xrepo fetch --cmake nlohmann_json)
cmake --build buildOption 2 — xrepo env (recommended for interactive use)
xrepo env cmake -B build -S .
xrepo env cmake --build buildxrepo env sets CMAKE_PREFIX_PATH, PKG_CONFIG_PATH, LD_LIBRARY_PATH, and compiler hints so that find_package() in CMakeLists.txt resolves installed packages without extra flags.
Option 3 — export and source (useful for scripts or IDEs)
xrepo env --export > env.sh
source env.sh
cmake -B build -S .The exported file is a plain shell script that sets the environment variables xrepo would inject — portable to any script or IDE that can source a shell file.
Full CMake workflow
# 1. Install dependencies
xrepo install fmt nlohmann_json
# 2. Configure
xrepo env cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
# 3. Build
cmake --build build --parallel $(nproc)Your CMakeLists.txt stays standard:
cmake_minimum_required(VERSION 3.25)
project(myapp)
find_package(fmt REQUIRED)
find_package(nlohmann_json REQUIRED)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt nlohmann_json::nlohmann_json)No toolchain file, no generator expressions specific to xrepo — the project remains portable to vcpkg or Conan without modification.
Using with Meson
Meson's pkg-config integration is the cleanest path for xrepo packages. Most packages installed by xrepo generate .pc files; export the path and Meson's dependency resolution picks them up transparently.
# Install a package
xrepo install fmt
# Get the pkg-config output path
xrepo fetch --pkg-config fmt
# /home/user/.xmake/packages/f/fmt/10.2.1/.../lib/pkgconfigPass the path to Meson:
PKG_CONFIG_PATH=$(xrepo fetch --pkg-config fmt) meson setup build
ninja -C buildFor multiple packages, accumulate the paths:
export PKG_CONFIG_PATH=$(xrepo fetch --pkg-config fmt):$(xrepo fetch --pkg-config zlib)
meson setup buildThe xrepo env shortcut works here too:
xrepo env meson setup build
xrepo env ninja -C buildxrepo env sets PKG_CONFIG_PATH alongside CMAKE_PREFIX_PATH, so the same invocation style works regardless of whether your project uses CMake or Meson.
Using with xmake
When xmake is your build system, xrepo integration is native — no fetch step, no env injection. Declare packages in xmake.lua and they are downloaded, built, and linked automatically.
-- xmake.lua
add_rules("mode.release", "mode.debug")
add_requires("fmt 10.x", {configs = {header_only = false}})
add_requires("nlohmann_json", {alias = "json"})
add_requires("openssl >=3.0")
target("myapp")
set_kind("binary")
add_files("src/*.cpp")
add_packages("fmt", "json", "openssl")Build with dependency resolution in one step:
xmake # downloads missing packages, then builds
xmake -m releaseThe difference from standalone xrepo install is that xmake reads package requirements from xmake.lua automatically — you never call xrepo install manually in an xmake project. The xrepo cache is shared, though, so packages installed for one project are reused by all others.
When you run xmake for the first time in a project, it:
- Reads
add_requires()declarations - Checks
~/.xmake/packagesfor cached builds matching the version and configuration - Downloads and builds anything missing
- Links the packages into the declared targets
There is no lock file separate from xmake.lua — the version constraint in add_requires() is the contract.
Package Versions and Options
xrepo's version syntax handles both exact pins and range constraints. You can also enable or disable package features (called "configs") at install time.
Version pinning and ranges
xrepo install "boost 1.83.0" # exact version
xrepo install "boost >=1.80.0" # minimum version
xrepo install "boost >=1.80,<1.85" # version range
xrepo install "openssl >=3.0"Selecting package components (features)
Many packages expose optional components as build-time configs. Pass them with --configs:
# Build fmt as a shared library instead of static
xrepo install --configs="shared=true" fmt
# Boost with selected components only
xrepo install --configs="filesystem=true,system=true,thread=false" boostIn xmake.lua, the same option appears inside the add_requires() call:
add_requires("boost", {configs = {filesystem = true, system = true, thread = false}})
add_requires("fmt", {configs = {shared = true}})Debug vs release installs
xrepo install --mode=release fmt # optimised, stripped
xrepo install --mode=debug fmt # symbols included, assertions enabledBoth can coexist in the cache. xrepo fetch accepts the same --mode flag to return paths for the correct variant.
Checking what configs a package supports
xrepo info fmt # lists available config options, URL, license, deps
xrepo info boost # shows components that can be toggledCross-Compilation
xrepo cross-compilation is first-class, not an afterthought. The --plat and --arch flags tell xrepo to build the package for a different target; the host toolchain is picked up automatically or specified via --sdk.
Generic sysroot-based cross-compilation
xrepo install \
--plat=cross \
--arch=aarch64 \
--sdk=/path/to/aarch64-sysroot \
fmt zlibThe --sdk path should be the root of your cross toolchain (the directory containing bin/aarch64-linux-gnu-gcc, etc.).
Android NDK
xrepo install \
--plat=android \
--arch=arm64-v8a \
--ndk=/path/to/android-ndk-r26 \
fmt opensslSupported Android architectures: arm64-v8a, armeabi-v7a, x86, x86_64.
# Fetch CMake flags for the cross-built package
xrepo fetch --cmake --plat=android --arch=arm64-v8a fmtiOS
xrepo install --plat=iphoneos --arch=arm64 fmt
xrepo install --plat=iphonesimulator --arch=x86_64 fmtRequires Xcode and the iOS SDK to be installed on macOS.
WebAssembly (Emscripten)
xrepo install --plat=wasm fmtxrepo detects the active Emscripten environment (emcc on PATH) and uses it automatically.
Listing cross-built packages
xrepo list --plat=android --arch=arm64-v8aEach platform/arch combination is stored separately in the cache so host and cross builds never collide.
Private and Custom Repositories
xrepo's package registry is just a Git repository, and you can add your own. Private package definitions live in the same package() DSL as the official registry — once registered, xrepo install treats them identically to public packages.
Adding a remote repository
xrepo add-repo myrepo https://github.com/myorg/xmake-repo.gitxrepo clones the repo and searches it alongside the official registry. Package names from your repo take priority over the official one if there is a conflict.
Adding a local directory repository
xrepo add-repo localrepo /path/to/local/xmake-repoUseful during development of new package definitions before pushing them upstream.
Listing registered repositories
xrepo repo list
# official https://github.com/xmake-io/xmake-repo.git
# myrepo https://github.com/myorg/xmake-repo.gitPackage definition format
Package definitions live in packages/<initial-letter>/<package-name>/xmake.lua inside your repo. The structure mirrors the official registry:
-- packages/f/foobar/xmake.lua
package("foobar")
set_homepage("https://github.com/myorg/foobar")
set_description("An internal C++ utility library.")
set_license("MIT")
add_urls("https://github.com/myorg/foobar/archive/refs/tags/$(version).tar.gz")
add_versions("1.2.0", "sha256:abcdef1234567890...")
add_versions("1.3.0", "sha256:fedcba0987654321...")
add_deps("fmt", "zlib") -- declare dependencies
on_install(function (package)
local configs = {}
table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release"))
table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF"))
import("package.tools.cmake").install(package, configs)
end)
on_test(function (package)
assert(package:has_cfuncs("foobar_init", {includes = "foobar/foobar.h"}))
end)
package_end()Key sections:
add_urls— download URL(s);$(version)is interpolated fromadd_versionsadd_versions— version string and SHA-256 checksum of the archiveadd_deps— other xrepo packages this one depends onon_install— Lua function that builds and installs; usepackage.tools.cmake,package.tools.meson, orpackage.tools.autoconfhelperson_test— optional smoke test run after install
CI Integration
xrepo's package cache lives in ~/.xmake/packages and is trivially cacheable in CI. Caching this directory between runs makes repeated CI builds nearly as fast as local builds.
GitHub Actions — full workflow
name: C++ CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install xmake (includes xrepo)
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: latest
- name: Cache xrepo packages
uses: actions/cache@v4
with:
path: ~/.xmake/packages
key: xrepo-${{ runner.os }}-${{ hashFiles('xmake.lua') }}
restore-keys: |
xrepo-${{ runner.os }}-
- name: Install dependencies
run: xrepo install fmt nlohmann_json openssl
- name: Configure
run: xrepo env cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build build --parallel
- name: Test
run: ctest --test-dir build --output-on-failureThe xmake-io/github-action-setup-xmake action handles PATH setup and platform quirks. The cache key includes the hash of xmake.lua so a changed dependency list invalidates the cache automatically.
Comparing CI overhead to other package managers
xrepo packages are built from source on a cache miss, similar to Conan with --build=missing. On a cache hit, install time is under a second. vcpkg with binary caching via GitHub Packages has comparable hit-time performance but requires more setup. The main xrepo advantage in CI is the single binary dependency — no Python, no pip, no environment setup beyond running the installer script.
Docker-based CI (no cache layer needed)
FROM tboox/xmake:latest AS deps
WORKDIR /build
RUN xrepo install fmt nlohmann_json openssl
FROM deps AS build
COPY . /src
WORKDIR /src
RUN xrepo env cmake -B build -S . -DCMAKE_BUILD_TYPE=Release \
&& cmake --build build --parallelSplitting into two stages lets Docker cache the dependency layer independently of source changes.
xrepo vs vcpkg vs Conan vs CPM
Choosing a package manager depends on your constraints. The table below reflects the state of each tool as of mid-2026.
| Feature | xrepo | vcpkg | Conan 2 | CPM.cmake |
|---|---|---|---|---|
| Package count | 5000+ | 2200+ | 1700+ (CCI) | any CMake FetchContent source |
| Binary caching | Yes (local) | Yes (local + GitHub Packages + Azure) | Yes (Conan Center + custom) | No |
| Cross-compilation | First-class (--plat, --arch, --ndk) | Triplets (good, but fiddly) | Profiles (powerful, complex) | No (inherits CMake toolchain) |
| CMake integration | Via xrepo env or xrepo fetch --cmake | Toolchain file, seamless | CMakeDeps generator | Native (IS cmake) |
| Meson integration | Via xrepo env or --pkg-config | Third-party scripts | pkg-config generator | No |
| Build-system agnostic | Yes | Partial (CMake-first) | Yes | No (CMake only) |
| Runtime dependency | None (self-contained binary) | Git + compiler | Python 3.8+ | CMake 3.14+ |
| Windows support | Excellent | Excellent (Microsoft-maintained) | Good | Good |
| Offline mode | Yes (after first install) | Yes (after bootstrap) | Yes (with cache) | No (fetches at configure time) |
| Private repos | Yes (xrepo add-repo) | Overlays + registries | Custom remotes | Any URL/Git ref |
| Learning curve | Low (one CLI) | Low (one CLI) | Medium (conanfile.py) | Very low |
When to pick xrepo:
- You are already using xmake or are open to it
- You need Android/iOS/WASM cross-compilation without a complex toolchain setup
- You want a single binary that works identically on all three platforms with no runtime deps
- You value a clean CLI where
xrepo installjust works
When to pick vcpkg:
- Your team is on Windows and Visual Studio integration matters
- You need the largest well-maintained package count
- Azure DevOps binary caching is already in your pipeline
When to pick Conan:
- You need precise binary compatibility management across many compiler/OS matrix combinations
- Your project has complex
conanfile.pylogic that encodes build variants - You are in a large organisation with a private Artifactory server
When to pick CPM:
- Pure CMake projects, zero extra tooling, packages available as CMake targets
- Acceptable to build everything from source every time (or rely on FetchContent caching)
See Also
- xmake — the build system xrepo ships with; native package integration via
add_requires() - vcpkg — Microsoft's package manager; best Windows + CMake story
- Conan — decentralised, Python-based, strongest binary compatibility model
- CPM — CMake-native package management via FetchContent
- CMake — the build system most packages target; works with all four package managers above