|
14 | 14 |
|
15 | 15 | """Perl rules for Bazel""" |
16 | 16 |
|
17 | | -load("@bazel_skylib//lib:new_sets.bzl", "sets") |
18 | | -load("@bazel_skylib//lib:paths.bzl", "paths") |
19 | | -load("@rules_cc//cc:defs.bzl", "CcInfo", "cc_common") |
20 | | -load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") |
21 | | - |
22 | | -# buildifier: disable=name-conventions |
23 | | -PerlLibrary = provider( |
24 | | - doc = "A provider containing components of a `perl_library`", |
25 | | - fields = [ |
26 | | - "transitive_perl_sources", |
27 | | - "includes", |
28 | | - ], |
| 17 | +load( |
| 18 | + "//perl/private:perl.bzl", |
| 19 | + _perl_binary = "perl_binary", |
| 20 | + _perl_library = "perl_library", |
| 21 | + _perl_test = "perl_test", |
29 | 22 | ) |
30 | | - |
31 | | -PERL_XS_COPTS = [ |
32 | | - "-fwrapv", |
33 | | - "-fPIC", |
34 | | - "-fno-strict-aliasing", |
35 | | - "-D_LARGEFILE_SOURCE", |
36 | | - "-D_FILE_OFFSET_BITS=64", |
37 | | -] |
38 | | - |
39 | | -_perl_file_types = [".pl", ".pm", ".t", ".so", ".ix", ".al", ""] |
40 | | -_perl_srcs_attr = attr.label_list(allow_files = _perl_file_types) |
41 | | - |
42 | | -_perl_deps_attr = attr.label_list( |
43 | | - allow_files = False, |
44 | | - providers = [PerlLibrary], |
45 | | -) |
46 | | - |
47 | | -_perl_data_attr = attr.label_list( |
48 | | - allow_files = True, |
| 23 | +load( |
| 24 | + "//perl/private:perl_xs.bzl", |
| 25 | + _perl_xs = "perl_xs", |
49 | 26 | ) |
50 | | - |
51 | | -_perl_main_attr = attr.label( |
52 | | - allow_single_file = _perl_file_types, |
| 27 | +load( |
| 28 | + "//perl/private:providers.bzl", |
| 29 | + _PerlInfo = "PerlInfo", |
53 | 30 | ) |
54 | 31 |
|
55 | | -_perl_env_attr = attr.string_dict() |
56 | | - |
57 | | -def _get_main_from_sources(ctx): |
58 | | - sources = ctx.files.srcs |
59 | | - if len(sources) != 1: |
60 | | - fail("Cannot infer main from multiple 'srcs'. Please specify 'main' attribute.", "main") |
61 | | - return sources[0] |
62 | | - |
63 | | -def _transitive_srcs(deps): |
64 | | - return struct( |
65 | | - srcs = [ |
66 | | - d[PerlLibrary].transitive_perl_sources |
67 | | - for d in deps |
68 | | - if PerlLibrary in d |
69 | | - ], |
70 | | - files = [ |
71 | | - d[DefaultInfo].default_runfiles.files |
72 | | - for d in deps |
73 | | - ], |
74 | | - ) |
75 | | - |
76 | | -def transitive_deps(ctx, extra_files = [], extra_deps = []): |
77 | | - """Calculates transitive sets of args. |
78 | | -
|
79 | | - Calculates the transitive sets for perl sources, data runfiles, |
80 | | - include flags and runtime flags from the srcs, data and deps attributes |
81 | | - in the context. |
82 | | -
|
83 | | - Also adds extra_deps to the roots of the traversal. |
84 | | -
|
85 | | - Args: |
86 | | - ctx: a ctx object for a perl_library or a perl_binary rule. |
87 | | - extra_files: a list of File objects to be added to the default_files |
88 | | - extra_deps: a list of Target objects. |
89 | | - """ |
90 | | - deps = _transitive_srcs(ctx.attr.deps + extra_deps) |
91 | | - files = ctx.runfiles( |
92 | | - files = extra_files + ctx.files.srcs + ctx.files.data, |
93 | | - transitive_files = depset(transitive = deps.files), |
94 | | - collect_default = True, |
95 | | - ) |
96 | | - return struct( |
97 | | - srcs = depset( |
98 | | - direct = ctx.files.srcs, |
99 | | - transitive = deps.srcs, |
100 | | - ), |
101 | | - files = files, |
102 | | - ) |
103 | | - |
104 | | -def _include_paths(ctx): |
105 | | - """Calculate the PERL5LIB paths for a perl_library rule's includes.""" |
106 | | - workspace_name = ctx.label.workspace_name |
107 | | - if workspace_name: |
108 | | - workspace_root = "../" + workspace_name |
109 | | - else: |
110 | | - workspace_root = "" |
111 | | - package_root = (workspace_root + "/" + ctx.label.package).strip("/") or "." |
112 | | - include_paths = [package_root] if "." in ctx.attr.includes else [] |
113 | | - include_paths.extend([package_root + "/" + include for include in ctx.attr.includes if include != "."]) |
114 | | - for dep in ctx.attr.deps: |
115 | | - include_paths.extend(dep[PerlLibrary].includes) |
116 | | - include_paths = depset(direct = include_paths).to_list() |
117 | | - return include_paths |
118 | | - |
119 | | -def _perl_library_implementation(ctx): |
120 | | - transitive_sources = transitive_deps(ctx) |
121 | | - return [ |
122 | | - DefaultInfo( |
123 | | - runfiles = transitive_sources.files, |
124 | | - ), |
125 | | - PerlLibrary( |
126 | | - transitive_perl_sources = transitive_sources.srcs, |
127 | | - includes = _include_paths(ctx), |
128 | | - ), |
129 | | - ] |
130 | | - |
131 | | -def sum(items, initial): |
132 | | - result = initial |
133 | | - for item in items: |
134 | | - result += item |
135 | | - return result |
136 | | - |
137 | | -def _perl_binary_implementation(ctx): |
138 | | - toolchain = ctx.toolchains["@rules_perl//perl:toolchain_type"].perl_runtime |
139 | | - interpreter = toolchain.interpreter |
140 | | - |
141 | | - transitive_sources = transitive_deps(ctx, extra_files = toolchain.runtime + [ctx.outputs.executable]) |
142 | | - |
143 | | - main = ctx.file.main |
144 | | - if main == None: |
145 | | - main = _get_main_from_sources(ctx) |
146 | | - |
147 | | - include_paths = sum([dep[PerlLibrary].includes for dep in ctx.attr.deps], []) |
148 | | - perl5lib = ":" + ":".join(include_paths) if include_paths else "" |
149 | | - |
150 | | - ctx.actions.expand_template( |
151 | | - template = ctx.file._wrapper_template, |
152 | | - output = ctx.outputs.executable, |
153 | | - substitutions = { |
154 | | - "{PERL5LIB}": perl5lib, |
155 | | - "{env_vars}": _env_vars(ctx), |
156 | | - "{interpreter}": interpreter.short_path, |
157 | | - "{main}": main.short_path, |
158 | | - "{workspace_name}": ctx.label.workspace_name or ctx.workspace_name, |
159 | | - }, |
160 | | - is_executable = True, |
161 | | - ) |
162 | | - |
163 | | - return DefaultInfo( |
164 | | - executable = ctx.outputs.executable, |
165 | | - runfiles = transitive_sources.files, |
166 | | - ) |
167 | | - |
168 | | -def _env_vars(ctx): |
169 | | - environment = "" |
170 | | - for name, value in ctx.attr.env.items(): |
171 | | - if not _is_identifier(name): |
172 | | - fail("%s is not a valid environment variable name." % str(name)) |
173 | | - value = ctx.expand_location(value, targets = ctx.attr.data) |
174 | | - environment += ("{key}='{value}' ").format( |
175 | | - key = name, |
176 | | - value = value.replace("'", "\\'"), |
177 | | - ) |
178 | | - return environment |
179 | | - |
180 | | -def _is_identifier(name): |
181 | | - # Must be non-empty. |
182 | | - if name == None or len(name) == 0: |
183 | | - return False |
184 | | - |
185 | | - # Must start with alpha or '_' |
186 | | - if not (name[0].isalpha() or name[0] == "_"): |
187 | | - return False |
188 | | - |
189 | | - # Must consist of alnum characters or '_'s. |
190 | | - for c in name.elems(): |
191 | | - if not (c.isalnum() or c == "_"): |
192 | | - return False |
193 | | - return True |
194 | | - |
195 | | -def _perl_test_implementation(ctx): |
196 | | - return _perl_binary_implementation(ctx) |
| 32 | +PerlInfo = _PerlInfo |
| 33 | +perl_binary = _perl_binary |
| 34 | +perl_library = _perl_library |
| 35 | +perl_test = _perl_test |
| 36 | +perl_xs = _perl_xs |
197 | 37 |
|
198 | | -def _perl_xs_cc_lib(ctx, toolchain, srcs): |
199 | | - cc_toolchain = find_cc_toolchain(ctx) |
200 | | - xs_headers = toolchain.xs_headers |
201 | | - |
202 | | - includes = [f.dirname for f in xs_headers.to_list()] |
203 | | - |
204 | | - textual_hdrs = [] |
205 | | - for hdrs in ctx.attr.textual_hdrs: |
206 | | - for hdr in hdrs.files.to_list(): |
207 | | - textual_hdrs.append(hdr) |
208 | | - includes.append(hdr.dirname) |
209 | | - |
210 | | - includes = sets.make(includes) |
211 | | - includes = sets.to_list(includes) |
212 | | - |
213 | | - feature_configuration = cc_common.configure_features( |
214 | | - ctx = ctx, |
215 | | - cc_toolchain = cc_toolchain, |
216 | | - requested_features = ctx.features, |
217 | | - unsupported_features = ctx.disabled_features, |
218 | | - ) |
219 | | - |
220 | | - (compilation_context, compilation_outputs) = cc_common.compile( |
221 | | - actions = ctx.actions, |
222 | | - name = ctx.label.name, |
223 | | - feature_configuration = feature_configuration, |
224 | | - cc_toolchain = cc_toolchain, |
225 | | - srcs = srcs + ctx.files.cc_srcs, |
226 | | - defines = ctx.attr.defines, |
227 | | - additional_inputs = textual_hdrs, |
228 | | - private_hdrs = xs_headers.to_list(), |
229 | | - includes = includes, |
230 | | - user_compile_flags = ctx.attr.copts + PERL_XS_COPTS, |
231 | | - compilation_contexts = [], |
232 | | - ) |
233 | | - |
234 | | - (linking_context, _linking_outputs) = cc_common.create_linking_context_from_compilation_outputs( |
235 | | - actions = ctx.actions, |
236 | | - name = ctx.label.name, |
237 | | - feature_configuration = feature_configuration, |
238 | | - cc_toolchain = cc_toolchain, |
239 | | - compilation_outputs = compilation_outputs, |
240 | | - user_link_flags = ctx.attr.linkopts, |
241 | | - linking_contexts = [], |
242 | | - ) |
243 | | - |
244 | | - return CcInfo( |
245 | | - compilation_context = compilation_context, |
246 | | - linking_context = linking_context, |
247 | | - ) |
248 | | - |
249 | | -def _perl_xs_implementation(ctx): |
250 | | - toolchain = ctx.toolchains["@rules_perl//perl:toolchain_type"].perl_runtime |
251 | | - xsubpp = toolchain.xsubpp |
252 | | - |
253 | | - toolchain_files = depset(toolchain.runtime) |
254 | | - |
255 | | - gen = [] |
256 | | - cc_infos = [] |
257 | | - args_typemaps = [] |
258 | | - |
259 | | - for typemap in ctx.files.typemaps: |
260 | | - args_typemaps += ["-typemap", typemap.short_path] |
261 | | - |
262 | | - for src in ctx.files.srcs: |
263 | | - c_execpath = paths.replace_extension(src.path, ".c") |
264 | | - o_packagepath = paths.join("_objs/execroot/", c_execpath) |
265 | | - out = ctx.actions.declare_file(o_packagepath) |
266 | | - |
267 | | - ctx.actions.run( |
268 | | - outputs = [out], |
269 | | - inputs = [src] + ctx.files.typemaps, |
270 | | - arguments = args_typemaps + ["-output", out.path, src.path], |
271 | | - progress_message = "Translitterating %s to %s" % (src.short_path, out.short_path), |
272 | | - executable = xsubpp, |
273 | | - tools = toolchain_files, |
274 | | - ) |
275 | | - |
276 | | - gen.append(out) |
277 | | - |
278 | | - cc_info = _perl_xs_cc_lib(ctx, toolchain, gen) |
279 | | - cc_infos = [cc_info] + [dep[CcInfo] for dep in ctx.attr.deps] |
280 | | - cc_info = cc_common.merge_cc_infos(cc_infos = cc_infos) |
281 | | - lib = cc_info.linking_context.linker_inputs.to_list()[0].libraries[0] |
282 | | - dyn_lib = lib.dynamic_library |
283 | | - |
284 | | - if len(ctx.attr.output_loc): |
285 | | - output = ctx.actions.declare_file(ctx.attr.output_loc) |
286 | | - else: |
287 | | - output = ctx.actions.declare_file(ctx.label.name + ".so") |
288 | | - |
289 | | - ctx.actions.run_shell( |
290 | | - outputs = [output], |
291 | | - inputs = [dyn_lib], |
292 | | - arguments = [dyn_lib.path, output.path], |
293 | | - command = "cp $1 $2", |
294 | | - ) |
295 | | - |
296 | | - return [ |
297 | | - cc_info, |
298 | | - DefaultInfo(files = depset([output])), |
299 | | - ] |
300 | | - |
301 | | -perl_library = rule( |
302 | | - attrs = { |
303 | | - "data": _perl_data_attr, |
304 | | - "deps": _perl_deps_attr, |
305 | | - "includes": attr.string_list(default = [".", "lib"]), |
306 | | - "srcs": _perl_srcs_attr, |
307 | | - }, |
308 | | - implementation = _perl_library_implementation, |
309 | | - toolchains = ["@rules_perl//perl:toolchain_type"], |
310 | | -) |
311 | | - |
312 | | -perl_binary = rule( |
313 | | - attrs = { |
314 | | - "data": _perl_data_attr, |
315 | | - "deps": _perl_deps_attr, |
316 | | - "env": _perl_env_attr, |
317 | | - "main": _perl_main_attr, |
318 | | - "srcs": _perl_srcs_attr, |
319 | | - "_wrapper_template": attr.label( |
320 | | - allow_single_file = True, |
321 | | - default = "binary_wrapper.tpl", |
322 | | - ), |
323 | | - }, |
324 | | - executable = True, |
325 | | - implementation = _perl_binary_implementation, |
326 | | - toolchains = ["@rules_perl//perl:toolchain_type"], |
327 | | -) |
328 | | - |
329 | | -perl_test = rule( |
330 | | - attrs = { |
331 | | - "data": _perl_data_attr, |
332 | | - "deps": _perl_deps_attr, |
333 | | - "env": _perl_env_attr, |
334 | | - "main": _perl_main_attr, |
335 | | - "srcs": _perl_srcs_attr, |
336 | | - "_wrapper_template": attr.label( |
337 | | - allow_single_file = True, |
338 | | - default = "binary_wrapper.tpl", |
339 | | - ), |
340 | | - }, |
341 | | - executable = True, |
342 | | - test = True, |
343 | | - implementation = _perl_test_implementation, |
344 | | - toolchains = ["@rules_perl//perl:toolchain_type"], |
345 | | -) |
346 | | - |
347 | | -perl_xs = rule( |
348 | | - attrs = { |
349 | | - "cc_srcs": attr.label_list(allow_files = [".c", ".cc"]), |
350 | | - "copts": attr.string_list(), |
351 | | - "defines": attr.string_list(), |
352 | | - "deps": attr.label_list(providers = [CcInfo]), |
353 | | - "linkopts": attr.string_list(), |
354 | | - "output_loc": attr.string(), |
355 | | - "srcs": attr.label_list(allow_files = [".xs"]), |
356 | | - "textual_hdrs": attr.label_list(allow_files = True), |
357 | | - "typemaps": attr.label_list(allow_files = True), |
358 | | - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), |
359 | | - }, |
360 | | - implementation = _perl_xs_implementation, |
361 | | - fragments = ["cpp"], |
362 | | - toolchains = [ |
363 | | - "@rules_perl//perl:toolchain_type", |
364 | | - "@bazel_tools//tools/cpp:toolchain_type", |
365 | | - ], |
366 | | -) |
| 38 | +# Keep this name around for legacy support. |
| 39 | +# buildifier: disable=name-conventions |
| 40 | +PerlLibrary = PerlInfo |
0 commit comments