This is an automated email from the ASF dual-hosted git repository.

leginee pushed a commit to branch bazel-migration
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit da6d97753b9dbacd92e5039544392af0fdea15d6
Author: Peter Kovacs <[email protected]>
AuthorDate: Thu Jul 2 21:41:20 2026 +0200

    switch to LLVM Linker if we build debug builds with pbd files
---
 build/toolchain/BUILD.bazel                     | 16 +++--
 build/toolchain/windows_cc_toolchain_config.bzl | 34 ++++++++--
 build/vs_config_repo.bzl                        | 88 +++++++++++++++++++++++--
 3 files changed, 123 insertions(+), 15 deletions(-)

diff --git a/build/toolchain/BUILD.bazel b/build/toolchain/BUILD.bazel
index ab0b8b16cf..5a244540d0 100644
--- a/build/toolchain/BUILD.bazel
+++ b/build/toolchain/BUILD.bazel
@@ -1,6 +1,6 @@
 load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain")
 load(":windows_cc_toolchain_config.bzl", "cc_toolchain_config")
-load("@vs_config//:paths.bzl", _VS = "VS", _VC = "VC", _SDK = "SDK", _MSVC_TMP 
= "MSVC_TMP", _LINK_WRAPPER = "LINK_WRAPPER")
+load("@vs_config//:paths.bzl", _VS = "VS", _VC = "VC", _SDK = "SDK", _MSVC_TMP 
= "MSVC_TMP", _LINK_WRAPPER = "LINK_WRAPPER", _PDB_LINK = "PDB_LINK")
 
 # VS2008 x86 toolchain for Apache OpenOffice on Windows
 # Paths are configured via --repo_env=VS_PATH / --repo_env=SDK_PATH in 
user.bazelrc.
@@ -37,10 +37,16 @@ cc_toolchain_config(
     tool_bin_path  = _VC + "\\bin",
     msvc_cl_path   = _VC + "\\bin\\cl.exe",
     msvc_ml_path   = _VC + "\\bin\\ml.exe",
-    # Native cc_library/cc_binary links go through the mspdbsrv-endpoint 
wrapper
-    # (see vs_config_repo.bzl) so debug (/DEBUG) builds run parallel without
-    # LNK1318.  rules_foreign_cc still uses raw link.exe via the "ld" tool_path
-    # below (external libs build without /DEBUG, so no mspdbsrv contention).
+    # Link tool selection (see windows_cc_toolchain_config.bzl link_tools):
+    #  - generate_pdb builds (debug .pdb) link with a modern MSVC link.exe
+    #    (auto-discovered under VS_MODERN_PATH), whose mspdbsrv writes PDBs in
+    #    parallel — so /DEBUG links run at full --jobs without the VC9 LNK1318
+    #    mspdbsrv contention. It reads the VC9 /Z7 objects natively.
+    #  - all other links use VC9 link.exe (via the mspdbsrv-endpoint wrapper),
+    #    so shipped non-PDB binaries are produced by the same linker as before.
+    # rules_foreign_cc still uses raw link.exe via the "ld" tool_path below
+    # (external libs build without /DEBUG, so no mspdbsrv contention there).
+    pdb_link_path  = _PDB_LINK,
     msvc_link_path = _LINK_WRAPPER,
     msvc_lib_path  = _VC + "\\bin\\lib.exe",
     cxx_builtin_include_directories = [
diff --git a/build/toolchain/windows_cc_toolchain_config.bzl 
b/build/toolchain/windows_cc_toolchain_config.bzl
index 0a26698240..85924bb390 100644
--- a/build/toolchain/windows_cc_toolchain_config.bzl
+++ b/build/toolchain/windows_cc_toolchain_config.bzl
@@ -146,6 +146,24 @@ def _impl(ctx):
         ]
 
     if _use_msvc_toolchain(ctx):
+        # Linker tool selection for the executable / dynamic-library link 
actions.
+        # When the generate_pdb feature is enabled (debug builds that emit 
.pdb),
+        # Bazel runs a modern MSVC link.exe (pdb_link_path, auto-discovered 
from a
+        # VS2017+/BuildTools install). The VC9 linker's single mspdbsrv cannot
+        # write PDBs in parallel (LNK1318 0x6BA; VC9 has no /FS), while a 
modern
+        # link.exe reads the VC9 /Z7 objects natively and its mspdbsrv handles
+        # parallel PDB writes — so debug builds run at full --jobs. (LLVM 
lld-link
+        # was rejected: it cannot emit PDBs from VC9-era CodeView.) Every other
+        # link stays on VC9 link.exe so shipped (non-PDB) binaries are 
produced by
+        # the same linker as before. Bazel selects the first tool whose
+        # with_features set matches the active feature configuration.
+        link_tools = [
+            tool(
+                path = ctx.attr.pdb_link_path,
+                with_features = [with_feature_set(features = 
["generate_pdb"])],
+            ),
+            tool(path = ctx.attr.msvc_link_path),
+        ]
         cpp_link_nodeps_dynamic_library_action = action_config(
             action_name = ACTION_NAMES.cpp_link_nodeps_dynamic_library,
             implies = [
@@ -162,7 +180,7 @@ def _impl(ctx):
                 "has_configured_linker_path",
                 "def_file",
             ],
-            tools = [tool(path = ctx.attr.msvc_link_path)],
+            tools = link_tools,
         )
 
         cpp_link_static_library_action = action_config(
@@ -256,7 +274,7 @@ def _impl(ctx):
                 "msvc_env",
                 "no_stripping",
             ],
