为 Fuchsia 构建自定义 Rust 工具链

本指南介绍了如何构建 Rust 编译器以用于 Fuchsia。如果您需要使用已修补的编译器或使用自定义选项构建的编译器来构建 Fuchsia,此功能非常有用。使用其他版本的 Rust 构建 Fuchsia 并不总是需要构建自定义 Rust 工具链;有关详情,请参阅使用自定义 Rust 工具链构建 Fuchsia

前提条件

在为 Fuchsia 构建自定义 Rust 工具链之前,您需要执行以下操作:

  1. 如果您尚未克隆 Rust 源代码,请先克隆。无论何时处理编译器,都可以参考《Rustc 开发指南》

    DEV_ROOT=DEV_ROOT  # parent of your Rust directory
    git clone --recurse-submodules https://github.com/rust-lang/rust.git $DEV_ROOT/rust
  2. 运行以下命令以安装 cmake 和 ninja:

    sudo apt-get install cmake ninja-build
  3. 运行以下命令以获取基础架构来源:

    DEV_ROOT=DEV_ROOT  # parent of your Rust directory
    mkdir -p "$DEV_ROOT/infra" && \
    ( \
      builtin cd "$DEV_ROOT/infra" && \
      jiri init && \
      jiri import -overwrite -name=fuchsia/manifest infra \
          https://fuchsia.googlesource.com/manifest && \
      jiri update \
    )
  4. 运行以下命令,使用 cipd 获取 Fuchsia 核心 IDK、Linux sysroot、最新版本的 clang 以及用于构建 Fuchsia 的 Rust 工具链的正确 Beta 版编译器:

    DEV_ROOT=DEV_ROOT
    HOST_TRIPLE=x86_64-unknown-linux-gnu
    cat << "EOF" > ${DEV_ROOT}/cipd.ensure
    fuchsia/third_party/clang/${platform} latest
    fuchsia/third_party/cmake/${platform} integration
    fuchsia/third_party/ninja/${platform} integration
    fuchsia/third_party/make/${platform} version:4.3
    infra/3pp/tools/go/${platform} version:3@1.24.1
    @Subdir linux
    fuchsia/third_party/sysroot/linux integration
    @Subdir ubuntu20.04
    fuchsia/third_party/sysroot/focal latest
    @Subdir sdk
    fuchsia/sdk/core/${platform} latest
    @Subdir breakpad
    fuchsia/tools/breakpad/${platform} integration
    EOF
    STAGE0_DATE=$(sed -nr 's/^compiler_date=(.*)/\1/p' ${DEV_ROOT}/rust/src/stage0)
    STAGE0_VERSION=$(sed -nr 's/^compiler_version=(.*)/\1/p' ${DEV_ROOT}/rust/src/stage0)
    STAGE0_COMMIT_HASH=$( \
      curl -s "https://static.rust-lang.org/dist/${STAGE0_DATE}/channel-rust-${STAGE0_VERSION}.toml" \
      | python3 -c 'import tomllib, sys; print(tomllib.load(sys.stdin.buffer)["pkg"]["rust"]["git_commit_hash"])')
    echo "@Subdir stage0" >> cipd.ensure
    echo "fuchsia/third_party/rust/host/\${platform} rust_revision:${STAGE0_COMMIT_HASH}" >> cipd.ensure
    echo "fuchsia/third_party/rust/target/${HOST_TRIPLE} rust_revision:${STAGE0_COMMIT_HASH}" >> cipd.ensure
    $DEV_ROOT/infra/fuchsia/prebuilt/tools/cipd ensure \
      --root "${DEV_ROOT}" \
      --ensure-file "${DEV_ROOT}/cipd.ensure"

    下载 Fuchsia 构建的 stage0 编译器是可选的,但对于在 CI 中重新创建 build 非常有用。如果 stage0 不可用,您可以指示 Rust build 下载并使用上游 stage0 编译器,方法是从 cipd.ensure 文件中省略这些行,并移除下面 generate_config.py--stage0 实参。

  5. 运行以下命令以构建 zlib。

    DEV_ROOT=DEV_ROOT  # parent of your Rust directory
    CIPD_DIR=$DEV_ROOT/cipd
    ZLIB_DIR="${DEV_ROOT}/zlib"
    ZLIB_BUILD_DIR="${DEV_ROOT}/build/zlib"
    ZLIB_INSTALL_DIR="${DEV_ROOT}/install/zlib"
    if [[ ! -e  "$ZLIB_DIR" ]]; then
      git clone https://fuchsia.googlesource.com/third_party/zlib $ZLIB_DIR
    fi
    cd $ZLIB_DIR
    git pull --ff-only
    if [[ ! -e "${ZLIB_BUILD_DIR}" ]]; then
      mkdir -p "${ZLIB_BUILD_DIR}"
    fi
    if [[ ! -e "${ZLIB_INSTALL_DIR}" ]]; then
      mkdir -p "${ZLIB_INSTALL_DIR}"
    fi
    ${CIPD_DIR}/bin/cmake \
      -S $ZLIB_DIR \
      -B $ZLIB_BUILD_DIR \
      -G Ninja \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_MAKE_PROGRAM=${CIPD_DIR}/bin/ninja \
      -DCMAKE_INSTALL_PREFIX= \
      -DCMAKE_C_COMPILER=${CIPD_DIR}/bin/clang \
      -DCMAKE_CXX_COMPILER=${CIPD_DIR}/bin/clang++ \
      -DCMAKE_ASM_COMPILER=${CIPD_DIR}/bin/clang \
      -DCMAKE_LINKER=${CIPD_DIR}/bin/ld.lld \
      -DCMAKE_SYSROOT=${CIPD_DIR}/linux \
      -DCMAKE_AR=${CIPD_DIR}/bin/llvm-ar \
      -DCMAKE_NM=${CIPD_DIR}/bin/llvm-nm \
      -DCMAKE_OBJCOPY=${CIPD_DIR}/bin/llvm-objcopy \
      -DCMAKE_OBJDUMP=${CIPD_DIR}/bin/llvm-objdump \
      -DCMAKE_RANLIB=${CIPD_DIR}/bin/llvm-ranlib \
      -DCMAKE_READELF=${CIPD_DIR}/bin/llvm-readelf \
      -DCMAKE_STRIP=${CIPD_DIR}/bin/llvm-strip \
      -DCMAKE_SHARED_LINKER_FLAGS=-Wl,--undefined-version \
      -DCMAKE_C_FLAGS=--target=x86_64-linux-gnu \
      -DCMAKE_CXX_FLAGS=--target=x86_64-linux-gnu \
      -DCMAKE_ASM_FLAGS=--target=x86_64-linux-gnu
    ${CIPD_DIR}/bin/ninja \
      -C $ZLIB_BUILD_DIR
    DESTDIR=$ZLIB_INSTALL_DIR ${CIPD_DIR}/bin/ninja \
      -C "$ZLIB_BUILD_DIR" \
      install
  6. 运行以下命令以构建 zstd。

    DEV_ROOT=DEV_ROOT  # parent of your Rust directory
    CIPD_DIR=$DEV_ROOT/cipd
    ZSTD_DIR=$DEV_ROOT/zstd
    ZSTD_BUILD_DIR=$DEV_ROOT/build/zstd
    ZSTD_INSTALL_DIR=$DEV_ROOT/install/zstd
    if [[ ! -e "$ZSTD_DIR" ]]; then
      git clone https://fuchsia.googlesource.com/third_party/zstd $ZSTD_DIR
    fi
    cd $ZSTD_DIR
    git pull --ff-only
    if [[ ! -e "$ZSTD_BUILD_DIR" ]]; then
      mkdir -p "$ZSTD_BUILD_DIR"
    fi
    if [[ ! -e "$ZSTD_INSTALL_DIR" ]]; then
      mkdir -p "$ZSTD_INSTALL_DIR"
    fi
    $CIPD_DIR/bin/cmake \
      -S ${ZSTD_DIR}/build/cmake \
      -B $ZSTD_BUILD_DIR \
      -G Ninja \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_MAKE_PROGRAM=$CIPD_DIR/bin/ninja \
      -DCMAKE_INSTALL_PREFIX= \
      -DCMAKE_C_COMPILER=$CIPD_DIR/bin/clang \
      -DCMAKE_CXX_COMPILER=$CIPD_DIR/bin/clang++ \
      -DCMAKE_ASM_COMPILER=$CIPD_DIR/bin/clang \
      -DCMAKE_LINKER=$CIPD_DIR/bin/ld.lld \
      -DCMAKE_SYSROOT=$CIPD_DIR/linux \
      -DCMAKE_AR=$CIPD_DIR/bin/llvm-ar \
      -DCMAKE_NM=$CIPD_DIR/bin/llvm-nm \
      -DCMAKE_OBJCOPY=$CIPD_DIR/bin/llvm-objcopy \
      -DCMAKE_OBJDUMP=$CIPD_DIR/bin/llvm-objdump \
      -DCMAKE_RANLIB=$CIPD_DIR/bin/llvm-ranlib \
      -DCMAKE_READELF=$CIPD_DIR/bin/llvm-readelf \
      -DCMAKE_STRIP=$CIPD_DIR/bin/llvm-strip \
      -DZSTD_BUILD_SHARED=OFF \
      -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
      -DCMAKE_C_FLAGS=--target=x86_64-linux-gnu \
      -DCMAKE_CXX_FLAGS=--target=x86_64-linux-gnu \
      -DCMAKE_ASM_FLAGS=--target=x86_64-linux-gnu
    $CIPD_DIR/bin/ninja \
      -C $ZSTD_BUILD_DIR
    DESTDIR=$ZSTD_INSTALL_DIR $CIPD_DIR/bin/ninja \
      -C $ZSTD_BUILD_DIR \
      install

