diff --git a/.bazelrc b/.bazelrc index 1c001eda49..ed02c4319c 100644 --- a/.bazelrc +++ b/.bazelrc @@ -102,11 +102,12 @@ common:clang --cxxopt=-gmlt --host_cxxopt=-gmlt common:clang --linkopt=-fuse-ld=lld --host_linkopt=-fuse-ld=lld common:clang --define is_clang=true -# --config=release : the exact compiler configuration used for published executables. Keep debug -# information in Bazel's outputs so tools/stage_release_artifacts.sh can split it from the shipped -# binaries. Explicit -flto=thin flags are intentional: toolchains_llvm does not expose Bazel's -# thin_lto feature, and --features=thin_lto would therefore be accepted but silently do nothing. -common:release --config=clang +# --config=release supplies the production optimization and link settings without selecting a +# compiler. --config=clang_release is the exact composed configuration used for tests and published +# executables. Keep debug information in Bazel's outputs so tools/stage_release_artifacts.sh can +# split it from the shipped binaries. Explicit -flto=thin flags are intentional: toolchains_llvm +# does not expose Bazel's thin_lto feature, and --features=thin_lto would therefore be accepted but +# silently do nothing. common:release --compilation_mode=opt common:release --strip=never common:release --copt=-Oz @@ -115,6 +116,7 @@ common:release --linkopt=-flto=thin # Enable the ELF-only linkopts selected by the two shipped binary targets. Keeping these behind a # build setting prevents LLD spellings from reaching macOS or unrelated test/host executables. common:release --//xff:xff_release_elf_link_optimizations=True +common:clang_release --config=clang --config=release # --config=clang-coverage : collect C++ coverage with the same hermetic Clang/libc++ toolchain # that owns the default build. Bazel otherwise defaults C++ coverage to the local gcov toolchain. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ca54dc96ac..6f49587673 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: os: [ubuntu-latest, macos-latest] config: - name: default - flags: "--config=clang" + flags: "--config=clang_release" - name: asan flags: "--config=clang --config=asan" exclude: @@ -106,12 +106,10 @@ jobs: --disk_cache=$HOME/.cache/bazel-disk --repository_cache=$HOME/.cache/bazel-repo \ "${fuse_test_config[@]}" \ ${{ matrix.config.flags }} - # ThinLTO on every unit-test executable makes a cold job exceed 20 minutes. The ordinary suite - # above remains on the same hermetic Clang toolchain without LTO; these tagged binary-level - # tests compile the actual release targets with size optimization + ThinLTO and exercise both - # lean and full programs. Staging and executing the stripped copies covers the final release - # transformation as well. - - name: Test, build, and smoke-test release artifacts + # The complete suite above builds both shipped binaries with the production ThinLTO config. + # Stage those already-built outputs and execute the stripped copies to cover the final release + # transformation without a second Bazel invocation or compilation configuration. + - name: Stage and smoke-test release artifacts if: matrix.config.name == 'default' run: | set -euo pipefail @@ -122,20 +120,8 @@ jobs: *) echo "unsupported runner OS: ${RUNNER_OS}" >&2; exit 2 ;; esac arch="$(uname -m)" - release_test_config=(--config=release) - if [ "${RUNNER_OS}" = "Linux" ]; then - release_test_config+=(--config=xff_fuse_tests_required) - fi - bazel test //xff/cli:all --config=xff_docs \ - --test_tag_filters=release-binary \ - --disk_cache=$HOME/.cache/bazel-disk --repository_cache=$HOME/.cache/bazel-repo \ - "${release_test_config[@]}" - bazel build --config=release //xff/cli:xff \ - --disk_cache=$HOME/.cache/bazel-disk --repository_cache=$HOME/.cache/bazel-repo - bazel build --config=release --config=xff_full //xff/cli:xff_full \ - --disk_cache=$HOME/.cache/bazel-disk --repository_cache=$HOME/.cache/bazel-repo - lean="$(bazel cquery --config=release --output=files //xff/cli:xff 2>/dev/null)" - full="$(bazel cquery --config=release --config=xff_full --output=files //xff/cli:xff_full 2>/dev/null)" + lean="bazel-bin/xff/cli/xff" + full="bazel-bin/xff/cli/xff_full" tools/stage_release_artifacts.sh "${platform}" "${arch}" "${lean}" "${full}" dist lean_staged="dist/.xff-${platform}-${arch}-staging/xff-${platform}-${arch}/xff" full_staged="dist/.xff_full-${platform}-${arch}-staging/xff_full-${platform}-${arch}/xff_full" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5eb1534676..237b983f6f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -176,17 +176,17 @@ jobs: - name: Build lean + full binaries run: | command -v zstd - bazel build --config=release //xff/cli:xff \ + bazel build --config=clang_release //xff/cli:xff \ --disk_cache="${HOME}/.cache/bazel-disk" --repository_cache="${HOME}/.cache/bazel-repo" - bazel build --config=release --config=xff_full //xff/cli:xff_full \ + bazel build --config=clang_release --config=xff_full //xff/cli:xff_full \ --disk_cache="${HOME}/.cache/bazel-disk" --repository_cache="${HOME}/.cache/bazel-repo" - name: Stage artifacts env: PLATFORM: ${{ matrix.platform }} run: | arch="$(uname -m)" - lean="$(bazel cquery --config=release --output=files //xff/cli:xff 2>/dev/null)" - full="$(bazel cquery --config=release --config=xff_full --output=files //xff/cli:xff_full 2>/dev/null)" + lean="$(bazel cquery --config=clang_release --output=files //xff/cli:xff 2>/dev/null)" + full="$(bazel cquery --config=clang_release --config=xff_full --output=files //xff/cli:xff_full 2>/dev/null)" tools/stage_release_artifacts.sh "${PLATFORM}" "${arch}" "${lean}" "${full}" dist lean_staged="dist/.xff-${PLATFORM}-${arch}-staging/xff-${PLATFORM}-${arch}/xff" full_staged="dist/.xff_full-${PLATFORM}-${arch}-staging/xff_full-${PLATFORM}-${arch}/xff_full" diff --git a/README.md b/README.md index e6433d9546..a6e1c00170 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ bazel build --config=xff_full //xff/cli:xff_full The `//xff` target alias follows your active workspace configuration automatically: it resolves to the lean binary by default, and switches to the full binary under `--config=xff_full`. The underlying targets remain explicit and configuration-stable: `//xff/cli:xff` is always lean, and `//xff/cli:xff_full` is always full. -Published binaries use `--config=release`, which selects the hermetic Clang toolchain, optimizes for +Published binaries use `--config=clang_release`, which combines the hermetic Clang toolchain with size, and enables ThinLTO. Releases provide the stripped `xff-PLATFORM-ARCH` and `xff_full-PLATFORM-ARCH` executables directly. Each platform also provides one level-19 Zstandard-compressed `xff-PLATFORM-ARCH.tar.zst` archive containing both executables plus their diff --git a/docs/history.md b/docs/history.md index 1f640f3005..bca1c2da4c 100644 --- a/docs/history.md +++ b/docs/history.md @@ -65,7 +65,7 @@ The former combined roadmap and completion ledger through PR #683 is retained se | combined `.tar.zst` | 3,794,872 | 3,875,217 | +80,345 B | This non-LTO comparison isolates ordinary ELF linking but is not xff's release configuration. - The actual `--config=release` build uses ThinLTO. Mold reaches that link and then fails because + The actual `--config=clang_release` build uses ThinLTO. Mold reaches that link and then fails because Clang supplies `LLVMgold.so`, which is absent from the downloaded LLVM 22 distribution. LLVM's documented external-linker path requires building a matching gold plugin from the LLVM source tree; LLD consumes the bitcode natively. Supplying that plugin would therefore expand the diff --git a/tools/release_prep_test.sh b/tools/release_prep_test.sh index 322b942ffa..4605d2ebf9 100755 --- a/tools/release_prep_test.sh +++ b/tools/release_prep_test.sh @@ -213,11 +213,11 @@ test_release_reference_uses_clang() { test_release_binaries_use_shared_configuration_and_staging() { release_workflow="${HERE}/../.github/workflows/release.yml" main_workflow="${HERE}/../.github/workflows/main.yml" - if [ "$(count_lines_with 'bazel build --config=release //xff/cli:xff' "${release_workflow}")" -ne 1 ]; then - fail "release workflow: lean binary must build exactly once with --config=release" + if [ "$(count_lines_with 'bazel build --config=clang_release //xff/cli:xff' "${release_workflow}")" -ne 1 ]; then + fail "release workflow: lean binary must build exactly once with --config=clang_release" fi - if [ "$(count_lines_with 'bazel build --config=release --config=xff_full //xff/cli:xff_full' "${release_workflow}")" -ne 1 ]; then - fail "release workflow: full binary must build exactly once with --config=release" + if [ "$(count_lines_with 'bazel build --config=clang_release --config=xff_full //xff/cli:xff_full' "${release_workflow}")" -ne 1 ]; then + fail "release workflow: full binary must build exactly once with --config=clang_release" fi if [ "$(count_lines_with 'tools/stage_release_artifacts.sh' "${release_workflow}")" -ne 1 ]; then fail "release workflow: artifacts must use the shared staging script" @@ -240,14 +240,18 @@ test_release_binaries_use_shared_configuration_and_staging() { if [ "$(count_lines_with ' subject-path: dist/*' "${release_workflow}")" -ne 1 ]; then fail "release workflow: provenance must attest every asset, including SHA256SUMS" fi - if [ "$(count_lines_with 'release_test_config=(--config=release)' "${main_workflow}")" -ne 1 ]; then - fail "main workflow: release-test options must start with --config=release" + if [ "$(count_lines_with 'flags: "--config=clang_release"' "${main_workflow}")" -ne 1 ]; then + fail "main workflow: default tests must use the production Clang release configuration" fi - if [ "$(count_lines_with 'bazel test //xff/cli:all --config=xff_docs' "${main_workflow}")" -ne 1 ]; then - fail "main workflow: binary-level tests must use --config=release" + if [ "$(count_lines_with 'bazel test //xff/cli:all --config=xff_docs' "${main_workflow}")" -ne 0 ]; then + fail "main workflow: release validation must not add a second bazel test invocation" fi - if [ "$(count_lines_with '--test_tag_filters=release-binary' "${main_workflow}")" -ne 1 ]; then - fail "main workflow: release tests must select tagged binary-level bashtests" + if [ "$(count_lines_with 'bazel build --config=clang_release' "${main_workflow}")" -ne 0 ]; then + fail "main workflow: release validation must not add a bazel build invocation" + fi + if [ "$(count_lines_with 'lean="bazel-bin/xff/cli/xff"' "${main_workflow}")" -ne 1 ] \ + || [ "$(count_lines_with 'full="bazel-bin/xff/cli/xff_full"' "${main_workflow}")" -ne 1 ]; then + fail "main workflow: staging must consume both binaries built by the complete test invocation" fi if [ "$(count_lines_with 'tools/stage_release_artifacts.sh' "${main_workflow}")" -ne 1 ]; then fail "main workflow: release cells must exercise the shared staging script" diff --git a/xff/BUILD.bazel b/xff/BUILD.bazel index 02bf415659..a61337b798 100644 --- a/xff/BUILD.bazel +++ b/xff/BUILD.bazel @@ -35,7 +35,8 @@ load("//xff:cc.bzl", "cc_test") package(default_visibility = ["//visibility:private"]) # Internal release-mode switch for ELF linker optimizations. `.bazelrc` enables it only through -# `--config=release`; the Linux constraint below ensures those LLD options never reach Mach-O links. +# `--config=clang_release`; the Linux constraint below ensures those LLD options never reach Mach-O +# links. bool_flag( name = "xff_release_elf_link_optimizations", build_setting_default = False,