-            tools = [tool(path = ctx.attr.msvc_link_path)],
+            tools = link_tools,
         )
 
         cpp_link_dynamic_library_action = action_config(
@@ -275,7 +293,7 @@ def _impl(ctx):
                 "has_configured_linker_path",
                 "def_file",
             ],
-            tools = [tool(path = ctx.attr.msvc_link_path)],
+            tools = link_tools,
         )
 
         deps_scanner = "cpp-module-deps-scanner_not_found"
@@ -1366,7 +1384,14 @@ def _impl(ctx):
             flag_sets = [
                 flag_set(
                     actions = all_link_actions,
-                    flag_groups = [flag_group(flags = ["/DEBUG"])],
+                    # /DEBUG: emit the separate .pdb.
+                    # /SAFESEH:NO: this feature routes links through lld-link 
(see
+                    # link_tools), which — unlike VC9 link.exe — enforces 
/safeseh
+                    # on x86 and rejects data-only objects that carry no SEH 
table
+                    # (e.g. ICU's icudt49_dat.obj). SafeSEH is a ship-time 
mitigation
+                    # and these are non-distributed debug binaries, so 
disabling it
+                    # here is harmless and only affects the generate_pdb path.
+                    flag_groups = [flag_group(flags = ["/DEBUG", 
"/SAFESEH:NO"])],
                 ),
             ],
         )
@@ -1825,6 +1850,7 @@ This is only offered as a migration bridge for projects 
transitioning to rule-ba
         "msvc_lib_path": attr.string(default = "vc_installation_error.bat"),
         "msvc_link_path": attr.string(default = "vc_installation_error.bat"),
         "msvc_ml_path": attr.string(default = "vc_installation_error.bat"),
+        "pdb_link_path": attr.string(default = "vc_installation_error.bat"),
         "shorten_virtual_includes": attr.bool(default = False),
         "supports_parse_showincludes": attr.bool(),
         "target_libc": attr.string(),
diff --git a/build/vs_config_repo.bzl b/build/vs_config_repo.bzl
index e1f283af06..df0fb7dbc8 100644
--- a/build/vs_config_repo.bzl
+++ b/build/vs_config_repo.bzl
@@ -7,9 +7,19 @@ flag value so bazelrc doesn't strip backslashes):
   build --repo_env="SDK_PATH=C:/Program Files/Microsoft SDKs/Windows/v7.0"
   build --repo_env="MSVC_TMP=C:/Users/<you>/AppData/Local/Temp"
   build --repo_env="PERL_PATH=C:/msys64/usr/bin/perl.exe"
+  build --repo_env="VS_MODERN_PATH=C:/Program Files (x86)/Microsoft Visual 
Studio/2019/BuildTools"
 
 The generated @vs_config//:paths.bzl exposes VS, VC, SDK, MSVC_TMP,
