Skip to content

Commit 674e734

Browse files
committed
basic windows impl
1 parent 393dcfd commit 674e734

2 files changed

Lines changed: 94 additions & 16 deletions

File tree

python/private/zipapp/py_zipapp_rule.bzl

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,56 @@
11
"""Implementation of the zipapp rules."""
22

33
load("@bazel_skylib//lib:paths.bzl", "paths")
4+
load("@rules_python_internal//:rules_python_config.bzl", rp_config = "config")
45
load("//python/private:attributes.bzl", "apply_config_settings_attr")
56
load("//python/private:builders.bzl", "builders")
6-
load("//python/private:common.bzl", "BUILTIN_BUILD_PYTHON_ZIP", "actions_run", "maybe_builtin_build_python_zip", "maybe_create_repo_mapping", "runfiles_root_path")
7+
load("//python/private:common.bzl", "BUILTIN_BUILD_PYTHON_ZIP", "actions_run", "maybe_builtin_build_python_zip", "maybe_create_repo_mapping", "runfiles_root_path", "target_platform_has_any_constraint")
78
load("//python/private:common_labels.bzl", "labels")
89
load("//python/private:py_executable_info.bzl", "PyExecutableInfo")
910
load("//python/private:py_internal.bzl", "py_internal")
1011
load("//python/private:py_runtime_info.bzl", "PyRuntimeInfo")
1112
load("//python/private:toolchain_types.bzl", "EXEC_TOOLS_TOOLCHAIN_TYPE")
1213
load("//python/private:transition_labels.bzl", "TRANSITION_LABELS")
1314

15+
_LAUNCHER_MAKER_TOOLCHAIN_TYPE = "@bazel_tools//tools/launcher:launcher_maker_toolchain_type"
16+
17+
def _find_launcher_maker(ctx):
18+
if rp_config.bazel_9_or_later:
19+
return (ctx.toolchains[_LAUNCHER_MAKER_TOOLCHAIN_TYPE].binary, _LAUNCHER_MAKER_TOOLCHAIN_TYPE)
20+
return (ctx.executable._windows_launcher_maker, None)
21+
22+
def _create_windows_exe_launcher(
23+
ctx,
24+
*,
25+
output,
26+
python_binary_path,
27+
use_zip_file):
28+
launch_info = ctx.actions.args()
29+
launch_info.use_param_file("%s", use_always = True)
30+
launch_info.set_param_file_format("multiline")
31+
launch_info.add("binary_type=Python")
32+
launch_info.add(ctx.workspace_name, format = "workspace_name=%s")
33+
launch_info.add(
34+
"1" if py_internal.runfiles_enabled(ctx) else "0",
35+
format = "symlink_runfiles_enabled=%s",
36+
)
37+
launch_info.add(python_binary_path, format = "python_bin_path=%s")
38+
launch_info.add("1" if use_zip_file else "0", format = "use_zip_file=%s")
39+
40+
launcher = ctx.attr._launcher[DefaultInfo].files_to_run.executable
41+
executable, toolchain = _find_launcher_maker(ctx)
42+
ctx.actions.run(
43+
executable = executable,
44+
arguments = [launcher.path, launch_info, output.path],
45+
inputs = [launcher],
46+
outputs = [output],
47+
mnemonic = "PyBuildLauncher",
48+
progress_message = "Creating launcher for %{label}",
49+
# Needed to inherit PATH when using non-MSVC compilers like MinGW
50+
use_default_shell_env = True,
51+
toolchain = toolchain,
52+
)
53+
1454
def _is_symlink(f):
1555
if hasattr(f, "is_symlink"):
1656
return str(int(f.is_symlink))
@@ -184,20 +224,39 @@ def _py_zipapp_executable_impl(ctx):
184224

185225
zip_file = _create_zip(ctx, py_runtime, py_executable, stage2_bootstrap)
186226
if ctx.attr.executable:
187-
preamble = _create_shell_bootstrap(ctx, py_runtime, py_executable, stage2_bootstrap)
188-
executable = _create_self_executable_zip(ctx, preamble, zip_file)
189-
default_output = executable
227+
if target_platform_has_any_constraint(ctx, ctx.attr._windows_constraints):
228+
executable = ctx.actions.declare_file(ctx.label.name + ".exe")
229+
230+
python_exe = py_executable.venv_python_exe
231+
if python_exe:
232+
python_exe_path = runfiles_root_path(ctx, python_exe.short_path)
233+
elif py_runtime.interpreter:
234+
python_exe_path = runfiles_root_path(ctx, py_runtime.interpreter.short_path)
235+
else:
236+
python_exe_path = py_runtime.interpreter_path
237+
238+
_create_windows_exe_launcher(
239+
ctx,
240+
output = executable,
241+
python_binary_path = python_exe_path,
242+
use_zip_file = True,
243+
)
244+
default_output = depset([executable, zip_file])
245+
else:
246+
preamble = _create_shell_bootstrap(ctx, py_runtime, py_executable, stage2_bootstrap)
247+
executable = _create_self_executable_zip(ctx, preamble, zip_file)
248+
default_output = depset([executable])
190249
else:
191250
# Bazel requires executable=True rules to have an executable given, so give
192251
# a fake one to satisfy that.
193-
default_output = zip_file
252+
default_output = depset([zip_file])
194253
executable = ctx.actions.declare_file(ctx.label.name + "-not-executable")
195254
ctx.actions.write(executable, "echo 'ERROR: Non executable zip file'; exit 1")
196255

