强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

18 - Docker 中的 GCC

18 - Docker 中的 GCC

学习在 Docker 容器中使用 GCC,构建交叉编译容器和多架构构建流水线。


18.1 Docker 中使用 GCC 的优势

优势说明
环境一致性所有开发者和 CI 使用相同的编译环境
多版本共存不同项目可以使用不同 GCC 版本,互不干扰
清洁环境每次构建都是干净的,避免环境残留问题
交叉编译轻松配置目标架构的编译环境
CI/CD 集成标准化的构建镜像,易于 CI 集成

18.2 基本 GCC Docker 镜像

基于 Ubuntu 的镜像

# Dockerfile.gcc
FROM ubuntu:22.04

# 安装基本开发工具
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    g++ \
    make \
    cmake \
    gdb \
    libc6-dev \
    && rm -rf /var/lib/apt/lists/*

# 设置工作目录
WORKDIR /src

# 默认命令
CMD ["bash"]
# 构建镜像
docker build -t my-gcc -f Dockerfile.gcc .

# 使用
docker run --rm -v $(pwd):/src my-gcc gcc -o hello main.c
docker run --rm -v $(pwd):/src my-gcc ./hello

多版本 GCC 镜像

# Dockerfile.gcc-multi
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y --no-install-recommends \
    software-properties-common \
    && add-apt-repository ppa:ubuntu-toolchain-r/test \
    && apt-get update \
    && apt-get install -y --no-install-recommends \
    gcc-11 g++-11 \
    gcc-12 g++-12 \
    gcc-13 g++-13 \
    make cmake \
    && rm -rf /var/lib/apt/lists/*

# 设置默认版本
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 \
    && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 100

WORKDIR /src
CMD ["bash"]

18.3 交叉编译容器

ARM64 交叉编译镜像

# Dockerfile.cross-aarch64
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc-aarch64-linux-gnu \
    g++-aarch64-linux-gnu \
    libc6-dev-arm64-cross \
    cmake \
    make \
    file \
    qemu-user-static \
    && rm -rf /var/lib/apt/lists/*

# 设置环境变量
ENV CROSS_TRIPLE=aarch64-linux-gnu
ENV CC=${CROSS_TRIPLE}-gcc
ENV CXX=${CROSS_TRIPLE}-g++

WORKDIR /src
CMD ["bash"]
# 构建
docker build -t cross-aarch64 -f Dockerfile.cross-aarch64 .

# 交叉编译
docker run --rm -v $(pwd):/src cross-aarch64 \
    aarch64-linux-gnu-gcc -o hello_arm64 main.c

# 检查
docker run --rm -v $(pwd):/src cross-aarch64 \
    file hello_arm64

多架构交叉编译镜像

# Dockerfile.cross-multi
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \
    gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
    gcc-riscv64-linux-gnu g++-riscv64-linux-gnu \
    gcc-mips-linux-gnu g++-mips-linux-gnu \
    libc6-dev-arm64-cross libc6-dev-armhf-cross \
    cmake make file \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /src

# 构建脚本
COPY build-all.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/build-all.sh

CMD ["build-all.sh"]
#!/bin/bash
# build-all.sh - 为所有目标架构编译
set -e

TARGETS="aarch64-linux-gnu arm-linux-gnueabihf riscv64-linux-gnu"

for target in $TARGETS; do
    echo "=== Building for $target ==="
    $target-gcc -O2 -Wall -o hello_${target} main.c
    file hello_${target}
done

18.4 CI/CD 集成

GitHub Actions

# .github/workflows/build.yml
name: Build with GCC

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        gcc-version: [11, 12, 13]

    steps:
    - uses: actions/checkout@v4

    - name: Install GCC
      run: |
        sudo apt-get update
        sudo apt-get install -y gcc-${{ matrix.gcc-version }} g++-${{ matrix.gcc-version }}

    - name: Build
      run: |
        CC=gcc-${{ matrix.gcc-version }} CXX=g++-${{ matrix.gcc-version }} \
        cmake -B build -DCMAKE_BUILD_TYPE=Release
        cmake --build build

    - name: Test
      run: cd build && ctest --output-on-failure

  cross-compile:
    runs-on: ubuntu-latest
    container:
      image: ubuntu:22.04
    strategy:
      matrix:
        arch: [aarch64, armhf, riscv64]

    steps:
    - uses: actions/checkout@v4

    - name: Install cross-compiler
      run: |
        apt-get update
        apt-get install -y gcc-${{ matrix.arch }}-linux-gnu cmake make

    - name: Build
      run: |
        cmake -B build \
          -DCMAKE_TOOLCHAIN_FILE=cmake/${{ matrix.arch }}-toolchain.cmake
        cmake --build build

GitLab CI

# .gitlab-ci.yml
stages:
  - build
  - test

build-gcc:
  stage: build
  image: gcc:13
  script:
    - cmake -B build -DCMAKE_BUILD_TYPE=Release
    - cmake --build build
  artifacts:
    paths:
      - build/

test:
  stage: test
  image: ubuntu:22.04
  script:
    - cd build && ctest --output-on-failure

18.5 构建优化的 Docker 镜像

多阶段构建

# Dockerfile.multistage
# 阶段 1: 编译
FROM ubuntu:22.04 AS builder

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc g++ make cmake libc6-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /src
COPY . .

RUN cmake -B build -DCMAKE_BUILD_TYPE=Release \
    && cmake --build build

# 阶段 2: 运行(最小镜像)
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y --no-install-recommends \
    libc6 \
    && rm -rf /var/lib/apt/lists/*

COPY --from=builder /src/build/hello /usr/local/bin/

CMD ["hello"]

静态链接最小镜像

# Dockerfile.static
FROM alpine:3.19 AS builder

RUN apk add --no-cache gcc musl-dev make cmake

WORKDIR /src
COPY . .

RUN cmake -B build -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_EXE_LINKER_FLAGS="-static" \
    && cmake --build build

# 使用 scratch(空镜像)
FROM scratch
COPY --from=builder /src/build/hello /hello
CMD ["/hello"]

18.6 Docker 中的性能分析

# Dockerfile.profiling
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc g++ make cmake \
    linux-tools-generic \
    valgrind \
    && rm -rf /var/lib/apt/lists/*

# perf 需要特定内核版本,可能在容器中受限
# 推荐使用 --privileged 运行
WORKDIR /src
# 使用 perf 进行性能分析(需要 --privileged)
docker run --rm --privileged -v $(pwd):/src my-profiling \
    bash -c "cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo \
    && cmake --build build && cd build && perf record -g ./hello && perf report"

# 使用 Valgrind
docker run --rm -v $(pwd):/src my-profiling \
    valgrind --leak-check=full ./build/hello

18.7 多架构 Docker 镜像构建

# 注册 QEMU binfmt
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

# 为多个架构构建
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 \
    -t myapp:latest --push .

Dockerfile 多架构支持

# Dockerfile.multiarch
FROM --platform=$BUILDPLATFORM ubuntu:22.04 AS builder

ARG TARGETPLATFORM
ARG TARGETARCH

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc make cmake \
    && if [ "$TARGETARCH" = "arm64" ]; then \
        apt-get install -y gcc-aarch64-linux-gnu; \
    elif [ "$TARGETARCH" = "arm" ]; then \
        apt-get install -y gcc-arm-linux-gnueabihf; \
    fi \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /src
COPY . .

RUN if [ "$TARGETARCH" = "arm64" ]; then \
        CC=aarch64-linux-gnu-gcc cmake -B build; \
    elif [ "$TARGETARCH" = "arm" ]; then \
        CC=arm-linux-gnueabihf-gcc cmake -B build; \
    else \
        cmake -B build; \
    fi \
    && cmake --build build

# 最终运行镜像
FROM ubuntu:22.04
COPY --from=builder /src/build/hello /usr/local/bin/
CMD ["hello"]

要点回顾

要点核心内容
基本镜像Ubuntu + gcc/g++,适合开发和测试
交叉编译gcc-aarch64-linux-gnu + QEMU 用户模式
多阶段构建编译阶段 + 运行阶段,最小化最终镜像
CI 集成GitHub Actions / GitLab CI 中使用容器构建
多架构docker buildx build --platform 构建多架构镜像

注意事项

缓存层优化: Dockerfile 中将安装依赖的 RUN 指令放在 COPY 源码之前,利用 Docker 层缓存加速重复构建。

不要在容器中存储构建产物: 使用 -v 挂载或 docker cp 将构建产物移到宿主机。

perf 在容器中受限: 容器中使用 perf 需要 --privileged 或配置 security_opt

静态链接简化部署: 对于 C 程序,使用 -static 链接可以用 scratch 镜像,极大减小镜像大小。


扩展阅读


下一步

19 - 故障排查:掌握 GCC 编译和链接过程中常见错误的诊断与解决。