-PERL, DEBUG_CRT_DIR, and LINK_WRAPPER.
+PERL, DEBUG_CRT_DIR, LINK_WRAPPER, and PDB_LINK.
+
+PDB_LINK is a modern MSVC link.exe (auto-discovered under VS_MODERN_PATH).
+The C++ toolchain routes generate_pdb (debug .pdb) links to it instead of
+VC9 link.exe: the VC9 linker's single mspdbsrv cannot write PDBs in parallel
+(LNK1318 0x6BA, no /FS), while a modern link.exe reads the VC9 /Z7 objects
+natively and its mspdbsrv handles parallel PDB writes — so debug builds run
+at full --jobs.  (LLVM lld-link was evaluated and rejected: it cannot write
+PDBs from VC9-era CodeView — "Stream too short".)  Non-PDB links stay on VC9
+link.exe via LINK_WRAPPER, below, so shipped binaries are unchanged.
 
 LINK_WRAPPER is a generated batch file that wraps link.exe and gives every
 link action its own _MSPDBSRV_ENDPOINT_ (derived from the unique per-target
@@ -19,28 +29,70 @@ LNK1318 RPC_S_SERVER_UNAVAILABLE (0x6BA), which is the only 
reason debug builds
 ever needed --jobs=1.  Routing all links through the wrapper lets debug builds
 run fully parallel.  VS2008/VC9 has no /FS flag (added in VS2013), so the
 per-process endpoint is the only fix available here.
+
+Endpoint isolation prevents shared-server *corruption*, but each isolated link
+must still spawn its own mspdbsrv.exe, and a wide parallel link phase can still
+transiently lose the RPC handshake (LNK1318 0x6BA) when many servers start at
+once.  So the wrapper also retries link.exe on LNK1318 with a linear backoff,
+handing each attempt a *fresh* endpoint (…_a1, _a2, …) so a retry never
+reconnects to a half-dead server from the previous try.  Non-PDB link errors
+(unresolved externals, etc.) are detected and returned immediately without
+wasting retries.  Tunable via LINK_MAX_RETRY / LINK_RETRY_BASE_SEC env vars.
 """
 
 _DEFAULT_VS   = "C:\\Program Files (x86)\\Microsoft Visual Studio 9.0"
 _DEFAULT_SDK  = "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0"
 _DEFAULT_TMP  = "C:\\Temp"
 _DEFAULT_PERL = "C:\\msys64\\usr\\bin\\perl.exe"
+# Modern MSVC (VS2017+/BuildTools) install root — only used to source a newer
+# link.exe for the generate_pdb path (see _find_modern_link / PDB_LINK below).
+_DEFAULT_VS_MODERN = "C:\\Program Files (x86)\\Microsoft Visual 
Studio\\2019\\BuildTools"
+
+def _find_modern_link(rctx, vs_modern):
+    """Locate the newest VS2017+ x86-target link.exe under a BuildTools/VS 
root.
+
+    The VC9 link.exe cannot write PDBs in parallel (single mspdbsrv, no /FS, 
the
+    LNK1318 bug); LLVM lld-link cannot write PDBs from VC9-era CodeView at all
+    ("Stream too short"). A modern MSVC link.exe reads the VC9 /Z7 objects 
natively
+    and its mspdbsrv handles parallel PDB writes, so the generate_pdb link path
+    uses it. Returns a placeholder if none is found (only breaks generate_pdb 
builds).
+    """
+    tools = rctx.path(vs_modern + "\\VC\\Tools\\MSVC")
+    if not tools.exists:
+        return "modern_link_not_found.bat"
+    best = None
+    for ver in tools.readdir():
+        for host in ["Hostx64", "Hostx86"]:
+            link = 
ver.get_child("bin").get_child(host).get_child("x86").get_child("link.exe")
+            if link.exists:
+                if best == None or ver.basename > best[0]:
+                    best = (ver.basename, str(link))
+                break
+    if best == None:
+        return "modern_link_not_found.bat"
+    return best[1]
 
 def _vs_config_impl(rctx):
     vs   = rctx.os.environ.get("VS_PATH",   _DEFAULT_VS)
     sdk  = rctx.os.environ.get("SDK_PATH",  _DEFAULT_SDK)
     tmp  = rctx.os.environ.get("MSVC_TMP",  _DEFAULT_TMP)
     perl = rctx.os.environ.get("PERL_PATH", _DEFAULT_PERL)
+    vs_modern = rctx.os.environ.get("VS_MODERN_PATH", _DEFAULT_VS_MODERN)
     vc   = vs + "\\VC"
+    pdb_link = _find_modern_link(rctx, vs_modern)
     debug_crt = vc + "\\redist\\Debug_NonRedist\\x86\\Microsoft.VC90.DebugCRT"
 
     def q(p):
         return p.replace("\\", "\\\\")
 
     # link.exe wrapper: per-action _MSPDBSRV_ENDPOINT_ so concurrent /DEBUG 
links
-    # each get a private mspdbsrv.exe instead of sharing one (LNK1318 0x6BA).
+    # each get a private mspdbsrv.exe instead of sharing one (LNK1318 0x6BA), 
plus
+    # a bounded retry-with-backoff on LNK1318 (fresh endpoint per attempt) for 
the
+    # residual "server unavailable" that isolation alone can't prevent.
     # The endpoint is derived from the linker @param-file name (unique per 
target,
     # always on the command line); falls back to %RANDOM% if no @file is 
present.
+    # Output is captured so we can tell a transient PDB failure (retry) from a 
real
+    # link error (return immediately).  Dynamic wait grows linearly per 
attempt.
     link_exe = vc + "\\bin\\link.exe"
     bat = "\r\n".join([
         "@echo off",
@@ -56,9 +108,32 @@ def _vs_config_impl(rctx):
         "set \"ep=!ep:/=_!\"",
         "set \"ep=!ep:.=_!\"",
         "set \"ep=!ep::=_!\"",
-        "set \"_MSPDBSRV_ENDPOINT_=bzl_!ep!\"",
-        "\"" + link_exe + "\" %*",
-        "exit /b !ERRORLEVEL!",
+        # Tunables (override via --action_env at build time), with sane 
defaults.
+        "if not defined LINK_MAX_RETRY set \"LINK_MAX_RETRY=5\"",
+        "if not defined LINK_RETRY_BASE_SEC set \"LINK_RETRY_BASE_SEC=2\"",
+        "set \"log=%TEMP%\\bzl_link_%RANDOM%%RANDOM%.log\"",
+        "set \"n=0\"",
+        ":retry",
+        "set /a n+=1",
+        # Fresh endpoint each attempt so a retry spawns a brand-new 
mspdbsrv.exe
+        # instead of reconnecting to a hung/half-dead one from the previous 
try.
+        "set \"_MSPDBSRV_ENDPOINT_=bzl_!ep!_a!n!\"",
+        "\"" + link_exe + "\" %* > \"!log!\" 2>&1",
+        "set \"rc=!ERRORLEVEL!\"",
+        "if !rc! equ 0 goto done",
+        # Only LNK1318 (PDB RPC) is transient; anything else is a real failure.
+        "findstr /c:\"LNK1318\" \"!log!\" >nul",
+        "if errorlevel 1 goto done",
+        "if !n! geq !LINK_MAX_RETRY! goto done",
+        "set /a wait=!n!*!LINK_RETRY_BASE_SEC!",
+        "set /a pings=!wait!+1",
+        "echo [msvc_link] LNK1318 PDB RPC error; retry !n!/!LINK_MAX_RETRY! 
after !wait!s (endpoint bzl_!ep!_a!n!)>&2",
+        "ping -n !pings! 127.0.0.1 >nul",
+        "goto retry",
+        ":done",
+        "type \"!log!\"",
+        "del \"!log!\" >nul 2>&1",
+        "exit /b !rc!",
         "",
     ])
     rctx.file("msvc_link.bat", bat)
@@ -74,6 +149,7 @@ def _vs_config_impl(rctx):
         'PERL     = "{}"'.format(q(perl)),
         'DEBUG_CRT_DIR = "{}"'.format(q(debug_crt)),
         'LINK_WRAPPER = "{}"'.format(q(link_wrapper)),
+        'PDB_LINK = "{}"'.format(q(pdb_link)),
         "",
     ])
     rctx.file("paths.bzl", content)
@@ -81,5 +157,5 @@ def _vs_config_impl(rctx):
 
 vs_config_repo = repository_rule(
     implementation = _vs_config_impl,
-    environ = ["VS_PATH", "SDK_PATH", "MSVC_TMP", "PERL_PATH"],
+    environ = ["VS_PATH", "SDK_PATH", "MSVC_TMP", "PERL_PATH", 
"VS_MODERN_PATH"],
 )

Reply via email to