197256
return [
198257
DefaultInfo(
199-
files = depset([default_output]),
200-
runfiles = ctx.runfiles(files = [default_output]),
258+
files = default_output,
259+
runfiles = ctx.runfiles(files = default_output.to_list()),
201260
executable = executable,
202261
),
203262
]
@@ -277,6 +336,18 @@ Whether the output should be an executable zip file.
277336
cfg = "exec",
278337
default = "//tools/private/zipapp:exe_zip_maker",
279338
),
339+
"_launcher": attr.label(
340+
cfg = "target",
341+
# NOTE: This is an executable, but is only used for Windows. It
342+
# can't have executable=True because the backing target is an
343+
# empty target for other platforms.
344+
default = "//tools/launcher:launcher",
345+
),
346+
"_windows_constraints": attr.label_list(
347+
default = [
348+
"@platforms//os:windows",
349+
],
350+
),
280351
"_zip_shell_template": attr.label(
281352
default = ":zip_shell_template",
282353
allow_single_file = True,
@@ -285,8 +356,15 @@ Whether the output should be an executable zip file.
285356
cfg = "exec",
286357
default = "//tools/private/zipapp:zipper",
287358
),
288-
}
289-
_TOOLCHAINS = [EXEC_TOOLS_TOOLCHAIN_TYPE]
359+
} | ({
360+
"_windows_launcher_maker": attr.label(
361+
default = "@bazel_tools//tools/launcher:launcher_maker",
362+
cfg = "exec",
363+
executable = True,
364+
),
365+
} if not rp_config.bazel_9_or_later else {})
366+
367+
_TOOLCHAINS = [EXEC_TOOLS_TOOLCHAIN_TYPE] + ([_LAUNCHER_MAKER_TOOLCHAIN_TYPE] if rp_config.bazel_9_or_later else [])
290368

291369
py_zipapp_binary = rule(
292370
doc = """

tests/py_zipapp/BUILD.bazel

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ py_binary(
1616
"//python/config_settings:venvs_site_packages": "yes",
1717
},
1818
main = "main.py",
19-
target_compatible_with = NOT_WINDOWS,
19+
##target_compatible_with = NOT_WINDOWS,
2020
deps = ["@dev_pip//absl_py"],
2121
)
2222

2323
py_zipapp_binary(
2424
name = "venv_zipapp",
2525
binary = ":venv_bin",
26-
target_compatible_with = NOT_WINDOWS,
26+
##target_compatible_with = NOT_WINDOWS,
2727
)
2828

2929
py_test(
@@ -34,7 +34,7 @@ py_test(
3434
"BZLMOD_ENABLED": str(int(BZLMOD_ENABLED)),
3535
"TEST_ZIPAPP": "$(location :venv_zipapp)",
3636
},
37-
target_compatible_with = NOT_WINDOWS,
37+
##target_compatible_with = NOT_WINDOWS,
3838
)
3939

4040
py_binary(
@@ -46,14 +46,14 @@ py_binary(
4646
},
4747
main = "main.py",
4848
# TODO: #2586 - Add windows support
49-
target_compatible_with = NOT_WINDOWS,
50-
deps = ["@dev_pip//absl_py"],
49+
##target_compatible_with = NOT_WINDOWS,
50+
##deps = ["@dev_pip//absl_py"],
5151
)
5252

5353
py_zipapp_binary(
5454
name = "system_python_zipapp",
5555
binary = ":system_python_bin",
56-
target_compatible_with = NOT_WINDOWS,
56+
##target_compatible_with = NOT_WINDOWS,
5757
)
5858

5959
py_test(
@@ -63,5 +63,5 @@ py_test(
6363
env = {
6464
"TEST_ZIPAPP": "$(location :system_python_zipapp)",
6565
},
66-
target_compatible_with = NOT_WINDOWS,
66+
##target_compatible_with = NOT_WINDOWS,
6767
)

0 commit comments

Comments
 (0)