为 Fuchsia 配置 Rust

  1. 切换到 Rust 目录。
  2. 运行以下命令,为 Rust 工具链生成配置:

    DEV_ROOT=DEV_ROOT
    CIPD_DIR="${DEV_ROOT}/cipd"
    ZLIB_INSTALL_DIR="${DEV_ROOT}/install/zlib"
    ZSTD_INSTALL_DIR="${DEV_ROOT}/install/zstd"
    STAGE0_DIR="${CIPD_DIR}/stage0"
    ( \
      export PATH="${DEV_ROOT}/infra/fuchsia/prebuilt/tools:$PATH" && \
      \
      $DEV_ROOT/infra/fuchsia/prebuilt/tools/vpython3 \
        $DEV_ROOT/infra/fuchsia/recipes/recipes/rust_toolchain.resources/generate_config.py \
          config_toml \
          --targets=aarch64-unknown-linux-gnu,x86_64-unknown-linux-gnu,thumbv6m-none-eabi,thumbv7m-none-eabi,riscv32imc-unknown-none-elf,riscv64gc-unknown-linux-gnu \
          --clang-prefix=$CIPD_DIR \
          --stage0="${STAGE0_DIR}" \
          --prefix="${DEV_ROOT}/install/fuchsia-rust" \
          --host-sysroot="${DEV_ROOT}/sysroot/linux" \
          --channel=nightly \
          --zlib-path="${ZLIB_INSTALL_DIR}" \
          --zstd-path="${ZSTD_INSTALL_DIR}" \
          --llvm-is-vanilla \
         | tee "${DEV_ROOT}/fuchsia-config.toml" && \
      \
      $DEV_ROOT/infra/fuchsia/prebuilt/tools/vpython3 \
          $DEV_ROOT/infra/fuchsia/recipes/recipes/rust_toolchain.resources/generate_config.py \
            environment \
            --targets=aarch64-unknown-linux-gnu,x86_64-unknown-linux-gnu,thumbv6m-none-eabi,thumbv7m-none-eabi,riscv32imc-unknown-none-elf,riscv64gc-unknown-linux-gnu \
            --source="${DEV_ROOT}/rust" \
            --stage0="${STAGE0_DIR}" \
            --clang-prefix="$${CIPD_DIR}" \
            --sdk-dir="${CIPD_DIR}/sdk" \
            --linux-sysroot="$CIPD_DIR}/linux" \
            --linux-riscv64-sysroot="${CIPD_DIR}/ubuntu20.04" \
            --eval \
         | tee "${DEV_ROOT}/fuchsia-env.sh" \
    )
  3. (可选)运行以下命令,告知 Git 忽略生成的文件:

    echo fuchsia-config.toml >> .git/info/exclude
    echo fuchsia-env.sh >> .git/info/exclude
  4. (可选)自定义 fuchsia-config.toml

