Building and Integrating ZXC
Table of Contents
Package managers are covered in the README. This document is for the cases that need more room: verifying a release archive, vendoring zxc into another build, and building it from source. Vendoring into a libc-less target (a kernel module, a firmware) has its own tree: contrib/linux-kernel.
Release archives#
Pick the archive for your platform on the Releases page
— zxc-<version>-linux-{x86_64,arm64}.tar.gz, zxc-<version>-macos-arm64.tar.gz, or zxc-<version>-windows-{x86_64,arm64}.zip.
x86_64 builds dispatch AVX2/AVX-512 at runtime; ARM64 builds carry NEON. zxc-<version>.tar.gz is
the canonical source, reproducible with
git archive --format=tar --prefix=zxc-<version>/ v<version> | gzip -n -9; zxc-<version>.tar.zxc
is that same tar compressed with zxc -7, readable only by a zxc whose format version matches, so
keep the .tar.gz for archival.
Verify before extracting — the manifest is signed, so check it first:
minisign -Vm checksums.sha256 -P 'RWQV0cpiyJYPkxF5iIysJzKNtzcGphqeyyFkiFErLMo5UZkWisGBxkNB'
sha256sum -c checksums.sha256 --ignore-missing
# macOS, replacing ARCHIVE with the downloaded archive's file name:
# grep -F 'ARCHIVE' checksums.sha256 | shasum -a 256 -c
gh attestation verify zxc-<version>-linux-x86_64.tar.gz --repo hellobertrand/zxc
tar -xzf zxc-<version>-linux-x86_64.tar.gz
sudo cp -r zxc-<version>-linux-x86_64/* /usr/local/
Linux and macOS archives hold bin/zxc, include/, lib/libzxc.a, lib/pkgconfig/libzxc.pc and
lib/cmake/zxc/zxcConfig.cmake. Windows ZIP archives are built with MinGW-w64 on the UCRT, which Windows 10 and later include
(GCC on x86_64, Clang on ARM64), and need no other runtime: bin/zxc.exe; bin/libzxc.dll with
its MinGW import library lib/libzxc.dll.a; lib/libzxc.def, the DLL's export list; the static
lib/libzxc.a for UCRT MinGW toolchains (MSYS2 UCRT64 or CLANG64 on x86_64, CLANGARM64 on ARM64),
with lib/pkgconfig/libzxc.pc and lib/cmake/zxc/zxcConfig.cmake, which also target MinGW; and
include/. As with every MinGW library, -lzxc links the DLL and -static the static library.
MSVC users build their own import library (lib /def:lib\libzxc.def /out:zxc.lib /machine:x64, or
arm64), define ZXC_DLL_IMPORT, and build with the release shared UCRT (/MD, not /MDd) to
pass FILE*s to the DLL; for a static MSVC library, build zxc from source (vcpkg, Conan, CMake).
Release tags are PGP-signed. Check the key's fingerprint against the one published in
SECURITY.md before importing it — otherwise the import is circular, and
git verify-tag would validate a signature made by whatever key the download happened to supply
(it also exits 0 for a key you have never certified):
curl -sS https://github.com/hellobertrand.gpg -o zxc-maintainer.gpg
gpg --show-keys --with-fingerprint zxc-maintainer.gpg # compare with .github/SECURITY.md
gpg --import zxc-maintainer.gpg # only once it matches
git clone https://github.com/hellobertrand/zxc.git # the archives carry no tags
cd zxc
git verify-tag v<version>
Key fingerprint and vulnerability reporting: SECURITY.md.
Building from source (CMake)#
Requirements: CMake 3.21+, a C17 compiler (Clang, GCC or MSVC). Built by
another build system, the sources need C11 or later (MSVC: /std:c11).
git clone https://github.com/hellobertrand/zxc.git
cd zxc
Single-config generators (Unix Makefiles, Ninja)#
The default on Linux and macOS. The build type is fixed at configure time.
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
# Run tests. CMake 3.20+ can use: ctest --test-dir build --output-on-failure
cd build && ctest --output-on-failure && cd ..
# CLI usage
./build/zxc --help
# Install library, headers, pkg-config and CMake package files.
# CMake 3.15+ can use: sudo cmake --install build
sudo cmake --build build --target install
Multi-config generators (Visual Studio, Xcode, Ninja Multi-Config)#
Here the build type is chosen at build time, so CMAKE_BUILD_TYPE is ignored at configure time
and --config is required at build, test and install time. Artifacts land in a per-configuration
subdirectory: the CLI is build/Release/zxc, not build/zxc.
cmake -B build
cmake --build build --config Release --parallel
cd build
ctest -C Release --output-on-failure
cd ..
cmake --build build --config Release --target install
Installing into a system prefix needs sudo on Unix or an elevated shell on Windows. Pass
-DCMAKE_INSTALL_PREFIX=<dir> at configure time to install somewhere writable instead.
CMake options#
| Option | Default (standalone) | Default (vendored) | Description |
|---|---|---|---|
BUILD_SHARED_LIBS |
OFF | OFF | Build shared libraries instead of static (libzxc.so, libzxc.dylib, libzxc.dll) |
ZXC_NATIVE_ARCH |
ON | OFF | Enable -march=native for maximum performance |
ZXC_ENABLE_LTO |
OFF | OFF | Enable Link-Time Optimization (LTO) |
ZXC_PGO_MODE |
OFF | OFF | Profile-Guided Optimization mode (OFF, GENERATE, USE) |
ZXC_BUILD_CLI |
ON | OFF | Build command-line interface |
ZXC_BUILD_TESTS |
ON | OFF | Build unit tests |
ZXC_INSTALL |
ON | OFF | Generate install rules (headers, pkg-config, CMake package) |
ZXC_ENABLE_COVERAGE |
OFF | OFF | Enable code coverage generation (disables LTO/PGO) |
ZXC_DISABLE_SIMD |
OFF | OFF | Disable hand-written SIMD paths (AVX2/AVX512/NEON) |
ZXC_USE_SYSTEM_RAPIDHASH |
OFF | OFF | Use a system-installed rapidhash.h instead of the vendored copy |
RAPIDHASH_INCLUDE_DIR |
(found) | (found) | Directory holding a system rapidhash.h, when find_path cannot locate it |
"Vendored" is a build where zxc is not the top-level project (add_subdirectory(),
FetchContent): the embedding project then keeps control of its own compiler flags,
test registration and install set.
# Build shared library
cmake -B build -DBUILD_SHARED_LIBS=ON
# Portable build (without -march=native)
cmake -B build -DZXC_NATIVE_ARCH=OFF
# Library only (no CLI, no tests)
cmake -B build -DZXC_BUILD_CLI=OFF -DZXC_BUILD_TESTS=OFF
# Code coverage build
cmake -B build -DZXC_ENABLE_COVERAGE=ON
# Disable explicit SIMD code paths (compiler auto-vectorisation is unaffected)
cmake -B build -DZXC_DISABLE_SIMD=ON
# Warnings as errors, as CI builds (CMake 3.24+)
cmake -B build -DCMAKE_COMPILE_WARNING_AS_ERROR=ON
Profile-Guided Optimization (PGO — Clang and GCC, single-config generators)#
PGO uses runtime profiling data to optimize branch layout, inlining decisions, and code placement.
Not available with MSVC.
ZXC_PGO_MODEis accepted there but emits no instrumentation and no profile-use flags:cmake/zxcCompilerFlags.cmakegates the whole PGO block onNOT MSVC, and so does the missing-profile check.GENERATEandUSEtherefore produce an ordinary build, without a warning. The steps below assume Clang or GCC.
Written for a single-config generator (Ninja, Unix Makefiles). Clang and GCC also drive Xcode and Ninja Multi-Config, which ignore
CMAKE_BUILD_TYPE: there, add--config Releaseto everycmake --build, and run the workload from the per-configuration directory —build/Release/zxc_testandbuild/Release/zxc. The profile directory isbuild/pgo/either way, so step 3 is unchanged.
Step 1 - Build with instrumentation:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DZXC_PGO_MODE=GENERATE
cmake --build build --parallel
Step 2 - Run a representative workload to collect profile data:
# Run the test suite (exercises all block types and compression levels)
./build/zxc_test
# Or compress/decompress representative data
./build/zxc -b your_data_file
Step 3 - (Clang only) Merge raw profiles:
# Clang generates .profraw files that must be merged before use
llvm-profdata merge -output=build/pgo/default.profdata build/pgo/*.profraw
GCC uses a directory-based format and does not require this step.
Step 4 - Rebuild with profile data:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DZXC_PGO_MODE=USE
cmake --build build --parallel
CMake subproject (vendored)#
zxc can be vendored directly into a CMake build, either as a git submodule with
add_subdirectory() or through FetchContent:
include(FetchContent)
FetchContent_Declare(zxc
GIT_REPOSITORY https://github.com/hellobertrand/zxc.git
GIT_TAG v0.15.0
)
FetchContent_MakeAvailable(zxc)
target_link_libraries(myapp PRIVATE zxc::zxc_lib)
zxc::zxc_lib is the same target name the installed package exports, so
switching between a vendored copy and find_package(zxc) needs no other
change.
When zxc is not the top-level project it builds the library only: the CLI, the
tests, -march=native and the install rules all default to off, so the
embedding project keeps full control of its own CTest registration and install
set. Any of them can still be turned back on explicitly (-DZXC_BUILD_CLI=ON,
-DZXC_NATIVE_ARCH=ON, -DZXC_INSTALL=ON, ...). -march=native is also
ignored whenever CMake is cross-compiling, since it would encode the build
host's ISA.
Compiler flags follow the same rule. Vendored, zxc adds nothing to what it
inherits from the parent: the optimisation level comes from the build type, and
the warning level (-Wall -Wextra, /W3) and code generation policy
(-fomit-frame-pointer, -fstrict-aliasing, -ffunction-sections,
-fdata-sections and the matching dead-strip link options) are the embedding
project's to set. An embedder that builds with frame pointers for its profiler,
its own aliasing rules or a quiet build log keeps them. A configure-time warning
fires if neither a build type nor an optimisation flag is set, since zxc would
then be built unoptimised.
Third-party code is vendored, never probed: rapidhash.h comes from the copy in
the tree unless -DZXC_USE_SYSTEM_RAPIDHASH=ON asks for a system one, so a
build cannot silently pick up a header from the host. Packagers who strip the
vendored copy must pass that option: either header is resolved at configure
time, so a missing one fails there rather than once per translation unit.
Meson subproject (or WrapDB)#
zxc ships a native meson.build, so any Meson project can pull it in as a
subproject or via WrapDB.
1. Create subprojects/zxc.wrap:
[wrap-git]
url = https://github.com/hellobertrand/zxc.git
revision = head
depth = 1
[provide]
libzxc = libzxc_dep
2. Use the dependency in your meson.build:
project('my_project', 'c', default_options : ['c_std=c17'])
zxc_dep = dependency('libzxc', fallback : ['zxc', 'libzxc_dep'])
executable('my_app', 'main.c', dependencies : zxc_dep)
3. Build and run:
meson setup build
meson compile -C build
./build/my_app
When consumed as a subproject, only the library is built (CLI and tests are skipped automatically).
Meson options#
| Option | Default | Description |
|---|---|---|
build_cli |
false |
Build the command-line interface |
use_system_rapidhash |
false |
Use a system-installed rapidhash.h instead of the vendored copy |
use_system_rapidhash mirrors ZXC_USE_SYSTEM_RAPIDHASH in the CMake build,
with the same setup-time check. It has no equivalent of RAPIDHASH_INCLUDE_DIR:
Meson probes the compiler's default search path, so a header installed elsewhere
is reached with -Dc_args=-I<dir>.