Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
21 changes: 21 additions & 0 deletions bazel/patches/rules_pkg-windows-junction-copy.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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,16 @@ 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.
+ if sys.platform == "win32":
+ try:
+ target = os.readlink(src)
+ except OSError:
+ target = None
+ if target:
+ src = target
Comment thread
JSGette marked this conversation as resolved.
Outdated
# 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