@@ -194,6 +194,10 @@ accepting arbitrary Python versions.
194194 allow_single_file = True ,
195195 default = "@bazel_tools//tools/python:python_bootstrap_template.txt" ,
196196 ),
197+ "_main_module_entrypoint_template" : lambda : attrb .Label (
198+ allow_single_file = True ,
199+ default = "//python/private:main_module_entrypoint_template.py" ,
200+ ),
197201 "_launcher" : lambda : attrb .Label (
198202 cfg = "target" ,
199203 # NOTE: This is an executable, but is only used for Windows. It
@@ -360,9 +364,8 @@ def _create_executable(
360364 )
361365 else :
362366 stage2_bootstrap = None
363- extra_runfiles = ctx .runfiles ()
364367 zip_main = ctx .actions .declare_file (base_executable_name + ".temp" , sibling = executable )
365- _create_stage1_bootstrap (
368+ extra_runfiles = _create_stage1_bootstrap (
366369 ctx ,
367370 output = zip_main ,
368371 main_py = main_py ,
@@ -426,16 +429,17 @@ def _create_executable(
426429 if bootstrap_output != None :
427430 fail ("Should not occur: bootstrap_output should not be used " +
428431 "when creating an executable zip" )
429- _create_executable_zip_file (
432+ more_runfiles = _create_executable_zip_file (
430433 ctx ,
431434 output = executable ,
432435 zip_file = zip_file ,
433436 stage2_bootstrap = stage2_bootstrap ,
434437 runtime_details = runtime_details ,
435438 venv = venv ,
436439 )
440+ extra_runfiles = extra_runfiles .merge (more_runfiles )
437441 elif bootstrap_output :
438- _create_stage1_bootstrap (
442+ more_runfiles = _create_stage1_bootstrap (
439443 ctx ,
440444 output = bootstrap_output ,
441445 stage2_bootstrap = stage2_bootstrap ,
@@ -445,6 +449,7 @@ def _create_executable(
445449 main_py = main_py ,
446450 venv = venv ,
447451 )
452+ extra_runfiles = extra_runfiles .merge (more_runfiles )
448453 else :
449454 # Otherwise, this should be the Windows case of launcher + zip.
450455 # Double check this just to make sure.
@@ -796,6 +801,7 @@ def _create_stage1_bootstrap(
796801 is_for_zip ,
797802 runtime_details ,
798803 venv = None ):
804+ extra_runfiles = ctx .runfiles ()
799805 runtime = runtime_details .effective_runtime
800806
801807 if venv :
@@ -833,9 +839,10 @@ def _create_stage1_bootstrap(
833839 )
834840 template = runtime .bootstrap_template
835841 subs ["%shebang%" ] = runtime .stub_shebang
836- elif not ctx .files .srcs :
837- fail ("mandatory 'srcs' files have not been provided" )
838842 else :
843+ if not ctx .files .srcs and not ctx .attr .main_module :
844+ fail ("mandatory 'srcs' files have not been provided" )
845+
839846 if (ctx .configuration .coverage_enabled and
840847 runtime and
841848 runtime .coverage_tool ):
@@ -855,6 +862,20 @@ def _create_stage1_bootstrap(
855862 subs ["%coverage_tool%" ] = coverage_tool_runfiles_path
856863 subs ["%import_all%" ] = ("True" if ctx .fragments .bazel_py .python_import_all_repositories else "False" )
857864 subs ["%imports%" ] = ":" .join (imports .to_list ())
865+
866+ if ctx .attr .main_module :
867+ main_module_entrypoint = ctx .actions .declare_file ("main_module_entrypoint.py" )
868+ ctx .actions .expand_template (
869+ template = ctx .file ._main_module_entrypoint_template ,
870+ output = main_module_entrypoint ,
871+ substitutions = {"%main_module%" : ctx .attr .main_module }
872+ )
873+ main_py = main_module_entrypoint
874+ extra_runfiles = extra_runfiles .merge (ctx .runfiles ([main_module_entrypoint ]))
875+ else :
876+ # shouldn't happen
877+ fail ("Neither main nor main_module was provided" )
878+
858879 subs ["%main%" ] = "{}/{}" .format (ctx .workspace_name , main_py .short_path )
859880
860881 ctx .actions .expand_template (
@@ -863,6 +884,8 @@ def _create_stage1_bootstrap(
863884 substitutions = subs ,
864885 )
865886
887+ return extra_runfiles
888+
866889def _create_windows_exe_launcher (
867890 ctx ,
868891 * ,
@@ -985,7 +1008,7 @@ def _create_executable_zip_file(
9851008 sibling = output ,
9861009 )
9871010 if stage2_bootstrap :
988- _create_stage1_bootstrap (
1011+ extra_runfiles = _create_stage1_bootstrap (
9891012 ctx ,
9901013 output = prelude ,
9911014 stage2_bootstrap = stage2_bootstrap ,
@@ -994,6 +1017,7 @@ def _create_executable_zip_file(
9941017 venv = venv ,
9951018 )
9961019 else :
1020+ extra_runfiles = ctx .runfiles ()
9971021 ctx .actions .write (prelude , "#!/usr/bin/env python3\n " )
9981022
9991023 ctx .actions .run_shell (
@@ -1009,6 +1033,8 @@ def _create_executable_zip_file(
10091033 progress_message = "Build Python zip executable: %{label}" ,
10101034 )
10111035
1036+ return extra_runfiles
1037+
10121038def _get_cc_details_for_binary (ctx , extra_deps ):
10131039 cc_info = collect_cc_info (ctx , extra_deps = extra_deps )
10141040 return create_cc_details_struct (
0 commit comments