Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:ClickHouse ClickHouse Clickhouse Add Executable Macro

From Leeroopedia


Knowledge Sources
Domains Build_System, C++, Systems_Programming
Last Updated 2026-02-08 00:00 GMT

Overview

Concrete tool for creating executable targets with memory allocator interposition provided by the clickhouse_add_executable macro in the root CMakeLists.txt.

Description

The clickhouse_add_executable macro (lines 504-557 of CMakeLists.txt) wraps CMake's built-in add_executable command to automatically inject memory allocator interposition into every ClickHouse executable. This macro is the single point where the critical connection between ClickHouse binaries and the custom memory allocator is established.

The macro performs three key actions:

1. Object file injection: The clickhouse_malloc object library is always included in the executable. On amd64 with glibc compatibility and ThinLTO both enabled, a memcpy object is additionally injected to prevent ThinLTO from generating calls to an incompatible system memcpy.

2. Malloc wrapping via linker options: On Linux (excluding sanitizer builds, macOS, FreeBSD, and SunOS), the macro adds --wrap linker options for nine allocation functions: malloc, free, calloc, realloc, aligned_alloc, posix_memalign, valloc, memalign, and reallocarray. On non-musl builds, pvalloc is also wrapped.

3. C++ new/delete linkage: If the target is an executable type, it links against clickhouse_new_delete, which provides custom operator new and operator delete implementations that use the wrapped allocator.

On macOS with jemalloc, an additional linker flag (-u_zone_register) ensures jemalloc's zone registration constructor is not omitted by the linker, which would cause a segmentation fault.

The primary invocation of this macro is at line 132 of programs/CMakeLists.txt:

clickhouse_add_executable (clickhouse main.cpp)

This creates the main clickhouse binary from main.cpp, which contains the dispatch table with 23+ entries mapping program names to their entry functions.

Usage

This macro must be used in place of add_executable for any ClickHouse executable that needs memory tracking. The main clickhouse binary is the primary consumer. Other executables (such as unit test runners or standalone keeper builds) also use this macro.

Code Reference

Source Location

  • Repository: ClickHouse
  • File: CMakeLists.txt
  • Lines: 504-557

Signature

macro (clickhouse_add_executable target)
    # Inject clickhouse_malloc objects (and optionally memcpy for ThinLTO)
    if (ARCH_AMD64 AND GLIBC_COMPATIBILITY AND ENABLE_THINLTO)
        add_executable (${ARGV} $<TARGET_OBJECTS:clickhouse_malloc> $<TARGET_OBJECTS:memcpy>)
    else ()
        add_executable (${ARGV} $<TARGET_OBJECTS:clickhouse_malloc>)
    endif ()

    # Wrap malloc/free/calloc/realloc/aligned_alloc/posix_memalign/valloc/memalign/reallocarray
    # via --wrap linker options (Linux, non-sanitizer builds only)
    if (NOT (SANITIZE OR SANITIZE_COVERAGE OR OS_DARWIN OR OS_FREEBSD OR OS_SUNOS))
        target_link_options(${target} PRIVATE
            "LINKER:--wrap=malloc"
            "LINKER:--wrap=free"
            "LINKER:--wrap=calloc"
            "LINKER:--wrap=realloc"
            "LINKER:--wrap=aligned_alloc"
            "LINKER:--wrap=posix_memalign"
            "LINKER:--wrap=valloc"
            "LINKER:--wrap=memalign"
            "LINKER:--wrap=reallocarray"
        )
        if (NOT USE_MUSL)
            target_link_options(${target} PRIVATE
                "LINKER:--wrap=pvalloc"
            )
        endif()
    endif()

    # Link custom new/delete operators
    get_target_property (type ${target} TYPE)
    if (${type} STREQUAL EXECUTABLE)
        target_link_libraries (${target} PUBLIC clickhouse_new_delete)

        # macOS jemalloc zone registration
        if (ENABLE_JEMALLOC AND OS_DARWIN)
            set_property(TARGET ${target} APPEND PROPERTY LINK_OPTIONS -u_zone_register)
        endif()
    endif()
endmacro()

Import

# Use instead of add_executable for ClickHouse binaries:
clickhouse_add_executable (clickhouse main.cpp)

# Then link component libraries and common I/O:
target_link_libraries (clickhouse PRIVATE clickhouse_common_io)
clickhouse_target_link_split_lib(clickhouse server)
clickhouse_target_link_split_lib(clickhouse client)
clickhouse_target_link_split_lib(clickhouse local)
# ... etc ...

I/O Contract

Inputs

Name Type Required Description
target String Yes Name of the executable target to create (e.g., clickhouse)
${ARGV} Arguments Yes All arguments passed to the macro, forwarded to add_executable (target name + source files)
clickhouse_malloc Object library Yes Object library providing wrapped allocation functions
memcpy Object library Conditional Custom memcpy object, required when ARCH_AMD64 AND GLIBC_COMPATIBILITY AND ENABLE_THINLTO
clickhouse_new_delete Library Yes Library providing custom C++ operator new and operator delete
Component libraries Static libraries Yes All clickhouse-{name}-lib targets linked after the executable is created
main.cpp Source file Yes Contains the dispatch table and main function

Outputs

Name Type Description
clickhouse Executable Single monolithic binary containing all program modes, with memory allocator interposition
Symlinks Files Post-build symlinks: clickhouse-server, clickhouse-client, clickhouse-local, clickhouse-keeper, chc, chl, ch, and others

Usage Examples

Building the Main Binary

# After CMake configuration:
ninja -C build clickhouse

# The resulting binary:
ls -lh build/programs/clickhouse
# Typical size: ~300MB+ (release), ~700MB+ (debug)

Using Symlinks

# All of these invoke the same binary in different modes:
./build/programs/clickhouse server
./build/programs/clickhouse-server
./build/programs/clickhouse client
./build/programs/clickhouse-client
./build/programs/clickhouse local -q "SELECT 1"
./build/programs/clickhouse-local -q "SELECT 1"
./build/programs/chl -q "SELECT 1"
./build/programs/ch -q "SELECT 1"

Verifying Malloc Wrapping

# Check that malloc is wrapped in the binary:
nm build/programs/clickhouse | grep __wrap_malloc

Related Pages

Implements Principle

Requires Environment

Uses Heuristic

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment