-
Notifications
You must be signed in to change notification settings - Fork 520
/
Copy pathtoolchain.bzl
279 lines (231 loc) · 9.89 KB
/
toolchain.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# Copyright 2018 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This module implements the node toolchain rule.
"""
NodeInfo = provider(
doc = "Information about how to invoke Node.js and npm.",
fields = {
"node": """Node.js executable
If set, node_path will not be set.""",
"node_path": """Path to Node.js executable; typically an absolute path to a non-hermetic Node.js.
If set, node will not be set.""",
"npm": """Npm JavaScript entry point File
For backward compability, if set then npm_path will be set to the runfiles path of npm.
""",
"npm_path": """Path to npm JavaScript entry point; typically an absolute path to a non-hermetic Node.js.
For backward compability, npm_path is set to the runfiles path of npm if npm is set.
""",
"npm_sources": """Additional source files required to run npm""",
"headers": """Optional.\
(struct) Information about the header files, with fields:
* providers_map: a dict of string to provider instances. The key should be
a fully qualified name (e.g. `@rules_foo//bar:baz.bzl#MyInfo`) of the
provider to uniquely identify its type.
The following keys are always present:
* CcInfo: the CcInfo provider instance for the headers.
* DefaultInfo: the DefaultInfo provider instance for the headers.
A map is used to allow additional providers from the originating headers
target (typically a `cc_library`) to be propagated to consumers (directly
exposing a Target object can cause memory issues and is an anti-pattern).
When consuming this map, it's suggested to use `providers_map.values()` to
return all providers; or copy the map and filter out or replace keys as
appropriate. Note that any keys begining with `_` (underscore) are
considered private and should be forward along as-is (this better allows
e.g. `:current_node_cc_headers` to act as the underlying headers target it
represents).
""",
# DEPRECATED
"target_tool_path": "(DEPRECATED) Path to Node.js executable for backward compatibility",
"tool_files": """(DEPRECATED) Alias for [node] for backward compatibility""",
"npm_files": """(DEPRECATED) Alias for npm_sources.to_list()""",
},
)
# Avoid using non-normalized paths (workspace/../other_workspace/path)
def _to_manifest_path(ctx, file):
if file.short_path.startswith("../"):
return "external/" + file.short_path[3:]
else:
return ctx.workspace_name + "/" + file.short_path
def _nodejs_toolchain_impl(ctx):
if ctx.attr.node and ctx.attr.node_path:
fail("Can only set one of node or node_path but both were set.")
if not ctx.attr.node and not ctx.attr.node_path:
fail("Must set one of node or node_path.")
if ctx.attr.npm and ctx.attr.npm_path:
fail("Can only set one of npm or npm_path but both were set.")
# Make the $(NODE_PATH) variable available in places like genrules.
# See https://docs.bazel.build/versions/main/be/make-variables.html#custom_variables
template_variables = platform_common.TemplateVariableInfo({
"NODE_PATH": ctx.file.node.path if ctx.attr.node else ctx.attr.node_path,
"NPM_PATH": ctx.file.npm.path if ctx.attr.npm else ctx.attr.npm_path,
})
default = DefaultInfo(
files = depset([ctx.file.node]) if ctx.attr.node else depset(),
runfiles = ctx.runfiles(files = [ctx.file.node] if ctx.attr.node else []),
)
npm_sources = depset([ctx.file.npm] + ctx.files.npm_srcs)
nodeinfo = NodeInfo(
node = ctx.file.node,
node_path = ctx.attr.node_path,
npm = ctx.file.npm,
npm_path = ctx.attr.npm_path if ctx.attr.npm_path else (_to_manifest_path(ctx, ctx.file.npm) if ctx.file.npm else ""), # _to_manifest_path for backward compat
npm_sources = npm_sources,
headers = struct(
providers_map = {
"CcInfo": ctx.attr.headers[CcInfo],
"DefaultInfo": ctx.attr.headers[DefaultInfo],
},
) if ctx.attr.headers else None,
# For backward compat
target_tool_path = _to_manifest_path(ctx, ctx.file.node) if ctx.attr.node else ctx.attr.node_path,
tool_files = [ctx.file.node] if ctx.attr.node else [],
npm_files = npm_sources.to_list(),
)
# Export all the providers inside our ToolchainInfo
# so the resolved_toolchain rule can grab and re-export them.
toolchain_info = platform_common.ToolchainInfo(
nodeinfo = nodeinfo,
template_variables = template_variables,
default = default,
)
return [
default,
toolchain_info,
template_variables,
]
_nodejs_toolchain = rule(
implementation = _nodejs_toolchain_impl,
attrs = {
"node": attr.label(
executable = True,
cfg = "exec",
allow_single_file = True,
),
"node_path": attr.string(),
"npm": attr.label(allow_single_file = True),
"npm_path": attr.string(),
"npm_srcs": attr.label_list(),
"headers": attr.label(),
},
)
def nodejs_toolchain(
name,
node = None,
node_path = "",
npm = None,
npm_path = "",
npm_srcs = [],
headers = None,
**kwargs):
"""Defines a node toolchain for a platform.
You can use this to refer to a vendored nodejs binary in your repository,
or even to compile nodejs from sources using rules_foreign_cc or other rules.
First, in a BUILD.bazel file, create a nodejs_toolchain definition:
```starlark
load("@rules_nodejs//nodejs:toolchain.bzl", "nodejs_toolchain")
nodejs_toolchain(
name = "toolchain",
node = "//some/path/bin/node",
)
```
Next, declare which execution platforms or target platforms the toolchain should be selected for
based on constraints.
```starlark
toolchain(
name = "my_nodejs",
exec_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
toolchain = ":toolchain",
toolchain_type = "@rules_nodejs//nodejs:runtime_toolchain_type",
)
```
See https://bazel.build/extending/toolchains#toolchain-resolution for more information on toolchain
resolution.
Finally in your `WORKSPACE`, register it with `register_toolchains("//:my_nodejs")`
For usage see https://docs.bazel.build/versions/main/toolchains.html#defining-toolchains.
You can use the `--toolchain_resolution_debug` flag to `bazel` to help diagnose which toolchain is selected.
Args:
name: Unique name for this target
node: Node.js executable
node_path: Path to Node.js executable file
This is typically an absolute path to a non-hermetic Node.js executable.
Only one of `node` and `node_path` may be set.
npm: Npm JavaScript entry point
npm_path: Path to npm JavaScript entry point.
This is typically an absolute path to a non-hermetic npm installation.
Only one of `npm` and `npm_path` may be set.
npm_srcs: Additional source files required to run npm.
Not necessary if specifying `npm_path` to a non-hermetic npm installation.
headers: cc_library that contains the Node/v8 header files
**kwargs: Additional parameters
"""
target_tool = kwargs.pop("target_tool", None)
if target_tool:
# buildifier: disable=print
print("""\
WARNING: target_tool attribute of nodejs_toolchain is deprecated; use node instead of target_tool.
If your are not calling nodejs_toolchain directly you may need to upgrade to rules_js 2.x to suppress this warning.
""")
node = target_tool
target_tool_path = kwargs.pop("target_tool_path", "")
if target_tool_path:
# buildifier: disable=print
print("""\
WARNING: target_tool_path attribute of nodejs_toolchain is deprecated; use node_path instead of target_tool_path
""")
node_path = target_tool_path
npm_files = kwargs.pop("npm_files", "")
if npm_files:
# buildifier: disable=print
print("""\
WARNING: npm_files attribute of nodejs_toolchain is deprecated; use npm_srcs instead of npm_files
""")
npm_srcs = npm_files
_nodejs_toolchain(
name = name,
node = node,
node_path = node_path,
npm = npm,
npm_path = npm_path,
npm_srcs = npm_srcs,
headers = headers,
**kwargs
)
def node_toolchain(**kwargs):
"""Deprecated. Use nodejs_toolchain instead.
Args:
**kwargs: Parameters to forward to nodejs_toolchain rule.
"""
# buildifier: disable=print
print("""\
WARNING: node_toolchain is deprecated; use nodejs_toolchain instead.
If your are not calling node_toolchain directly you may need to upgrade to rules_js 2.x to suppress this warning.
""")
nodejs_toolchain(**kwargs)
# Forward all the providers
def _resolved_toolchain_impl(ctx):
toolchain_info = ctx.toolchains["@rules_nodejs//nodejs:runtime_toolchain_type"]
return [
toolchain_info,
toolchain_info.default,
toolchain_info.nodeinfo,
toolchain_info.template_variables,
]
# Based on https://github.com/bazelbuild/rules_java/blob/6a34389003a6bed549858bb8f4673dd521ad8a54/toolchains/java_toolchain_alias.bzl#L19-L40
resolved_toolchain = rule(
implementation = _resolved_toolchain_impl,
toolchains = ["@rules_nodejs//nodejs:runtime_toolchain_type"],
)