|
16 | 16 | load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
|
17 | 17 | load(":util.bzl", "define_bazel_6_provider")
|
18 | 18 |
|
19 |
| -DEFAULT_STUB_SHEBANG = "#!/usr/bin/env python3" |
20 |
| - |
21 |
| -DEFAULT_BOOTSTRAP_TEMPLATE = Label("//python/private:bootstrap_template") |
22 |
| - |
23 |
| -_PYTHON_VERSION_VALUES = ["PY2", "PY3"] |
24 |
| - |
25 |
| -def _optional_int(value): |
26 |
| - return int(value) if value != None else None |
27 |
| - |
28 |
| -def interpreter_version_info_struct_from_dict(info_dict): |
29 |
| - """Create a struct of interpreter version info from a dict from an attribute. |
30 |
| -
|
31 |
| - Args: |
32 |
| - info_dict: (dict | None) of version info fields. See interpreter_version_info |
33 |
| - provider field docs. |
34 |
| -
|
35 |
| - Returns: |
36 |
| - struct of version info; see interpreter_version_info provider field docs. |
37 |
| - """ |
38 |
| - info_dict = dict(info_dict or {}) # Copy in case the original is frozen |
39 |
| - if info_dict: |
40 |
| - if not ("major" in info_dict and "minor" in info_dict): |
41 |
| - fail("interpreter_version_info must have at least two keys, 'major' and 'minor'") |
42 |
| - version_info_struct = struct( |
43 |
| - major = _optional_int(info_dict.pop("major", None)), |
44 |
| - minor = _optional_int(info_dict.pop("minor", None)), |
45 |
| - micro = _optional_int(info_dict.pop("micro", None)), |
46 |
| - releaselevel = str(info_dict.pop("releaselevel")) if "releaselevel" in info_dict else None, |
47 |
| - serial = _optional_int(info_dict.pop("serial", None)), |
48 |
| - ) |
49 |
| - |
50 |
| - if len(info_dict.keys()) > 0: |
51 |
| - fail("unexpected keys {} in interpreter_version_info".format( |
52 |
| - str(info_dict.keys()), |
53 |
| - )) |
54 |
| - |
55 |
| - return version_info_struct |
56 |
| - |
57 |
| -def _PyRuntimeInfo_init( |
58 |
| - *, |
59 |
| - implementation_name = None, |
60 |
| - interpreter_path = None, |
61 |
| - interpreter = None, |
62 |
| - files = None, |
63 |
| - coverage_tool = None, |
64 |
| - coverage_files = None, |
65 |
| - pyc_tag = None, |
66 |
| - python_version, |
67 |
| - stub_shebang = None, |
68 |
| - bootstrap_template = None, |
69 |
| - interpreter_version_info = None, |
70 |
| - stage2_bootstrap_template = None, |
71 |
| - zip_main_template = None): |
72 |
| - if (interpreter_path and interpreter) or (not interpreter_path and not interpreter): |
73 |
| - fail("exactly one of interpreter or interpreter_path must be specified") |
74 |
| - |
75 |
| - if interpreter_path and files != None: |
76 |
| - fail("cannot specify 'files' if 'interpreter_path' is given") |
77 |
| - |
78 |
| - if (coverage_tool and not coverage_files) or (not coverage_tool and coverage_files): |
79 |
| - fail( |
80 |
| - "coverage_tool and coverage_files must both be set or neither must be set, " + |
81 |
| - "got coverage_tool={}, coverage_files={}".format( |
82 |
| - coverage_tool, |
83 |
| - coverage_files, |
84 |
| - ), |
85 |
| - ) |
86 |
| - |
87 |
| - if python_version not in _PYTHON_VERSION_VALUES: |
88 |
| - fail("invalid python_version: '{}'; must be one of {}".format( |
89 |
| - python_version, |
90 |
| - _PYTHON_VERSION_VALUES, |
91 |
| - )) |
92 |
| - |
93 |
| - if files != None and type(files) != type(depset()): |
94 |
| - fail("invalid files: got value of type {}, want depset".format(type(files))) |
95 |
| - |
96 |
| - if interpreter: |
97 |
| - if files == None: |
98 |
| - files = depset() |
99 |
| - else: |
100 |
| - files = None |
101 |
| - |
102 |
| - if coverage_files == None: |
103 |
| - coverage_files = depset() |
104 |
| - |
105 |
| - if not stub_shebang: |
106 |
| - stub_shebang = DEFAULT_STUB_SHEBANG |
107 |
| - |
108 |
| - return { |
109 |
| - "bootstrap_template": bootstrap_template, |
110 |
| - "coverage_files": coverage_files, |
111 |
| - "coverage_tool": coverage_tool, |
112 |
| - "files": files, |
113 |
| - "implementation_name": implementation_name, |
114 |
| - "interpreter": interpreter, |
115 |
| - "interpreter_path": interpreter_path, |
116 |
| - "interpreter_version_info": interpreter_version_info_struct_from_dict(interpreter_version_info), |
117 |
| - "pyc_tag": pyc_tag, |
118 |
| - "python_version": python_version, |
119 |
| - "stage2_bootstrap_template": stage2_bootstrap_template, |
120 |
| - "stub_shebang": stub_shebang, |
121 |
| - "zip_main_template": zip_main_template, |
122 |
| - } |
123 |
| - |
124 |
| -PyRuntimeInfo, _unused_raw_py_runtime_info_ctor = define_bazel_6_provider( |
125 |
| - doc = """Contains information about a Python runtime, as returned by the `py_runtime` |
126 |
| -rule. |
127 |
| -
|
128 |
| -A Python runtime describes either a *platform runtime* or an *in-build runtime*. |
129 |
| -A platform runtime accesses a system-installed interpreter at a known path, |
130 |
| -whereas an in-build runtime points to a `File` that acts as the interpreter. In |
131 |
| -both cases, an "interpreter" is really any executable binary or wrapper script |
132 |
| -that is capable of running a Python script passed on the command line, following |
133 |
| -the same conventions as the standard CPython interpreter. |
134 |
| -""", |
135 |
| - init = _PyRuntimeInfo_init, |
136 |
| - fields = { |
137 |
| - "bootstrap_template": """ |
138 |
| -:type: File |
139 |
| -
|
140 |
| -A template of code responsible for the initial startup of a program. |
141 |
| -
|
142 |
| -This code is responsible for: |
143 |
| -
|
144 |
| -* Locating the target interpreter. Typically it is in runfiles, but not always. |
145 |
| -* Setting necessary environment variables, command line flags, or other |
146 |
| - configuration that can't be modified after the interpreter starts. |
147 |
| -* Invoking the appropriate entry point. This is usually a second-stage bootstrap |
148 |
| - that performs additional setup prior to running a program's actual entry point. |
149 |
| -
|
150 |
| -The {obj}`--bootstrap_impl` flag affects how this stage 1 bootstrap |
151 |
| -is expected to behave and the substutitions performed. |
152 |
| -
|
153 |
| -* `--bootstrap_impl=system_python` substitutions: `%is_zipfile%`, `%python_binary%`, |
154 |
| - `%target%`, `%workspace_name`, `%coverage_tool%`, `%import_all%`, `%imports%`, |
155 |
| - `%main%`, `%shebang%` |
156 |
| -* `--bootstrap_impl=script` substititions: `%is_zipfile%`, `%python_binary%`, |
157 |
| - `%target%`, `%workspace_name`, `%shebang%, `%stage2_bootstrap%` |
158 |
| -
|
159 |
| -Substitution definitions: |
160 |
| -
|
161 |
| -* `%shebang%`: The shebang to use with the bootstrap; the bootstrap template |
162 |
| - may choose to ignore this. |
163 |
| -* `%stage2_bootstrap%`: A runfiles-relative path to the stage 2 bootstrap. |
164 |
| -* `%python_binary%`: The path to the target Python interpreter. There are three |
165 |
| - types of paths: |
166 |
| - * An absolute path to a system interpreter (e.g. begins with `/`). |
167 |
| - * A runfiles-relative path to an interpreter (e.g. `somerepo/bin/python3`) |
168 |
| - * A program to search for on PATH, i.e. a word without spaces, e.g. `python3`. |
169 |
| -* `%workspace_name%`: The name of the workspace the target belongs to. |
170 |
| -* `%is_zipfile%`: The string `1` if this template is prepended to a zipfile to |
171 |
| - create a self-executable zip file. The string `0` otherwise. |
172 |
| -
|
173 |
| -For the other substitution definitions, see the {obj}`stage2_bootstrap_template` |
174 |
| -docs. |
175 |
| -
|
176 |
| -:::{versionchanged} 0.33.0 |
177 |
| -The set of substitutions depends on {obj}`--bootstrap_impl` |
178 |
| -::: |
179 |
| -""", |
180 |
| - "coverage_files": """ |
181 |
| -:type: depset[File] | None |
182 |
| -
|
183 |
| -The files required at runtime for using `coverage_tool`. Will be `None` if no |
184 |
| -`coverage_tool` was provided. |
185 |
| -""", |
186 |
| - "coverage_tool": """ |
187 |
| -:type: File | None |
188 |
| -
|
189 |
| -If set, this field is a `File` representing tool used for collecting code |
190 |
| -coverage information from python tests. Otherwise, this is `None`. |
191 |
| -""", |
192 |
| - "files": """ |
193 |
| -:type: depset[File] | None |
194 |
| -
|
195 |
| -If this is an in-build runtime, this field is a `depset` of `File`s that need to |
196 |
| -be added to the runfiles of an executable target that uses this runtime (in |
197 |
| -particular, files needed by `interpreter`). The value of `interpreter` need not |
198 |
| -be included in this field. If this is a platform runtime then this field is |
199 |
| -`None`. |
200 |
| -""", |
201 |
| - "implementation_name": """ |
202 |
| -:type: str | None |
203 |
| -
|
204 |
| -The Python implementation name (`sys.implementation.name`) |
205 |
| -""", |
206 |
| - "interpreter": """ |
207 |
| -:type: File | None |
208 |
| -
|
209 |
| -If this is an in-build runtime, this field is a `File` representing the |
210 |
| -interpreter. Otherwise, this is `None`. Note that an in-build runtime can use |
211 |
| -either a prebuilt, checked-in interpreter or an interpreter built from source. |
212 |
| -""", |
213 |
| - "interpreter_path": """ |
214 |
| -:type: str | None |
215 |
| -
|
216 |
| -If this is a platform runtime, this field is the absolute filesystem path to the |
217 |
| -interpreter on the target platform. Otherwise, this is `None`. |
218 |
| -""", |
219 |
| - "interpreter_version_info": """ |
220 |
| -:type: struct |
221 |
| -
|
222 |
| -Version information about the interpreter this runtime provides. |
223 |
| -It should match the format given by `sys.version_info`, however |
224 |
| -for simplicity, the micro, releaselevel, and serial values are |
225 |
| -optional. |
226 |
| -A struct with the following fields: |
227 |
| -* `major`: {type}`int`, the major version number |
228 |
| -* `minor`: {type}`int`, the minor version number |
229 |
| -* `micro`: {type}`int | None`, the micro version number |
230 |
| -* `releaselevel`: {type}`str | None`, the release level |
231 |
| -* `serial`: {type}`int | None`, the serial number of the release |
232 |
| -""", |
233 |
| - "pyc_tag": """ |
234 |
| -:type: str | None |
235 |
| -
|
236 |
| -The tag portion of a pyc filename, e.g. the `cpython-39` infix |
237 |
| -of `foo.cpython-39.pyc`. See PEP 3147. If not specified, it will be computed |
238 |
| -from {obj}`implementation_name` and {obj}`interpreter_version_info`. If no |
239 |
| -pyc_tag is available, then only source-less pyc generation will function |
240 |
| -correctly. |
241 |
| -""", |
242 |
| - "python_version": """ |
243 |
| -:type: str |
244 |
| -
|
245 |
| -Indicates whether this runtime uses Python major version 2 or 3. Valid values |
246 |
| -are (only) `"PY2"` and `"PY3"`. |
247 |
| -""", |
248 |
| - "stage2_bootstrap_template": """ |
249 |
| -:type: File |
250 |
| -
|
251 |
| -A template of Python code that runs under the desired interpreter and is |
252 |
| -responsible for orchestrating calling the program's actual main code. This |
253 |
| -bootstrap is responsible for affecting the current runtime's state, such as |
254 |
| -import paths or enabling coverage, so that, when it runs the program's actual |
255 |
| -main code, it works properly under Bazel. |
256 |
| -
|
257 |
| -The following substitutions are made during template expansion: |
258 |
| -* `%main%`: A runfiles-relative path to the program's actual main file. This |
259 |
| - can be a `.py` or `.pyc` file, depending on precompile settings. |
260 |
| -* `%coverage_tool%`: Runfiles-relative path to the coverage library's entry point. |
261 |
| - If coverage is not enabled or available, an empty string. |
262 |
| -* `%import_all%`: The string `True` if all repositories in the runfiles should |
263 |
| - be added to sys.path. The string `False` otherwise. |
264 |
| -* `%imports%`: A colon-delimited string of runfiles-relative paths to add to |
265 |
| - sys.path. |
266 |
| -* `%target%`: The name of the target this is for. |
267 |
| -* `%workspace_name%`: The name of the workspace the target belongs to. |
268 |
| -
|
269 |
| -:::{versionadded} 0.33.0 |
270 |
| -::: |
271 |
| -""", |
272 |
| - "stub_shebang": """ |
273 |
| -:type: str |
274 |
| -
|
275 |
| -"Shebang" expression prepended to the bootstrapping Python stub |
276 |
| -script used when executing {obj}`py_binary` targets. Does not |
277 |
| -apply to Windows. |
278 |
| -""", |
279 |
| - "zip_main_template": """ |
280 |
| -:type: File |
281 |
| -
|
282 |
| -A template of Python code that becomes a zip file's top-level `__main__.py` |
283 |
| -file. The top-level `__main__.py` file is used when the zip file is explicitly |
284 |
| -passed to a Python interpreter. See PEP 441 for more information about zipapp |
285 |
| -support. Note that py_binary-generated zip files are self-executing and |
286 |
| -skip calling `__main__.py`. |
287 |
| -
|
288 |
| -The following substitutions are made during template expansion: |
289 |
| -* `%stage2_bootstrap%`: A runfiles-relative string to the stage 2 bootstrap file. |
290 |
| -* `%python_binary%`: The path to the target Python interpreter. There are three |
291 |
| - types of paths: |
292 |
| - * An absolute path to a system interpreter (e.g. begins with `/`). |
293 |
| - * A runfiles-relative path to an interpreter (e.g. `somerepo/bin/python3`) |
294 |
| - * A program to search for on PATH, i.e. a word without spaces, e.g. `python3`. |
295 |
| -* `%workspace_name%`: The name of the workspace for the built target. |
296 |
| -
|
297 |
| -:::{versionadded} 0.33.0 |
298 |
| -::: |
299 |
| -""", |
300 |
| - }, |
301 |
| -) |
302 |
| - |
303 | 19 | def _PyCcLinkParamsInfo_init(cc_info):
|
304 | 20 | return {
|
305 | 21 | "cc_info": CcInfo(linking_context = cc_info.linking_context),
|
|
0 commit comments