mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Add installed dependencies for docker, documentation (#1377)
* Add development tools to docker image python3-cogapp, clang-format, treefmt Add script to run development environment in docker container Document docker use in docs/docker.md --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
parent
866c8a315e
commit
f858b8a72d
@ -36,15 +36,27 @@ RUN set -eux \
|
|||||||
&& apt-get -y install --no-install-recommends \
|
&& apt-get -y install --no-install-recommends \
|
||||||
python3-full \
|
python3-full \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
|
python3-cogapp \
|
||||||
git \
|
git \
|
||||||
wget \
|
wget \
|
||||||
cmake \
|
cmake \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
clang-format \
|
||||||
&& if pip help install | grep -q '\-\-break-system-packages'; then \
|
clang-format-18 \
|
||||||
pip install --no-cache-dir --break-system-packages cogapp; \
|
lcov \
|
||||||
else \
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
pip install --no-cache-dir cogapp; \
|
|
||||||
fi
|
RUN set -eux; \
|
||||||
|
VERSION="2.4.1"; \
|
||||||
|
case "$(uname -m)" in \
|
||||||
|
x86_64) ARCH="amd64"; SHA256="bdaa2c0fbee03e5c2f99e605d9419386ce5d558440baac2017398faada839e04" ;; \
|
||||||
|
aarch64) ARCH="arm64"; SHA256="0a09e1f04a0f8a86fd4e709552613f5d82adf6bc72f0a4b5e217670894e79fbf" ;; \
|
||||||
|
*) echo "Unsupported architecture: $(uname -m)"; exit 1 ;; \
|
||||||
|
esac; \
|
||||||
|
wget -O treefmt.tar.gz "https://github.com/numtide/treefmt/releases/download/v${VERSION}/treefmt_${VERSION}_linux_${ARCH}.tar.gz" \
|
||||||
|
&& echo "${SHA256} treefmt.tar.gz" | sha256sum -c \
|
||||||
|
&& tar xzf treefmt.tar.gz treefmt \
|
||||||
|
&& install -m 755 treefmt /usr/bin/treefmt \
|
||||||
|
&& rm treefmt.tar.gz treefmt
|
||||||
|
|
||||||
RUN set -eux \
|
RUN set -eux \
|
||||||
&& echo "Pip version: " \
|
&& echo "Pip version: " \
|
||||||
|
|||||||
289
docs/docker.md
Normal file
289
docs/docker.md
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
# Docker for Development
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The ETL repository ships a set of Docker-based development environments under
|
||||||
|
`.devcontainer/`. They give every contributor an identical, reproducible toolchain
|
||||||
|
regardless of host operating system. Three flavours are provided:
|
||||||
|
|
||||||
|
| Flavour | Path | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| **Default** | `.devcontainer/` | Day-to-day development (Microsoft C++ dev-container base image) |
|
||||||
|
| **Compiler-specific** | `.devcontainer/gcc09/` … `.devcontainer/gcc15/`, `.devcontainer/clang7/` … `.devcontainer/clang21/` | Test against a specific GCC or Clang version |
|
||||||
|
| **s390x big-endian** | `.devcontainer/s390x/` | Cross-compile and run tests on an s390x target via QEMU |
|
||||||
|
|
||||||
|
All containers include CMake, Make, Git, Python 3, cogapp (the code generator used
|
||||||
|
by ETL), clang-format 18, and treefmt.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Docker** (or Docker Desktop) – any recent version that supports `docker build`
|
||||||
|
and `docker run`.
|
||||||
|
- **VS Code** with the
|
||||||
|
[Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||||
|
extension (optional, but recommended for the smoothest experience).
|
||||||
|
- **Git** – to clone the repository.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Using the helper script
|
||||||
|
|
||||||
|
The fastest way to get a shell inside the default container from the project root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/run-docker.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This script performs two steps:
|
||||||
|
|
||||||
|
1. **Builds** the image from `.devcontainer/Dockerfile` and tags it `etl`.
|
||||||
|
2. **Runs** an interactive container that bind-mounts the repository at
|
||||||
|
`/home/vscode/etl` so that edits made inside the container are visible on
|
||||||
|
the host (and vice versa).
|
||||||
|
|
||||||
|
You are dropped into a Bash shell as the `vscode` user with the working
|
||||||
|
directory set to the repository root.
|
||||||
|
|
||||||
|
### Using VS Code Dev Containers
|
||||||
|
|
||||||
|
1. Open the repository folder in VS Code.
|
||||||
|
2. When prompted, click **Reopen in Container** – or run the command
|
||||||
|
*Dev Containers: Reopen in Container* from the command palette.
|
||||||
|
3. VS Code reads `.devcontainer/devcontainer.json`, builds the image, and
|
||||||
|
attaches to the running container automatically.
|
||||||
|
|
||||||
|
To open a **specific compiler variant** instead, run
|
||||||
|
*Dev Containers: Open Folder in Container…* and pick the sub-folder (e.g.
|
||||||
|
`.devcontainer/gcc14/`), or use the command palette action
|
||||||
|
*Dev Containers: Open Named Container Configuration…* and select the desired
|
||||||
|
name (e.g. "Gcc 14", "Clang 18").
|
||||||
|
|
||||||
|
## Default Development Container
|
||||||
|
|
||||||
|
The file `.devcontainer/Dockerfile` is a multi-purpose image used by the
|
||||||
|
default configuration **and** by every compiler-specific variant (they simply
|
||||||
|
override the `BASE_IMAGE_NAME` build argument).
|
||||||
|
|
||||||
|
### Base image
|
||||||
|
|
||||||
|
```text
|
||||||
|
mcr.microsoft.com/devcontainers/cpp:2
|
||||||
|
```
|
||||||
|
|
||||||
|
The exact digest is pinned in `devcontainer.json` so that builds are
|
||||||
|
reproducible even if the upstream tag is updated.
|
||||||
|
|
||||||
|
### Installed tools
|
||||||
|
|
||||||
|
The Dockerfile installs the following on top of the base image:
|
||||||
|
|
||||||
|
| Tool | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `python3`, `pip` | Runtime for helper scripts |
|
||||||
|
| `python3-cogapp` / `cogapp` | ETL code generator |
|
||||||
|
| `git` | Version control |
|
||||||
|
| `wget` | Downloading additional tooling |
|
||||||
|
| `cmake`, `make` | Build system |
|
||||||
|
| `clang-format` (v18) | Source formatting (see [source-formatting.md](source-formatting.md)) |
|
||||||
|
| `treefmt` (v2.4.1) | Single-command formatting wrapper |
|
||||||
|
|
||||||
|
### Reproducible builds with Debian snapshots
|
||||||
|
|
||||||
|
The default configuration sets the build argument
|
||||||
|
`DEBIAN_SNAPSHOT=20260223T000000Z`. When this value is not `"none"`, the
|
||||||
|
Dockerfile rewrites the APT sources to point at
|
||||||
|
`snapshot.debian.org/archive/debian/<timestamp>`, ensuring that every
|
||||||
|
contributor installs identical package versions. Compiler-specific variants
|
||||||
|
that are based on upstream `gcc:*` or `silkeh/clang:*` images set
|
||||||
|
`DEBIAN_SNAPSHOT=none` because those images manage their own package sources.
|
||||||
|
|
||||||
|
## Compiler-Specific Containers
|
||||||
|
|
||||||
|
Each sub-folder under `.devcontainer/` contains a `devcontainer.json` that
|
||||||
|
reuses the **same** `Dockerfile` (`../Dockerfile`) but overrides the
|
||||||
|
`BASE_IMAGE_NAME` build argument to select a different compiler.
|
||||||
|
|
||||||
|
### GCC variants
|
||||||
|
|
||||||
|
| Folder | Base image | Name |
|
||||||
|
|---|---|---|
|
||||||
|
| `gcc09/` | `gcc:9` | Gcc 09 |
|
||||||
|
| `gcc10/` | `gcc:10` | Gcc 10 |
|
||||||
|
| `gcc11/` | `gcc:11` | Gcc 11 |
|
||||||
|
| `gcc12/` | `gcc:12` | Gcc 12 |
|
||||||
|
| `gcc13/` | `gcc:13` | Gcc 13 |
|
||||||
|
| `gcc14/` | `gcc:14` | Gcc 14 |
|
||||||
|
| `gcc15/` | `gcc:15` | Gcc 15 |
|
||||||
|
|
||||||
|
### Clang variants
|
||||||
|
|
||||||
|
| Folder | Base image | Name |
|
||||||
|
|---|---|---|
|
||||||
|
| `clang7/` | `silkeh/clang:7` | Clang 7 |
|
||||||
|
| `clang8/` | `silkeh/clang:8` | Clang 8 |
|
||||||
|
| `clang9/` | `silkeh/clang:9` | Clang 9 |
|
||||||
|
| `clang10/` | `silkeh/clang:10` | Clang 10 |
|
||||||
|
| `clang11/` | `silkeh/clang:11` | Clang 11 |
|
||||||
|
| `clang12/` | `silkeh/clang:12` | Clang 12 |
|
||||||
|
| `clang13/` | `silkeh/clang:13` | Clang 13 |
|
||||||
|
| `clang14/` | `silkeh/clang:14` | Clang 14 |
|
||||||
|
| `clang15/` | `silkeh/clang:15` | Clang 15 |
|
||||||
|
| `clang16/` | `silkeh/clang:16` | Clang 16 |
|
||||||
|
| `clang17/` | `silkeh/clang:17` | Clang 17 |
|
||||||
|
| `clang18/` | `silkeh/clang:18` | Clang 18 |
|
||||||
|
| `clang19/` | `silkeh/clang:19` | Clang 19 |
|
||||||
|
| `clang20/` | `silkeh/clang:20` | Clang 20 |
|
||||||
|
| `clang21/` | `silkeh/clang:21` | Clang 21 |
|
||||||
|
|
||||||
|
All compiler-specific variants set `DEBIAN_SNAPSHOT` to `"none"` because they
|
||||||
|
rely on the upstream image's own package sources.
|
||||||
|
|
||||||
|
## s390x Big-Endian Cross-Compilation
|
||||||
|
|
||||||
|
The `s390x` container lives in `.devcontainer/s390x/` and has its **own**
|
||||||
|
Dockerfile (it does not reuse the default one). It is based on
|
||||||
|
`debian:trixie` and installs:
|
||||||
|
|
||||||
|
- QEMU user-mode emulation (`qemu-user-static`, `qemu-user`, `binfmt-support`)
|
||||||
|
- s390x cross-compilation toolchain (`gcc-s390x-linux-gnu`,
|
||||||
|
`g++-s390x-linux-gnu`)
|
||||||
|
- CMake, Make, Ninja, Git, wget
|
||||||
|
|
||||||
|
### Container setup
|
||||||
|
|
||||||
|
Open `.devcontainer/s390x/` as a Dev Container in VS Code, or build manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t etl-s390x .devcontainer/s390x
|
||||||
|
docker run -it --rm -v .:/workspaces/etl -w /workspaces/etl etl-s390x
|
||||||
|
```
|
||||||
|
|
||||||
|
### CMake toolchain
|
||||||
|
|
||||||
|
A CMake toolchain file is provided at
|
||||||
|
`.devcontainer/s390x/toolchain-s390x.cmake`. It sets:
|
||||||
|
|
||||||
|
- `CMAKE_SYSTEM_PROCESSOR` to `s390x`
|
||||||
|
- Cross-compilers `s390x-linux-gnu-gcc` / `g++`
|
||||||
|
- `CMAKE_CROSSCOMPILING_EMULATOR` to `/usr/bin/qemu-s390x-static`
|
||||||
|
|
||||||
|
The VS Code Dev Container configuration already passes this toolchain file
|
||||||
|
via `cmake.configureArgs`, so CMake Tools picks it up automatically.
|
||||||
|
|
||||||
|
### Running tests under QEMU
|
||||||
|
|
||||||
|
Because the toolchain file sets `CMAKE_CROSSCOMPILING_EMULATOR`, CTest
|
||||||
|
automatically invokes `qemu-s390x-static` when running test binaries.
|
||||||
|
No extra flags are needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -S test -B build-s390x \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=.devcontainer/s390x/toolchain-s390x.cmake \
|
||||||
|
-DBUILD_TESTS=ON -DNO_STL=OFF -DETL_CXX_STANDARD=17 -G Ninja
|
||||||
|
cmake --build build-s390x
|
||||||
|
ctest --test-dir build-s390x
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building and Running Tests
|
||||||
|
|
||||||
|
Once inside any container (default, compiler-specific, or s390x) you can
|
||||||
|
build and run the ETL test suite.
|
||||||
|
|
||||||
|
### Quick CMake workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure – build tests with C++17
|
||||||
|
cmake -S test -B build -DBUILD_TESTS=ON -DETL_CXX_STANDARD=17
|
||||||
|
|
||||||
|
# Build
|
||||||
|
cmake --build build -j $(nproc)
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
ctest --test-dir build
|
||||||
|
```
|
||||||
|
|
||||||
|
Change `DETL_CXX_STANDARD` to `11`, `14`, `17`, `20`, or `23` as needed.
|
||||||
|
Add `-DNO_STL=ON` to build without the standard library.
|
||||||
|
|
||||||
|
### Using the run-tests script
|
||||||
|
|
||||||
|
The repository also provides a convenience script in `test/`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd test
|
||||||
|
./run-tests.sh <standard> [optimisation] [threads] [sanitizer] [compiler] [verbose]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Argument | Values | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| C++ standard | `11`, `14`, `17`, `20`, `23` | *(required)* |
|
||||||
|
| Optimisation | `0`, `1`, `2`, `3` | `0` |
|
||||||
|
| Threads | any integer | `4` |
|
||||||
|
| Sanitizer | `s` (enable) / `n` (disable) | `n` |
|
||||||
|
| Compiler | `gcc` / `clang` | all |
|
||||||
|
| Verbose | `v` (enable) / `n` (disable) | `n` |
|
||||||
|
|
||||||
|
Example – run C++17 tests at `-O2` with 8 threads using GCC:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run-tests.sh 17 2 8 n gcc n
|
||||||
|
```
|
||||||
|
|
||||||
|
## Formatting Inside the Container
|
||||||
|
|
||||||
|
The default container ships with **clang-format 18** and **treefmt**.
|
||||||
|
See [source-formatting.md](source-formatting.md) for the full formatting guide.
|
||||||
|
|
||||||
|
Quick reference:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Format all tracked C/C++ files with treefmt
|
||||||
|
treefmt
|
||||||
|
|
||||||
|
# Or use clang-format directly via the wrapper
|
||||||
|
./scripts/clang-format-wrapper -i include/etl/*.h
|
||||||
|
```
|
||||||
|
|
||||||
|
The wrapper script `scripts/clang-format-wrapper` resolves the correct
|
||||||
|
clang-format binary (prefers `clang-format-18`, falls back to `clang-format`
|
||||||
|
after checking the major version).
|
||||||
|
|
||||||
|
## Customisation
|
||||||
|
|
||||||
|
To add extra packages or tools to the default container, edit
|
||||||
|
`.devcontainer/Dockerfile`. The image follows a straightforward
|
||||||
|
`apt-get install` pattern, so adding a new package is as simple as appending
|
||||||
|
it to the existing `apt-get` line.
|
||||||
|
|
||||||
|
To create a new compiler variant:
|
||||||
|
|
||||||
|
1. Create a folder under `.devcontainer/` (e.g. `.devcontainer/gcc16/`).
|
||||||
|
2. Add a `devcontainer.json` that references `"../Dockerfile"` and sets
|
||||||
|
`BASE_IMAGE_NAME` to the desired image (e.g. `gcc:16`).
|
||||||
|
3. Set `DEBIAN_SNAPSHOT` to `"none"` for upstream compiler images.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"name": "Gcc 16",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "../Dockerfile",
|
||||||
|
"args": {
|
||||||
|
"BASE_IMAGE_NAME": "gcc:16",
|
||||||
|
"DEBIAN_SNAPSHOT": "none"
|
||||||
|
},
|
||||||
|
"context": "../context"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Symptom | Cause / Fix |
|
||||||
|
|---|---|
|
||||||
|
| `apt-get` fails with *"Release file … is not valid yet"* | The Debian snapshot timestamp is in the future relative to the build host clock. Either update `DEBIAN_SNAPSHOT` in `devcontainer.json` or set it to `"none"`. |
|
||||||
|
| `clang-format` reports the wrong version | The wrapper expects version **18**. Make sure the image installs `clang-format` (or `clang-format-18`) and that the binary is on `PATH`. |
|
||||||
|
| Permission errors on mounted files | The `run-docker.sh` script runs as user `vscode`. Ensure your host UID matches, or adjust the `--user` flag. |
|
||||||
|
| s390x tests crash immediately | Verify that `qemu-user-static` is installed and that `binfmt-support` is active. On some hosts you may need to register binfmt handlers with `docker run --privileged --rm tonistiigi/binfmt --install all`. |
|
||||||
|
| Build is very slow the first time | Docker is downloading and building the image from scratch. Subsequent builds use the layer cache and are much faster. |
|
||||||
18
scripts/run-docker.sh
Executable file
18
scripts/run-docker.sh
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Create docker image for development environment and enter container
|
||||||
|
#
|
||||||
|
# Run from project root directory
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Verify script is running from project root
|
||||||
|
if [ ! -d ".devcontainer" ]; then
|
||||||
|
echo "Error: This script must be run from the project root directory." >&2
|
||||||
|
echo "The .devcontainer directory was not found." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker build -t etl .devcontainer
|
||||||
|
docker run -it --rm -v "$(pwd)":/home/vscode/etl -u vscode -w /home/vscode/etl etl /bin/bash
|
||||||
@ -76,6 +76,7 @@ for CXXSTD in 11 14 17 20 23; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
genhtml total.info --output-directory coverage --rc "genhtml_branch_coverage=1" --branch-coverage -t $COMPILER \
|
genhtml total.info --output-directory coverage --rc "genhtml_branch_coverage=1" --branch-coverage -t $COMPILER \
|
||||||
--ignore-errors inconsistent
|
--ignore-errors inconsistent \
|
||||||
|
--ignore-errors category
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user