在Docker中使用crosstool-ng构建交叉编译工具链

目录

最近开始接触嵌入式Linux,构建嵌入式Linux相关的 程序如U-Boot、Kernel等需要在开发主机上安装交叉 编译工具链,本文记录一次在Docker中使用crosstool-ng 构建设适用于 TI Sitara AM3358 SOC 交叉编译工具链的过程。

相关背景

1. crosstool-ng

crosstool-ng用于构建交叉编译工具链,通过一套菜单化配置界面 (menuconfig)使开发者可以以自动化的方式生成适用于不同架构与 C库的交叉编译环境,省去手动编译 binutils、GCC、glibc 等组件 的麻烦。

2. 为什么使用Docker

最开始,我尝试在主机的 Arch Linux 系统上直接使用 crosstool-ng 构建交叉编译工具链,但最终以失败告终。原因在于 crosstool-ng 对构建环境的依赖非常严格,而 Arch Linux 的软件版本普遍较新, 常常与 crosstool-ng 期望的工具链构建流程不完全兼容。

实际操作下来,我发现折腾环境的时间已经远超过“构建工具链”本身。 因此,为了获得一个干净、稳定、可重复的构建环境,最终选择了使用 Docker。 通过 Docker,可以轻松创建一个稳定的 Ubuntu 22.04 环境, 并在其中顺利构建所需的交叉编译工具链。

实验环境

  • 主机OS: Arch Linux
  • 开发板: BeagleBone Black

Docker容器创建

以下Dockerfile和脚本文件的编写参考了 https://github.com/nxp-imx/imx-docker

1. Dockerfile

FROM ubuntu:22.04

# Update system and add the packages required for crosstool-ng builds.
# Use DEBIAN_FRONTEND=noninteractive, to avoid image build hang waiting
# for a default confirmation [Y/n] at some configurations.

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
    apt-get install -y  gcc g++ gperf bison flex texinfo help2man make libncurses5-dev \
    python3-dev autoconf automake libtool libtool-bin gawk wget bzip2 xz-utils unzip \
    patch libstdc++6 rsync git meson ninja-build locales sudo vim curl iputils-ping \
    libssl-dev libgnutls28-dev net-tools

# Set up locales
RUN locale-gen en_US.UTF-8 && \
    update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8

# Needs 'source' command for setting up the build environment, so replace
# the 'sh' alias to 'bash' instead of 'dash'.
RUN rm /bin/sh && ln -s bash /bin/sh

# Add your user to sudoers to be able to install other packages in the container.
ARG USER
RUN echo "${USER} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${USER} && \
    chmod 0440 /etc/sudoers.d/${USER}

# Set the arguments for host_id and user_id to be able to save the build artifacts
# outside the container, on host directories, as docker volumes.
ARG host_uid \
    host_gid
RUN groupadd -g $host_gid ctng && \
    useradd -g $host_gid -m -s /bin/bash -u $host_uid $USER

# Builds should run as a normal user.
USER $USER

ARG DOCKER_WORKDIR
WORKDIR ${DOCKER_WORKDIR}

2. Docker镜像/容器操作相关脚本

为了方便Docker镜像构建和启动容器等操作,编写了一系列脚本:

env.sh
DOCKER_IMAGE_TAG="ctng"
DOCKER_WORKDIR=$YOUR_WORKDIR
CTNG_RELEASE="crosstool-ng"
docker-build.sh
. ./env.sh

usage() {
    echo -e "\e[3m\nUsage: $0 [path_to_Dockerfile]\e[0m\n"
}

if [ $# -ne 1 ]
    then
        usage
    else
        docker build --tag "${DOCKER_IMAGE_TAG}" \
                     --build-arg "DOCKER_WORKDIR=${DOCKER_WORKDIR}" \
                     --build-arg "USER=$(whoami)" \
                     --build-arg "host_uid=$(id -u)" \
                     --build-arg "host_gid=$(id -g)" \
                     -f $1 \
                     .
fi
docker-run.sh
. ./env.sh

docker run -it --rm \
    # use '-e' or '--env' here to set environment variables within the container
    # such as http/https proxies.
    --volume ${HOME}:${HOME} \
    --volume ${DOCKER_WORKDIR}:${DOCKER_WORKDIR} \
    --volume ${DOCKER_WORKDIR}/${CTNG_RELEASE}:${DOCKER_WORKDIR}/${CTNG_RELEASE} \
    "${DOCKER_IMAGE_TAG}" \
    $1

3. 构建Docker镜像并启动容器

./docker-build.sh Dockerfile
./docker-run.sh

构建交叉编译工具链

以下操作均在Docker容器下执行。

1. 构建crosstool-ng

git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
./bootstrap
./configure --enable-local
make

2. 配置待构建工具链

注意工作路径,应该位于env.sh中配置的DOCKER_WORKDIR下。

查看crosstool-ng提供的构建配置文件

crosstool-ng/ct-ng list-samples

加载配置文件

使用与目标平台(Sitara AM3358) 最接近的 Cortex A8 样例配置:

crosstool-ng/ct-ng arm-cortex_a8-linux-gnueabi

调整配置

进入菜单化配置界面:

crosstool-ng/ct-ng menuconfig

做了如下调整:

  • Target选项中,Use specific FPU设置为vfpv3, Floating point设置为hardware (FPU)
  • Toolchain选项中,Tuple's vendor string设置为unknown
  • Operating System中,Version of linux选择6.12
  • Debug facilities下所有的项目取消选择
  • 其余配置选项保持crosstool-ng预设的默认值

3. 构建工具链

执行:

crosstool-ng/ct-ng build

构建工具链,构建完成后,工具链默认安装在$HOME/x-tools/路径下。

参考