diff --git a/bazel/MODULE.bazel.lock b/bazel/MODULE.bazel.lock index 60af7d73b2..f3ca37f37f 100644 --- a/bazel/MODULE.bazel.lock +++ b/bazel/MODULE.bazel.lock @@ -333,8 +333,8 @@ }, "//compile:extensions.bzl%libcxx_libs_extension": { "general": { - "bzlTransitiveDigest": "BTuyHAmPV6RLjmwYvHgt5sqEor5vYxcSNJW+rLVnLU4=", - "usagesDigest": "xm1WJBa3RDcHXWZqP+u1kihkP4aKA0K6N/umZp2Wd7U=", + "bzlTransitiveDigest": "xq4mUY6BVQnnWqOzX/XORJO7GVFn1zwGLk82OjEZLF4=", + "usagesDigest": "RIkUSFV80yIb144efeISdWNXBS3AN1AgryPVfPEqm7E=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -342,7 +342,7 @@ "libcxx_libs_aarch64": { "repoRuleId": "@@//compile:libcxx_libs.bzl%libcxx_libs", "attributes": { - "version": "0.2.7", + "version": "0.2.8", "sha256": "b3bd8dfc1c250d5c2c36de174138ffef9754402b33e54abe9b5efb25982fa2f7", "arch": "aarch64" } @@ -350,7 +350,7 @@ "libcxx_libs_x86_64": { "repoRuleId": "@@//compile:libcxx_libs.bzl%libcxx_libs", "attributes": { - "version": "0.2.7", + "version": "0.2.8", "sha256": "e40f39338ffe561dfa26541557c9e548fc7760db9d99f7b6c5de237b725482aa", "arch": "x86_64" } @@ -400,8 +400,8 @@ }, "//compile:extensions.bzl%llvm_minimal_extension": { "general": { - "bzlTransitiveDigest": "BTuyHAmPV6RLjmwYvHgt5sqEor5vYxcSNJW+rLVnLU4=", - "usagesDigest": "zTRetCqgCTR/JYUTsNeIov/5K+KNmJAxmPtAfB+35B4=", + "bzlTransitiveDigest": "xq4mUY6BVQnnWqOzX/XORJO7GVFn1zwGLk82OjEZLF4=", + "usagesDigest": "Q+CKSP0adR7YFwQRyGmwMLzUFi/fI4mpjnKPqgG4qPE=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -409,24 +409,24 @@ "llvm_minimal_linux_x64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.7/llvm-minimal-22.1.8-Linux-X64.tar.zst", - "sha256": "3055f223cb27740e319412303c8298787b78062839d8809b88b13c4d6bcd82ca", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.8/llvm-minimal-22.1.8-Linux-X64.tar.zst", + "sha256": "6cb4cca6df33be00c80fa1639062c973d1cafe4e7ad98a9b4bdf21bf9dec5806", "strip_prefix": "llvm-minimal-22.1.8-Linux-X64" } }, "llvm_minimal_linux_arm64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.7/llvm-minimal-22.1.8-Linux-ARM64.tar.zst", - "sha256": "b00ea67259e613907da30cb5d8290192b54ab656f4759ace6794f3e10de1d0ed", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.8/llvm-minimal-22.1.8-Linux-ARM64.tar.zst", + "sha256": "9a6cc0a84d524342e578db739b04e8a3875adb40b38887e4e074661e925f8a9c", "strip_prefix": "llvm-minimal-22.1.8-Linux-ARM64" } }, "llvm_minimal_macos_arm64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.7/llvm-minimal-22.1.8-macOS-ARM64.tar.zst", - "sha256": "04a2ac21e89a42dba532509ee67c246b71ec8a15c6cef0f2d63e349fb120934c", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.8/llvm-minimal-22.1.8-macOS-ARM64.tar.zst", + "sha256": "928e51aa7c97fbb8c5c50075118f4b36e36363b1a2c3af2dfef9aea1ef526ade", "strip_prefix": "llvm-minimal-22.1.8-macOS-ARM64" } } @@ -512,8 +512,8 @@ }, "//sysroot:extensions.bzl%sysroot_extension": { "general": { - "bzlTransitiveDigest": "8mBbKuC9X+dVsJfKM+AgJFJoBBNzOGVJZxdCfSxLqq0=", - "usagesDigest": "wKAMwdm/oEYUzhed5dKuDJChGeMSDIyTPv9j0p3ta18=", + "bzlTransitiveDigest": "PF3oNYod5GkYA2DCs46F5a8BkZbFeJLt6wv1gZYWk30=", + "usagesDigest": "QuvSVj2nF2HTzMnymPuZHLvRfdfCftaYggoWoY1FCyo=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -521,8 +521,8 @@ "sysroot_linux_amd64": { "repoRuleId": "@@//sysroot:sysroot.bzl%sysroot", "attributes": { - "version": "0.2.7", - "sha256": "fe05fe5200c2854286f5d7c5680fa05d203bf9de247b6df8d4994945743c94ff", + "version": "0.2.8", + "sha256": "63b6ff808f87b03fefb695941906e419b8f88f8e27150b3e2007dbc0012b78a8", "arch": "amd64", "glibc_version": "2.31", "stdcc_version": "13" @@ -531,8 +531,8 @@ "sysroot_linux_arm64": { "repoRuleId": "@@//sysroot:sysroot.bzl%sysroot", "attributes": { - "version": "0.2.7", - "sha256": "7a2781b72d55a178f57bb637b4c1e11f2703f2c8e6af221fc48c427f044aa839", + "version": "0.2.8", + "sha256": "8f3847a6a5147dd5c13c92914f009c38792dbe82196a77187bc284b937c0cc6c", "arch": "arm64", "glibc_version": "2.31", "stdcc_version": "13" @@ -544,8 +544,8 @@ }, "//v8:extensions.bzl%wee8_prebuilt_extension": { "general": { - "bzlTransitiveDigest": "3XVk7hxXkbm3MI5PCrruGa7H/eKm1U3zjVGWrvQLw4Q=", - "usagesDigest": "G3ksytQP2i8GCDK2aPOHdeCILz9E6+K7AK5dsV7Mi3g=", + "bzlTransitiveDigest": "gHfQ5XAztuVD/qC/C7BjzVSDMcAdCb/wGta8N4MEJ0E=", + "usagesDigest": "qtgEPyqlaewbvM4bt1SZIGrtGJ58GcpfmXLpk1VMdL8=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -553,8 +553,8 @@ "wee8_prebuilt_x86_64": { "repoRuleId": "@@//v8:wee8_prebuilt.bzl%wee8_prebuilt", "attributes": { - "version": "0.2.7", - "sha256": "4bb306264d85dc629e7bb03ede97064de6c2e6452044ef6e528f7e319f51d482", + "version": "0.2.8", + "sha256": "96e3146e68dc2d1ae299ba5845c2a9edb2cb3dfe64fbedbcc77b339a95061d80", "arch": "x86_64", "stdlib": "libcxx" } @@ -562,8 +562,8 @@ "wee8_prebuilt_x86_64_libstdcxx": { "repoRuleId": "@@//v8:wee8_prebuilt.bzl%wee8_prebuilt", "attributes": { - "version": "0.2.7", - "sha256": "9a92188a27c2b8f8ac0ff2548c259bd1ce375431af6ee7b67626d22745bd0f8a", + "version": "0.2.8", + "sha256": "874a66ebf631f13189b30179fceb232fabde59f8ca6a47b6a1a82d04db9afeee", "arch": "x86_64", "stdlib": "libstdcxx" } @@ -571,8 +571,8 @@ "wee8_prebuilt_aarch64": { "repoRuleId": "@@//v8:wee8_prebuilt.bzl%wee8_prebuilt", "attributes": { - "version": "0.2.7", - "sha256": "9c4ce19dd446f62791979e4cd03c2da4df43d035479820db5a4a35aee605c3d8", + "version": "0.2.8", + "sha256": "cacd8cf4b17bba81dc2a506b21c7314fcedb0fc6507c581dbc6c4827a9994cf5", "arch": "aarch64", "stdlib": "libcxx" } diff --git a/bazel/v8/wee8_package.bzl b/bazel/v8/wee8_package.bzl index 1cbac22d29..4f79d4d867 100644 --- a/bazel/v8/wee8_package.bzl +++ b/bazel/v8/wee8_package.bzl @@ -80,49 +80,35 @@ _TRANSITION_ATTRS = { # ── Fat archive ────────────────────────────────────────────────────────────── -# argv[1] archiver executable (from the resolved cc toolchain) -# argv[2] output libwee8.a path -# argv[3..] PIC static libraries to merge +# argv[1] archiver executable (from the resolved cc toolchain) +# argv[2] output libwee8.a path +# argv[3] params file listing one execroot-relative object path per line # -# `ar x --output=DIR` is a GNU binutils >=2.36 extension that llvm-ar does not -# support, so extract by cd'ing into a per-lib directory instead. Input paths -# are execroot-relative, so they must be made absolute before the cd. +# We archive the object files DIRECTLY rather than extracting the deps' `.a`/`.lo` +# archives and re-archiving. V8 emits many objects that share a basename (e.g. two +# `heap.pic.o`, two `factory.pic.o`, two `allocation.pic.o`, from same-named +# sources in different directories). Archive members are stored by basename, so +# extracting to the filesystem (`ar x`) makes the second `heap.pic.o` clobber the +# first, silently dropping one object of each colliding pair and every symbol it +# defined (Factory::NewSymbol, Heap::CollectAllGarbage, VirtualMemory::~…, PrintF, +# …). The distinct object Files have distinct on-disk paths, so archiving them +# straight into libwee8.a keeps both. The result carries duplicate member +# basenames, exactly like V8's own `.lo`, which links correctly because the linker +# reads members by content, not by filesystem name. `@file` avoids ARG_MAX with +# ~1200 objects; both llvm-ar and GNU ar expand it. _ARCHIVE_SCRIPT = r""" set -e -o pipefail AR="$PWD/$1" OUT="$2" -shift 2 - -EXECROOT="$PWD" -TMPDIR="$(mktemp -d)" -trap 'rm -rf "$TMPDIR"' EXIT - -n=0 -i=0 -for lib in "$@"; do - i=$((i+1)) - subdir="$TMPDIR/lib_${i}" - mkdir -p "$subdir" - (cd "$subdir" && "$AR" x "$EXECROOT/$lib") - - while IFS= read -r obj; do - [ -n "$obj" ] || continue - if [ ! -f "$subdir/$obj" ]; then - echo "ERROR: expected archive member '$obj' from '$lib' not found after extraction" >&2 - exit 1 - fi - n=$((n+1)) - cp "$subdir/$obj" "$TMPDIR/o_${n}.o" - done < <("$AR" t "$EXECROOT/$lib") -done - -if [ "$n" -eq 0 ]; then - echo "ERROR: no .o files extracted from: $*" >&2 +PARAMS="$3" + +if [ ! -s "$PARAMS" ]; then + echo "ERROR: no object files to archive (empty params file)" >&2 exit 1 fi -"$AR" Drcs "$OUT" "$TMPDIR"/o_*.o +"$AR" Drcs "$OUT" "@$PARAMS" """ def _wee8_fat_archive_impl(ctx): @@ -131,24 +117,48 @@ def _wee8_fat_archive_impl(ctx): cc_info = ctx.attr.wee8[0][CcInfo] excluded = ctx.attr.exclude_lib_prefixes - # Collect PIC static libraries from transitive linker inputs. - # abseil-cpp and icu are provided by consumers — exclude them. + # Collect the actual object files from transitive linker inputs. + # + # `exclude_lib_prefixes` is matched against each OBJECT's path. Under bzlmod + # an object lives at .../external///_objs/.../foo.pic.o, + # so the defaults ("abseil-cpp+", "icu+") are the canonical repo directory + # components — they match every abseil/icu object, not just an archive name. + # (Verified: all abseil objects contain "abseil-cpp+"; the noicu build pulls + # in zero icu objects.) abseil/icu are excluded because consumers link their + # own; bundling them would bloat libwee8.a and risk ODR/duplicate symbols. + # + # pic_objects and objects are the SAME translation units compiled two ways, + # not a partition, so taking one list is correct (both would double every + # object). We prefer PIC to match the prebuilt's PIC ABI; fall back to + # non-PIC only when a lib was built without PIC. + # + # Dedup by path (an object may appear in several linker inputs). seen = {} - pic_libs = [] + objects = [] for li in cc_info.linking_context.linker_inputs.to_list(): for lib in li.libraries: - f = lib.pic_static_library or lib.static_library - if not f or f.path in seen: - continue - seen[f.path] = True - if any([ex in f.path for ex in excluded]): + objs = lib.pic_objects if lib.pic_objects else lib.objects + if not objs: + # A dep exposing only a prebuilt archive with no object list. + # None of @v8//:wee8's current deps hit this; fail loudly rather + # than silently drop it if a future V8 bump introduces one. + f = lib.pic_static_library or lib.static_library + if f and not any([ex in f.path for ex in excluded]): + fail( + "wee8_fat_archive: library {} exposes an archive but no ".format(f.path) + + "object list; extend the rule to extract it uniquely.", + ) continue - pic_libs.append(f) + for o in objs: + if o.path in seen or any([ex in o.path for ex in excluded]): + continue + seen[o.path] = True + objects.append(o) - if not pic_libs: + if not objects: fail( - "wee8_fat_archive: no static libraries found in @v8//:wee8 deps. " + - "Verify that @v8//:wee8 is a cc_library with [pic_]static_library outputs.", + "wee8_fat_archive: no object files found in @v8//:wee8 deps. " + + "Verify that @v8//:wee8 is a cc_library exposing [pic_]objects.", ) cc_toolchain = find_cpp_toolchain(ctx) @@ -163,14 +173,20 @@ def _wee8_fat_archive_impl(ctx): action_name = ACTION_NAMES.cpp_link_static_library, ) + params = ctx.actions.declare_file("%s/libwee8.objects.params" % ctx.label.name) + # Trailing newline: llvm-ar and GNU ar both tolerate its absence, but it is + # free insurance against an archiver that expects newline-terminated entries. + ctx.actions.write(params, "\n".join([o.path for o in objects]) + "\n") + out = ctx.actions.declare_file("%s/lib/libwee8.a" % ctx.label.name) ctx.actions.run_shell( - inputs = depset(pic_libs, transitive = [cc_toolchain.all_files]), + inputs = depset(objects + [params], transitive = [cc_toolchain.all_files]), outputs = [out], command = _ARCHIVE_SCRIPT, - arguments = [ar, out.path] + [f.path for f in pic_libs], + arguments = [ar, out.path, params.path], mnemonic = "V8WeeEightArchive", - progress_message = "Creating fat libwee8.a for linux-%s (%s)" % ( + progress_message = "Creating fat libwee8.a (%d objects) for linux-%s (%s)" % ( + len(objects), ctx.attr.arch, ctx.attr.stdlib, ), @@ -189,7 +205,10 @@ wee8_fat_archive = rule( attrs = _TRANSITION_ATTRS | { "exclude_lib_prefixes": attr.string_list( default = ["abseil-cpp+", "icu+"], - doc = "Libs whose path contains any of these strings are excluded.", + doc = "Objects whose path contains any of these substrings are " + + "excluded. Defaults are the canonical bzlmod repo directory " + + "components for abseil/icu (which appear in every object path " + + "under those repos), so consumers supply their own abseil/icu.", ), "_cc_toolchain": attr.label( default = "@bazel_tools//tools/cpp:current_cc_toolchain", @@ -197,7 +216,12 @@ wee8_fat_archive = rule( }, fragments = ["cpp"], toolchains = use_cpp_toolchain(), - doc = "Merges @v8//:wee8 and its static deps into a single libwee8.a.", + doc = "Merges @v8//:wee8 and its static deps into a single libwee8.a. " + + "The archive INTENTIONALLY contains members with duplicate basenames " + + "(V8 emits same-named objects from different dirs); this is required " + + "for correctness and matches V8's own .lo. Do not 'dedup' by basename " + + "or extract-and-rearchive (`ar x`) — that clobbers members and drops " + + "symbols. `ar t` on the output is therefore ambiguous by design.", ) # ── Headers ──────────────────────────────────────────────────────────────────