| # 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, |
| }) |
| files = [f for f in [ctx.file.node, ctx.file.npm] if f] |
| default = DefaultInfo( |
| files = depset(files), |
| runfiles = ctx.runfiles(files = files), |
| ) |
| 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: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 you 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 you are not calling node_toolchain directly you may need to upgrade to rules_js 2.x to suppress this warning. |
| """) |
| nodejs_toolchain(**kwargs) |