This document describes how to build and package TundraDB for macOS distribution.
The process produces a self-contained .tar.gz archive containing tundra_shell
and all its dynamic library dependencies — no Homebrew or other installs required
on the target machine.
TundraDB-1.0.0-macOS-arm64.tar.gz
└── TundraDB-1.0.0-macOS/
├── tundra_shell ← launcher script (run this)
├── bin/
│ └── tundra_shell ← binary (library paths rewritten)
├── libs/
│ └── *.dylib ← all bundled dependencies
└── VERSION
Install these on the build machine (the machine where you create the release):
# Build tools
brew install cmake
# Library bundler — copies dylibs and rewrites load paths
brew install dylibbundlerAll TundraDB dependencies (Arrow, Parquet, TBB, ANTLR, LLVM, etc.) must already be installed. If you can build TundraDB from source, you're good.
./scripts/create_macos_bundle.shThis will:
- Configure a Release build in
build_release/ - Build
tundra_shell - Copy the binary to
dist/TundraDB-<version>-macOS/bin/ - Run
dylibbundlerto collect all.dylibdependencies intolibs/and rewrite the binary's load paths to@executable_path/../libs/ - Create a launcher script
- Verify all references are resolved
- Create
dist/TundraDB-<version>-macOS-<arch>.tar.gz
| Flag | Effect |
|---|---|
--skip-build |
Skip cmake configure/build, reuse existing |
# Full build + package
./scripts/create_macos_bundle.sh
# Just re-package (binary already built in build_release/)
./scripts/create_macos_bundle.sh --skip-buildIf you prefer to run the steps individually:
cmake -B build_release -S . \
-DCMAKE_BUILD_TYPE=Release \
-DTUNDRADB_BUILD_TESTS=OFF \
-DTUNDRADB_BUILD_BENCHMARKS=OFFcmake --build build_release -j$(sysctl -n hw.ncpu)mkdir -p dist/TundraDB-1.0.0-macOS/bin
mkdir -p dist/TundraDB-1.0.0-macOS/libs
cp build_release/tundra_shell dist/TundraDB-1.0.0-macOS/bin/dylibbundler -od -b \
-x dist/TundraDB-1.0.0-macOS/bin/tundra_shell \
-d dist/TundraDB-1.0.0-macOS/libs/ \
-p @executable_path/../libs/ \
-s /usr/local/lib \
-s /opt/homebrew/lib \
-s /opt/homebrew/opt/llvm/libWhat this does:
-od— overwrite existing files in the destination-b— bundle (copy) libraries-x— the executable to process-d— where to copy the.dylibfiles-p— prefix to rewrite into the binary (@executable_path/../libs/)-s— extra directories to search for@rpathlibraries
If dylibbundler prompts for a library path, it means an @rpath reference
couldn't be found in the search paths. Add the missing directory with another
-s /path/to/dir flag.
# Should show only /usr/lib, /System, and @executable_path references
otool -L dist/TundraDB-1.0.0-macOS/bin/tundra_shell
# Smoke test
dist/TundraDB-1.0.0-macOS/bin/tundra_shell --helpcd dist
tar -czf TundraDB-1.0.0-macOS-arm64.tar.gz TundraDB-1.0.0-macOSmacOS binaries reference their dynamic libraries by path. A development build
points to absolute Homebrew paths like /opt/homebrew/lib/libarrow.dylib.
This won't work on a machine without Homebrew.
dylibbundler does two things:
- Copies every non-system
.dylib(and their transitive dependencies) into the bundle'slibs/directory. - Rewrites every library reference in the binary (using
install_name_tool) from absolute paths to@executable_path/../libs/<libname>.
This makes the binary fully self-contained. At runtime, macOS resolves
@executable_path to the directory containing the binary (bin/), then
looks for libs in ../libs/ relative to that.
The binary expects libs at ../libs/ relative to itself, so the structure
must be:
<anything>/
├── bin/
│ └── tundra_shell ← binary lives here
└── libs/
└── *.dylib ← @executable_path/../libs/ resolves here
| Directory | Purpose | In .gitignore |
|---|---|---|
build_release/ |
CMake build artifacts | ✅ Yes |
dist/ |
Final distributable packages | ✅ Yes |
build/ |
Development (Debug) build | ✅ Yes |
build_release/ contains CMake cache, object files, and intermediate build
artifacts — these are not distributable. The clean, distributable output
goes into dist/.
/!\ WARNING : can't get path for '@rpath/libfoo.dylib'
Please specify the directory where this library is located:
Find the library and add its directory as a search path:
find /opt/homebrew /usr/local -name "libfoo*" -type f 2>/dev/null
# Then re-run with: -s /path/to/directoryCheck that the directory layout is correct — libs/ must be a sibling of
bin/:
otool -L bin/tundra_shell | head -5
# Should show @executable_path/../libs/...The bundle includes ~100 dylibs (~20 MB compressed). To reduce size:
# Strip debug symbols from bundled libs
strip -x dist/TundraDB-1.0.0-macOS/libs/*.dylib- The archive is architecture-specific: an
arm64build won't run on Intel Macs (and vice versa). The script names the archive accordingly. - To support both architectures, build on each platform separately or
create a Universal Binary with
CMAKE_OSX_ARCHITECTURES="arm64;x86_64"(requires all dependencies to also be universal). - This archive is macOS only. For Linux, see the Linux release process.