Repository navigation
refactor(bazel): drop the generated Linux toolchain wrapper scripts - #3832
Alexandr-Solovev wants to merge 6 commits into
Conversation
Third step of the Bazel maintainability series. No behavioural change; the Linux build produces the same actions (verified by a full action-cache hit). * `dev/bazel/toolchains/extra_toolchian_lnx.tpl.BUILD` -> `extra_toolchain_lnx`. The typo was load-bearing: the label in `extra_toolchain_lnx.bzl` spelled it the same way, so it worked, but the file did not turn up when grepping for the toolchain by name. * `_copy_dynamic_release_file` in `cc.bzl` had a `cp` branch for non-Windows hosts, and the only two call sites are inside `if is_windows:` and pass `is_windows = is_windows`. Renamed to `_copy_windows_release_file`, dropped the unreachable branch and the flag, and documented why a copy is used instead of a symlink. * `_copy_to_release_impl` in `release.bzl` resolved the `extra` toolchain into a local it never read; the rule does not use the toolchain at all, so the declaration goes too. `daal.bzl` remains its only consumer. * Dropped seven load symbols that are not referenced in the file that loads them. * `.bazelrc` opened with an argument-less `common` line, left behind by the Bazel 8 upgrade (uxlfoundation#3035) when the flag it was meant to carry ended up on the `build` line instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`cc_toolchain_config_lnx.bzl` and `cc_toolchain_config_win.bzl` are two descriptions of two different compiler drivers, so most of their features genuinely differ -- `-I` against `/I`, `-MD -MF` against `/clang:-MD /clang:-MF`. What did not differ was copied: the action groups, ten features whose flags come entirely from rule attributes or Bazel build variables, and the 28 rule attributes both rules declare. Move those to `cc_toolchain_config_common.bzl` and have both files load them. Nothing changes in the generated command lines: building after the change is a full action-cache hit, and every moved block is textually identical to the two originals it replaces, modulo whitespace and the parameter names that stand in for `ctx.attr.*`. `preprocessor_compile_actions` and `codegen_compile_actions` were defined in both files and referenced in neither, so they are dropped instead of moved. Addresses the "Toolchain code unification" item in dev/bazel/TODO.md. The per-compiler features stay where they are; a shared factory with a per-platform branch inside would be harder to follow than the duplicate it replaces. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Removing one `#define` per disabled ISA from `services/internal/daal_kernel_defines.h` was implemented as a custom toolchain: a toolchain type, a provider, a repository rule, a module extension, two generated `BUILD` templates and three copies of the patcher itself (bash, batch, PowerShell). Ten files, so that an action could run one regex substitution. `ctx.actions.expand_template` performs the substitution at execution time, so nothing needs to read the header during analysis and no helper tool is needed on either platform. The Makefile's Windows line ending -- a disabled define becomes a lone CR, leaving `\r\n` -- is expressed as the replacement string. Also removes a real hermeticity bug: the patcher was handed to `ctx.actions.run` as an `attr.string` absolute path, not as a file, so it was not an input of the action and editing it did not invalidate the cached output. Verified byte for byte against the previous implementation's output for `--cpu=all`, `avx512`, `avx2` and `sse2`, and the following build is a full action-cache hit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Linux toolchain templated two bash wrappers into the generated repository at configure time. `dynamic_link_lnx.tpl.sh` sat between Bazel and the compiler on every link action. Its only job was to turn a Windows module-definition file into `-u <symbol>` flags; no target in the tree passes one, and a `.def` has no GNU equivalent anyway (a version script is a different format), so the branch was dead and every link paid for an extra shell. The link actions now name the compiler driver directly, exactly like the compile actions do, and `cc_link_path` / `dpcc_link_path` move out of the shared attributes into the Windows rule, which is where a standalone linker really is used. `def_file` now fails with a clear message off Windows instead of passing the file to gcc as a response file. `merge_static_libs_lnx.tpl.sh` wrote an MRI script for `ar -M`, and existed only because `ctx.actions.run` cannot redirect stdin. Driving that from a generated script also required a custom `cpp_merge_static_libraries` action name and an `action_config` whose tool was a hard-coded absolute path. `actions.write` produces the MRI script as a tracked file and `actions.run_shell` redirects it into the toolchain's own, resolved `cpp_link_static_library` archiver, so the custom action name, its `action_config`, the `ar_merge_path` attribute and `action_names.bzl` all disappear. The action also gains a mnemonic and a progress message, which it never had. Verified on Linux: * a probe target that merges a static library with the MKL archives produces a byte-identical 658 MB result before and after; * `libonedal.so`, `libonedal_parameters.so` and `libonedal_dpc.so` relink byte-identically without the wrapper; * `//:release`, `//:release_all` and `//examples/oneapi/cpp:all` analyse clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
It changes critical cross-platform toolchain behavior while the Windows path remains unvalidated.
Review effort: Balanced
Findings: None
What changed in this PR
Simplifies Bazel toolchains by removing generated Linux wrappers and the stacked custom header-patching toolchain.
Changes:
- Links directly through compiler drivers and merges archives using an MRI script.
- Consolidates shared Linux/Windows toolchain configuration.
- Replaces kernel-definition patch scripts with
expand_template.
| File | Description |
|---|---|
.bazelrc |
Removes empty configuration and trailing whitespace. |
MODULE.bazel |
Unregisters the extra toolchain. |
dev/bazel/cc.bzl |
Restricts release-file copying to Windows. |
dev/bazel/cc/common.bzl |
Removes an unused import. |
dev/bazel/cc/link.bzl |
Uses direct archiver and linker actions. |
dev/bazel/daal.bzl |
Patches kernel defines with expand_template. |
dev/bazel/release.bzl |
Removes extra-toolchain resolution. |
dev/bazel/toolchains/BUILD |
Removes the obsolete toolchain type. |
dev/bazel/toolchains/action_names.bzl |
Deletes the custom merge action name. |
dev/bazel/toolchains/cc_toolchain_config_common.bzl |
Adds shared toolchain features and attributes. |
dev/bazel/toolchains/cc_toolchain_config_lnx.bzl |
Uses direct tools and shared configuration. |
dev/bazel/toolchains/cc_toolchain_config_win.bzl |
Reuses shared configuration factories. |
dev/bazel/toolchains/cc_toolchain_lnx.bzl |
Stops generating Linux wrapper scripts. |
dev/bazel/toolchains/cc_toolchain_lnx.tpl.BUILD |
Removes wrapper inputs and attributes. |
dev/bazel/toolchains/cc_toolchain_win.bzl |
Clarifies Windows linker behavior. |
dev/bazel/toolchains/dynamic_link_lnx.tpl.sh |
Removes the Linux link wrapper. |
dev/bazel/toolchains/merge_static_libs_lnx.tpl.sh |
Removes the archive-merge wrapper. |
dev/bazel/toolchains/extra_toolchain.bzl |
Deletes extra-toolchain implementation. |
dev/bazel/toolchains/extra_toolchain_extension.bzl |
Deletes its module extension. |
dev/bazel/toolchains/extra_toolchain_lnx.bzl |
Deletes Linux extra-toolchain setup. |
dev/bazel/toolchains/extra_toolchain_win.bzl |
Deletes Windows extra-toolchain setup. |
dev/bazel/toolchains/extra_toolchian_lnx.tpl.BUILD |
Deletes Linux toolchain template. |
dev/bazel/toolchains/extra_toolchain_win.tpl.BUILD |
Deletes Windows toolchain template. |
dev/bazel/toolchains/tools/patch_daal_kernel_defines.sh |
Deletes Linux patch helper. |
dev/bazel/toolchains/tools/patch_daal_kernel_defines.cmd |
Deletes Windows launcher. |
dev/bazel/toolchains/tools/patch_daal_kernel_defines.ps1 |
Deletes Windows patch helper. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
napetrov
left a comment
There was a problem hiding this comment.
Measured locally: Linux x86, Bazel 9.2.0, gcc 13.3, icpx 2025.2; clean env (env -i, no MKLROOT/TBBROOT); one worktree + output base per head, base = merge-base 3120d0ab.
- Linux host: walking #3831 -> this head in one output base re-runs exactly 8 actions (the 4
.a+ 4.solinks); all outputs byte-identical to base. - DPC: the
libonedal_dpc.solink now execsicpxdirectly (was.../onedal_cc_toolchain/dpc_dynamic_link.sh); DPC//:releasetree (1096 entries) at #3833, which contains this PR, is byte-identical to base. - Coverage of the new MRI path, inline.
- Minor: on Linux only
.afiles reach the MRI branch (objects go throughcc_commonfirst), so "object files and" in the_merge_static_libsdocstring applies to Windows only.
| feature_configuration = feature_configuration, | ||
| action_name = CPP_MERGE_STATIC_LIBRARIES, | ||
| variables = merger_variables, | ||
| mri_script = actions.declare_file(filename + ".mri") |
There was a problem hiding this comment.
Coverage note: on x86 with MKL this branch never runs. aquery 'mnemonic("MergeStaticLibraries", ...)' finds 0 actions for host //:release, DPC //:release, and //cpp/... + //examples/.... It only fires when a prebuilt .a is in the linking context, i.e. --backend_config=ref (libonedal_thread.a <- libonedal_thread_no_deps.a + libopenblas.a).
I built static OpenBLAS 0.3.34 with .ci/env/openblas.sh and ran that config: the MRI script works with the bzlmod + paths and the release tree is byte-identical to base. So the aarch64/rv64 OpenBLAS jobs are the only CI coverage of this code - worth stating in the description.
There was a problem hiding this comment.
Confirmed independently, and agreed it belongs in the description.
Reproduced the 0-action result here on x86 with MKL:
aquery 'mnemonic("MergeStaticLibraries", //:release)' -> 0 actions
aquery 'mnemonic("MergeStaticLibraries", //cpp/... union //examples/...)' -> 0 actions
And pinned down exactly where the flag that does reach it lives — --backend_config=ref appears in two places in CI and nowhere else:
.github/workflows/ci-aarch64.ymllines 253, 305, 330 — theLinuxBazel_OpenBLAS(SVE)jobs.ci/pipeline/ci.ymlline 717 —CI (LinuxBazelGNU_OpenBLAS_rv64)
So your conclusion holds: the aarch64 and rv64 OpenBLAS jobs are the only CI coverage of the MRI branch. The x86 jobs exercise the Windows lib branch and the unchanged link paths instead. I could not re-run the ref config locally — this worktree has no static OpenBLAS, and aquery --backend_config=ref stops at Cannot locate +openblas_repo+openblas dependency — so I am taking your byte-identical ref release tree on report rather than claiming it myself.
Your docstring point is also right, and it was wrong in both the summary line and the Args: entry. Only lines 121 and 252 pass all_object_list, and both sit inside if is_windows; the Linux-reachable call sites at 150, 198 and 207 pass unpacked_linking_context.static_libraries alone. Fixed in 3497aba:
"""Archive whole static libraries into a single library.
...
On Linux `static_libs` holds archives only, since object files go
through `cc_common` first.
Args:
...
static_libs: static libraries to merge, plus loose object files on
Windows.//:release still analyses clean after it. Docstring-only, so no action re-execution.
The coverage paragraph above is not in the description yet — I will get it in there.
Only Windows passes loose object files; the Linux callers pass archives alone, since objects go through `cc_common` first. Signed-off-by: Alexandr-Solovev <aleksandr.solovev@intel.com>
|
On the Copilot overview's "the Windows path remains unvalidated" — Windows Bazel is covered, and it is green on this head:
plus I think the flag comes from the file table in that overview, which lists One thing in that direction is fair, though: the description's "Windows is untouched apart from..." undersells it slightly. |
None of the cc_toolchain file attributes is mandatory, and an omitted one resolves to an empty depset, so listing :empty only adds noise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Superseded by #3833, which now carries this PR's commits unchanged (plus the review fixes made here), rebased on current |
Fifth PR of the
dev/bazelsimplification series. Stacked on #3831 — the diff below is the last commit only.The Linux toolchain templated two bash wrappers into the generated repository at configure time and put them on the critical path of every link and every archive merge. Both are gone; stock Bazel actions do the work.
dynamic_link_lnx.tpl.sh— an extra shell on every linkThe wrapper's only real behaviour was scanning the command line for a
*.defargument and rewriting it into-u <symbol>flags. Nothing in the tree passes a module-definition file to a Linux link (the single.def,export_win32e.def, is Makefile-only and Windows-only), and a.defhas no GNU counterpart anyway — a version script is a different file format. So the branch was dead, and every link action forked a shell to reach%{cc_path} "$@".Link actions now name the compiler driver directly, exactly like the compile actions already did.
cc_link_path/dpcc_link_pathmove out ofCOMMON_ATTRSinto the Windows rule, which is the only platform where the linker really is a separate binary (lld-link/link.exe), and the twotool()definitions they fed collapse into the existingcc_tool/dpcc_tool.def_filenowfail()s with a clear message off Windows rather than handing the file to gcc as an@responsefile.merge_static_libs_lnx.tpl.sh— a custom action name for a stdin redirectcc_commonhas no API for merging archives — its archiving action adds an input.aas a member — so oneDAL drivesaritself. GNUartakes its merge instructions as an MRI script on stdin, andctx.actions.runcannot redirect stdin, so the MRI script was generated by a shell wrapper. Supporting that required a whole custom action:dev/bazel/toolchains/action_names.bzldeclaringcpp_merge_static_librariesaction_configfor it whosetool()was the generated script's absolute pathar_merge_pathrule attribute, a%{ar_merge_path}substitution and anar_depsfilegroupcc_common.create_link_variables+get_memory_inefficient_command_line+get_environment_variablescalls to build a command line for an action that has no flagsReplaced by:
where
archiver_pathis the toolchain's resolvedcpp_link_static_librarytool. The MRI script becomes a tracked file, the custom action name and itsaction_configdisappear, and the action gains a mnemonic and a progress message it never had (it was reported as a bareAction).Net
-204 / +62lines, two generated scripts and one.bzlfile removed.Validation (Linux)
.abefore and after the change, from the sameADDLIBorder.libonedal.so,libonedal_parameters.soandlibonedal_dpc.sorelink byte-identically with the compiler driver called directly instead of through the wrapper — including the DPC++ link.//:release,//:release_alland//examples/oneapi/cpp:allanalyse clean.ar_files/linker_filesfilegroups no longer contain the deleted scripts; their outputs are the byte-identical ones above.ar_filesandlinker_fileswere:ar_deps/:linker_deps(the wrapper scripts) and are now omitted, i.e. empty, likedwp_files/objcopy_files/strip_files. The hostarand linker are therefore untracked absolute paths, which is already the case for the compiler driver's own tools; outputs are unchanged (host, DPC++ and--backend_config=refrelease trees byte-identical to base, measured by @napetrov).Windows is untouched apart from gaining the two link-path attributes it already used and a stale comment fix.