构建和安装 Rust

  1. 切换到 Rust 源代码目录。
  2. 运行以下命令来构建和安装 Rust 以及 Fuchsia 运行时规范:

    DEV_ROOT=DEV_ROOT
    rm -rf ${DEV_ROOT}/install/fuchsia-rust"
    mkdir -p "${DEV_ROOT}/install/fuchsia-rust"
    # Copy and paste the following subshell to build and install Rust, as needed.
    # The subshell avoids polluting your environment with fuchsia-specific rust settings.
    ( \
      export CFLAGS="-I${DEV_ROOT}/install/zlib/include -I${DEV_ROOT}/install/zstd/include" && \
      export CXXFLAGS="-I${DEV_ROOT}/install/zlib/include -I${DEV_ROOT}/install/zstd/include" && \
      export LDFLAGS="-L${DEV_ROOT}/install/zlib/lib -L${DEV_ROOT}/install/zstd/lib" && \
      export RUSTFLAGS="-Clink-arg=-L${DEV_ROOT}/install/zlib/lib -Clink-arg=-L${DEV_ROOT}/install/zstd/lib" && \
      \
      source "${DEV_ROOT/fuchsia-env.sh" && \
      ./x.py install \
        --config "${DEV_ROOT}/fuchsia-config.toml" \
        --skip-stage0-validation \
     ) && \
     rm -rf "${DEV_ROOT}/install/fuchsia-rust/lib/.build-id" && \
     "${DEV_ROOT}/infra/fuchsia/prebuilt/tools/vpython3" \
      "${DEV_ROOT}/infra/fuchsia/recipes/recipes/rust_toolchain.resources/generate_config.py" \
        runtime \
      | "${DEV_ROOT}/infra/fuchsia/prebuilt/tools/vpython3" \
          "${DEV_ROOT}/infra/fuchsia/recipes/recipe_modules/toolchain/resources/runtimes.py" \
            --dir "${DEV_ROOT}/install/fuchsia-rust/lib" \
            --build-id-repo debug/.build-id \
            --readelf "${CIPD_DIR}/bin/llvm-readelf" \
            --dump_syms "${CIPD_DIR}/breakpad/dump_syms/dump_syms" \
            --objcopy "${CIPD_DIR}/bin/llvm-objcopy" \
            --dist dist \
      > "${DEV_ROOT}/install/fuchsia-rust/lib/runtime.json"

