In the previous chapter, Build Configuration, we created the "Instruction Manual" (CMake) for our project. We defined how to switch between a fast "Release" version and a detailed "Debug" version.
However, having an instruction manual isn't enough. You still need someone (or something) to pick up the tools and do the actual work.
In this chapter, we will examine the Build Job Script (build_clickhouse.py). This is the tireless robot that reads the manual and constructs the software.
Imagine a professional kitchen. The Head Chef (you) writes a recipe (CMake).
The result? The food tastes different every time.
The Challenge: In CI, we cannot rely on manual commands. If a developer types cmake .. on their laptop, it might work. But on the CI server, we need absolute consistency. We also need speedโbuilding C++ is slow!
Central Use Case: We want a single command that:
To solve this, we use a Python script to wrap the complexity. Here are the tools it manages:
build_clickhouse.py)
This is a Python script located in docker/packager/. It is the "Manager." It doesn't compile code itself; it tells other tools what to do. It ensures every build happens exactly the same way.
Ninja is our "Builder." While CMake draws the blueprints, Ninja lays the bricks. It is a build tool designed to be extremely fast by running many tasks in parallel.
Sccache is our "Recycler." Compiling C++ takes a lot of CPU power.
Vector.cpp with these exact settings before?" If yes, it downloads the result instead of compiling it. This saves massive amounts of time.In our CI environment (Praktika), we don't type manual commands. The CI calls this script for us.
The script is designed to be run from the command line with arguments.
# usage: build_clickhouse.py --build-type=Release
import argparse
def main():
parser = argparse.ArgumentParser()
# We define the flavor of the build
parser.add_argument("--build-type", default="Release")
args = parser.parse_args()
build(args)
Explanation: This standard Python code accepts arguments. The most important one is --build-type, which corresponds to the configurations we learned about in the previous chapter (Release, Debug, ASan).
Before we build, the script sets up environment variables to enable the "Recycler" (Sccache).
import os
def setup_sccache():
# Tell the compiler to use sccache wrapper
os.environ["CC"] = "sccache clang"
os.environ["CXX"] = "sccache clang++"
# Where to store/fetch the cache (e.g., S3 bucket)
os.environ["SCCACHE_BUCKET"] = "clickhouse-builds"
Explanation: By setting CC and CXX, we trick CMake. Instead of calling the compiler directly, it calls sccache. Sccache then decides whether to download the result or call the actual compiler.
When the CI triggers a build job, a specific sequence of events occurs.
Here is the flow:
Let's look at how the script actually executes the commands. We use Python's subprocess module to run shell commands.
First, we translate our Python arguments into a CMake command.
import subprocess
def run_cmake(build_dir, build_type):
cmd = [
"cmake", "-S", ".", "-B", build_dir,
f"-DCMAKE_BUILD_TYPE={build_type}",
"-GNinja" # Use Ninja generator
]
# Execute the command
subprocess.check_call(cmd)
Explanation: This runs cmake.
-S .: Source is the current directory.-B build_dir: Put temporary files in build_dir.-GNinja: Generate a plan for the Ninja tool.Once the plan is generated, we run Ninja.
def run_ninja(build_dir):
cmd = ["ninja", "-C", build_dir]
print(f"Building in {build_dir}...")
# This starts the heavy compilation process
subprocess.check_call(cmd)
Explanation: ninja -C build_dir tells Ninja to go into the build directory and start working. This is the step that takes 90% of the time (or less, thanks to sccache!).
The script is smart enough to know what hardware it is running on.
import platform
def get_architecture():
# Returns 'aarch64' (ARM) or 'x86_64' (Intel/AMD)
arch = platform.machine()
if arch == "aarch64":
return "arm64"
else:
return "amd64"
Explanation: ClickHouse runs on standard Intel servers and ARM chips (like in newer Macs or AWS Graviton). The script detects the CPU so it can label the final package correctly.
By wrapping the build in a Python script, we gain:
Ninja and Sccache automatically.build_clickhouse.py --build-type=Release.In this chapter, we learned about the Build Job Script.
Now that the script has successfully compiled the code, we have a binary file (the executable). But a raw binary is hard to move around. We need to package it into a standard format that we can easily deploy and test.
In the next chapter, we will see how we wrap this binary into a Docker Server Image.
Next Chapter: Docker Server Image
Generated by Code IQ