This guide provides instructions for building, testing, and benchmarking the Ada URL parser library using CMake.
# Build library only (no tests, no benchmarks)
cmake -B build && cmake --build build
# Build with tests (development checks ENABLED)
cmake -B build -DADA_TESTING=ON && cmake --build build
ctest --output-on-failure --test-dir build
# Build with benchmarks (development checks DISABLED for accurate performance)
cmake -B build -DADA_BENCHMARKS=ON -DADA_USE_UNSAFE_STD_REGEX_PROVIDER=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build
./build/benchmarks/benchdata # Run main benchmark
# FASTER BUILDS: Use Ninja instead of Make
cmake -B build -G Ninja -DADA_TESTING=ON && cmake --build build
cmake -B build -G Ninja -DADA_BENCHMARKS=ON -DADA_USE_UNSAFE_STD_REGEX_PROVIDER=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build- C++20 compatible compiler (GCC 12+, LLVM 14+, MSVC 2022+)
- CMake 3.15+
- Git (for fetching test dependencies)
- Ninja (optional, for faster builds):
sudo apt install ninja-buildon Ubuntu
For a minimal build with just the library:
cmake -B build
cmake --build buildThis creates the Ada library without tests or benchmarks.
To build with tests enabled:
cmake -B build -DADA_TESTING=ON
cmake --build buildImportant: When ADA_TESTING=ON, development checks are automatically enabled unless you explicitly build in Release mode with NDEBUG defined. Development checks include assertions (ADA_ASSERT_TRUE, ADA_ASSERT_EQUAL) that validate internal state.
To build benchmarks for performance testing:
cmake -B build -DADA_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build buildCritical: Always build benchmarks in Release mode (-DCMAKE_BUILD_TYPE=Release) to disable development checks. Development assertions significantly impact performance and will give misleading benchmark results.
If you have dependencies (like GoogleTest, Google Benchmark) already installed locally:
cmake -B build -DADA_TESTING=ON -DCPM_USE_LOCAL_PACKAGES=ON
cmake --build build| Option | Default | Description |
|---|---|---|
ADA_TESTING |
OFF | Enable building tests |
ADA_BENCHMARKS |
OFF | Enable building benchmarks (requires 64-bit) |
ADA_TOOLS |
OFF | Enable building command-line tools |
ADA_BUILD_SINGLE_HEADER_LIB |
OFF | Build from single-header amalgamated files |
ADA_USE_SIMDUTF |
OFF | Enable SIMD-accelerated Unicode via simdutf |
CMAKE_BUILD_TYPE |
- | Set to Release for optimized builds, Debug for development |
After building with -DADA_TESTING=ON:
# Run all tests
ctest --output-on-failure --test-dir build
# Run specific test executable
./build/tests/basic_tests
# Run tests with verbose output
ctest --verbose --test-dir buildTests run with development checks enabled by default (unless built with -DCMAKE_BUILD_TYPE=Release -DNDEBUG). This means:
- Assertions are active (
ADA_ASSERT_TRUE,ADA_ASSERT_EQUAL) - Internal state validation occurs
- Performance is slower but catches bugs early
This is the recommended mode for development.
After building with -DADA_BENCHMARKS=ON:
# Main benchmark comparing against competitors
./build/benchmarks/benchdata
# Specific benchmarks
./build/benchmarks/bench # Basic URL parsing benchmarks
./build/benchmarks/bbc_bench # BBC URLs benchmark
./build/benchmarks/wpt_bench # Web Platform Tests benchmark
./build/benchmarks/percent_encode # Percent encoding benchmarksAlways disable development checks for benchmarks by building in Release mode:
# CORRECT: Benchmarks with development checks disabled
cmake -B build -DADA_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/benchmarks/benchdata
# WRONG: Don't benchmark with development checks enabled
cmake -B build -DADA_BENCHMARKS=ON # Missing Release mode!Development checks add significant overhead that skews performance measurements. The ADA_DEVELOPMENT_CHECKS macro is automatically disabled when:
- Building with
-DCMAKE_BUILD_TYPE=Release NDEBUGis defined- Explicitly set
ADA_DEVELOPMENT_CHECKS=0
# Clone and enter directory
cd /path/to/ada
# Create build directory for tests
cmake -B build -DADA_TESTING=ON
cmake --build build# Make code changes...
# Rebuild (only rebuilds changed files)
cmake --build build
# Run tests to verify correctness
ctest --output-on-failure --test-dir build
# Or run specific test
./build/tests/basic_tests# Create separate benchmark build
cmake -B build-release -DADA_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build-release
# Run benchmarks
./build-release/benchmarks/benchdata
# Compare before/after optimizations
# (stash changes, rebuild, run benchmark, restore, rebuild, run again)# Remove build directory and start fresh
rm -rf build
cmake -B build -DADA_TESTING=ON
cmake --build buildDevelopment checks are compile-time assertions that validate:
- Function preconditions and postconditions
- Internal invariants (e.g.,
validate()on URL objects) - Argument validity
Automatically enabled when:
ADA_TESTING=ON(unless overridden with Release mode)- Debug build (
CMAKE_BUILD_TYPE=Debug) NDEBUGis not defined
Automatically disabled when:
CMAKE_BUILD_TYPE=ReleaseNDEBUGis defined- Production builds
# Force enable development checks (even in Release)
cmake -B build -DADA_DEVELOPMENT_CHECKS=1
# Force disable development checks (even in Debug)
cmake -B build -DNDEBUG=1Clang-tidy is used for static analysis. There are two ways to run it:
Run clang-tidy automatically during compilation:
cmake -B build -DADA_TESTING=ON \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_CLANG_TIDY=clang-tidy \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build buildImportant: You must use clang++ as the compiler when running clang-tidy during build. Using GCC will cause errors because clang-tidy doesn't understand GCC-specific flags like -mno-avx256-split-unaligned-load.
First, generate the compilation database:
cmake -B build -DADA_TESTING=ON \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build buildThen run clang-tidy on specific files:
clang-tidy -p build src/ada.cpp
clang-tidy -p build src/ada_idna.cppThe -p build flag tells clang-tidy to use the compile_commands.json from the build directory.
The .clang-tidy file in the project root configures which checks are enabled. Current configuration enables:
bugprone-*checks (with some exclusions)clang-analyzer-*checks
All warnings are treated as errors (WarningsAsErrors: '*').
Specify configuration during build:
cmake -B build -DADA_TESTING=ON
cmake --build build --config Release
ctest --output-on-failure --test-dir build --config ReleaseStandard commands work as documented above.
Cause: Development checks are enabled.
Solution: Rebuild with Release mode:
cmake -B build -DADA_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build buildExpected behavior - development checks are catching bugs. Review the assertion message and fix the underlying issue.
Cause: Benchmarks not built (32-bit system or not enabled).
Solution:
cmake -B build -DADA_BENCHMARKS=ON
cmake --build build
ls build/benchmarks/ # Check what was builtAda is a shared library used by downstream distributors (e.g., Debian packages). Breaking the ABI causes runtime failures for users who upgrade without recompiling.
- Never remove or rename a public method declared in
include/ada/. Removing a method removes its exported symbol from the shared library, which is an ABI break. - Never change the signature of a public method (parameter types, return type,
const/noexceptqualifiers). - Never make a non-inline method inline (or vice versa) if it is part of the public API — this changes whether the symbol is emitted in the
.so. - Adding new public methods is always safe.
Internal-use methods that must remain exported (e.g., called from templates or inline functions in headers) must be defined in a .cpp file, not in a *-inl.h header. Inline definitions in headers produce weak symbols that the compiler may optimize away, silently breaking the ABI.
CI runs abidiff (from libabigail-tools) to compare the shared library against the latest release tag. You can run the same check locally:
# Build the latest release tag
git worktree add /tmp/ada-baseline <latest-tag>
cmake -G Ninja -B /tmp/ada-baseline-build /tmp/ada-baseline \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=ON -DADA_TESTING=OFF
cmake --build /tmp/ada-baseline-build -j4
# Build the current code
cmake -G Ninja -B /tmp/ada-current-build \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=ON -DADA_TESTING=OFF
cmake --build /tmp/ada-current-build -j4
# Compare ABIs (exit code non-zero = ABI break)
abidiff \
--drop-private-types --no-added-syms \
--headers-dir1 /tmp/ada-baseline/include \
--headers-dir2 include \
/tmp/ada-baseline-build/src/libada.so \
/tmp/ada-current-build/src/libada.so- README.md: General project overview and API usage
- docs/cli.md: Command-line interface documentation
- benchmarks/: Benchmark source code
- tests/: Test source code
- include/ada/: Library headers
| Task | Command | Development Checks |
|---|---|---|
| Library only | cmake -B build && cmake --build build |
N/A |
| Testing | cmake -B build -DADA_TESTING=ON && cmake --build build |
✅ Enabled |
| Benchmarking | cmake -B build -DADA_BENCHMARKS=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build |
❌ Disabled |
| Development | cmake -B build -DADA_TESTING=ON -DCMAKE_BUILD_TYPE=Debug && cmake --build build |
✅ Enabled |