仅构建(可选)

如果您想跳过安装步骤(例如在开发 Rust 本身期间),可以使用以下命令。

DEV_ROOT=DEV_ROOT
( \
  export CFLAGS="-I${DEV_ROOT}/install/zlib/include -I${DEV_ROOT}/install/zstd/include" && \
  export CXXFLAGS="-I${DEV_ROOT}/install/zlib/include -I${DEV_ROOT}/install/zstd/include" && \
  export LDFLAGS="-L${DEV_ROOT}/install/zlib/lib -L${DEV_ROOT}/install/zstd/lib" && \
  export RUSTFLAGS="-Clink-arg=-L${DEV_ROOT}/install/zlib/lib -Clink-arg=-L${DEV_ROOT}/install/zstd/lib" && \
  \
  source "${DEV_ROOT}fuchsia-env.sh && \
  \
  ./x.py build \
  --config \
    "${DEV_ROOT}/fuchsia-config.toml" \
    --skip-stage0-validation \
)

问题排查

如果您遇到 build 错误,请尝试删除 Rust build 目录:

rm -rf fuchsia-build

然后,重新运行该命令以构建 Rust。

使用自定义 Rust 工具链构建 Fuchsia

现在,您已编译了新的自定义 Rust 工具链,可以开始使用它来构建 Fuchsia 了。如需了解具体操作方法,请参阅专用指南