Skip to content

Commit c175a64

Browse files
authored
Reorganized rules to match interface of Bazel rules (#81)
1 parent aae1d5c commit c175a64

File tree

11 files changed

+428
-345
lines changed

11 files changed

+428
-345
lines changed

perl/defs.bzl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Perl rules for Bazel"""
2+
3+
load(
4+
"//perl/private:perl.bzl",
5+
_perl_binary = "perl_binary",
6+
_perl_library = "perl_library",
7+
_perl_test = "perl_test",
8+
)
9+
load(
10+
"//perl/private:perl_xs.bzl",
11+
_perl_xs = "perl_xs",
12+
)
13+
load(
14+
"//perl/private:providers.bzl",
15+
_PerlInfo = "PerlInfo",
16+
)
17+
18+
PerlInfo = _PerlInfo
19+
perl_binary = _perl_binary
20+
perl_library = _perl_library
21+
perl_test = _perl_test
22+
perl_xs = _perl_xs
23+
24+
# Keep this name around for legacy support.
25+
# buildifier: disable=name-conventions
26+
PerlLibrary = PerlInfo

perl/perl.bzl

Lines changed: 19 additions & 345 deletions
Original file line numberDiff line numberDiff line change
@@ -14,353 +14,27 @@
1414

1515
"""Perl rules for Bazel"""
1616

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",
2922
)
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",
4926
)
50-
51-
_perl_main_attr = attr.label(
52-
allow_single_file = _perl_file_types,
27+
load(
28+
"//perl/private:providers.bzl",
29+
_PerlInfo = "PerlInfo",
5330
)
5431

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
19737

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

Comments
 (0)