Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ single_version_override(
# Temporary until rules_pkg > 1.2.0 is in BCR
archive_override(
module_name = "rules_pkg",
patch_strip = 1,
patches = [
# Windows runfiles junctions cannot point at files; follow them on copy.
"//bazel/patches:rules_pkg-windows-junction-copy.patch",
],
sha256 = "9923c6c8855b153f837a953760159908507f571b4b77cb24ed862dda1de20f90",
strip_prefix = "rules_pkg-401969d4367c42dcbb45d33a637eae87788d025e",
urls = ["https://github.com/bazelbuild/rules_pkg/archive/401969d4367c42dcbb45d33a637eae87788d025e.tar.gz"], # main as of April 22, 2026
Expand Down
8 changes: 8 additions & 0 deletions bazel/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,14 @@ local and remote execution to be configured.
All Windows developers are expected to have **Developer Mode enabled**, which grants the necessary privileges for
symlink creation without administrator elevation. The `.bazelrc` sets `--enable_runfiles` accordingly.

**Runfiles file junctions.** `--enable_runfiles` builds the runfiles tree with directory junctions. Windows junctions
cannot point at files, so a file runfile shows up as a directory (`d----l`) and `open()` fails with `Permission
denied` / `The directory name is invalid`. `pkg_install` copies from that tree, not from the MANIFEST real path;
`bazel/patches/rules_pkg-windows-junction-copy.patch` makes the copier follow the reparse point. For generated trees
that must be reachable as a directory (not file-by-file), `copy_to_directory` so the runfiles entry is one directory
junction to a real directory of real files (see `//rtloader/test:dir_with_python_home`). Prefer the runfiles library
over constructing paths under `*.runfiles`.

**No sandbox.** Windows uses `--strategy=standalone`. Builds are less hermetic by default — undeclared dependencies that
happen to be present locally will succeed locally and fail in CI or RBE.

Expand Down
15 changes: 15 additions & 0 deletions bazel/patches/rules_pkg-windows-junction-copy.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
diff --git a/pkg/private/install.py.tpl b/pkg/private/install.py.tpl
index 5242b18a..00000000 100644
--- a/pkg/private/install.py.tpl
+++ b/pkg/private/install.py.tpl
@@ -82,6 +82,10 @@ class NativeInstaller(object):
def _do_file_copy(self, src, dest):
logging.debug("COPY %s <- %s", dest, src)
+ # Windows --enable_runfiles uses directory junctions for every runfile.
+ # Junctions cannot point at files, so open() fails with Permission denied.
+ # Follow the reparse point to the real bazel-out file.
+ src = os.path.realpath(src)
# Copy to a temporary directory and then move it to the destination.
# This ensures code-signed executables on certain platforms
# behave correctly.
# See: https://developer.apple.com/documentation/security/updating-mac-software
1 change: 1 addition & 0 deletions deps/cpython.BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ pkg_filegroup(
pkg_files(
name = "install_files_win",
srcs = [":python_win"],
strip_prefix = "build",
)

# On Windows, python_win is built via MSBuild (not cc_shared_library), so there are no
Expand Down
Loading