diff --git a/MODULE.bazel b/MODULE.bazel index b14eb4ad1c..deb4f2960a 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -9,6 +9,9 @@ module( bazel_dep(name = "bazel_skylib", version = "1.4.1") bazel_dep(name = "platforms", version = "0.0.5") +# workaround for https://github.com/bazelbuild/bazel/issues/25124 +bazel_dep(name = "zlib", version = "1.3.1.bcr.6", dev_dependency = True) + node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") # Note, this gets the default version of Node.js from @@ -18,37 +21,37 @@ use_repo(node, "nodejs_toolchains") # Toolchain registration under bzlmod should match the order of WORKSPACE registration # which is the order specified in the PLATFORMS dict https://github.com/bazel-contrib/rules_nodejs/blob/4c373209b058d46f2a5f9ab9f8abf11b161ae459/nodejs/private/nodejs_toolchains_repo.bzl#L20. -# For each platform, `:_toolchain_target` should be registered before `:_toolchain`, +# For each platform, `:_runtime_toolchain` should be registered before `:_toolchain`, # https://github.com/bazel-contrib/rules_nodejs/blob/4c373209b058d46f2a5f9ab9f8abf11b161ae459/nodejs/repositories.bzl#L461/. # See https://github.com/bazelbuild/bazel/issues/19645 and https://github.com/bazel-contrib/rules_nodejs/pull/3750 for more context. -register_toolchains("@nodejs_toolchains//:linux_amd64_toolchain_target") +register_toolchains("@nodejs_toolchains//:linux_amd64_runtime_toolchain") register_toolchains("@nodejs_toolchains//:linux_amd64_toolchain") -register_toolchains("@nodejs_toolchains//:linux_arm64_toolchain_target") +register_toolchains("@nodejs_toolchains//:linux_arm64_runtime_toolchain") register_toolchains("@nodejs_toolchains//:linux_arm64_toolchain") -register_toolchains("@nodejs_toolchains//:linux_s390x_toolchain_target") +register_toolchains("@nodejs_toolchains//:linux_s390x_runtime_toolchain") register_toolchains("@nodejs_toolchains//:linux_s390x_toolchain") -register_toolchains("@nodejs_toolchains//:linux_ppc64le_toolchain_target") +register_toolchains("@nodejs_toolchains//:linux_ppc64le_runtime_toolchain") register_toolchains("@nodejs_toolchains//:linux_ppc64le_toolchain") -register_toolchains("@nodejs_toolchains//:darwin_amd64_toolchain_target") +register_toolchains("@nodejs_toolchains//:darwin_amd64_runtime_toolchain") register_toolchains("@nodejs_toolchains//:darwin_amd64_toolchain") -register_toolchains("@nodejs_toolchains//:darwin_arm64_toolchain_target") +register_toolchains("@nodejs_toolchains//:darwin_arm64_runtime_toolchain") register_toolchains("@nodejs_toolchains//:darwin_arm64_toolchain") -register_toolchains("@nodejs_toolchains//:windows_amd64_toolchain_target") +register_toolchains("@nodejs_toolchains//:windows_amd64_runtime_toolchain") register_toolchains("@nodejs_toolchains//:windows_amd64_toolchain") -register_toolchains("@nodejs_toolchains//:windows_arm64_toolchain_target") +register_toolchains("@nodejs_toolchains//:windows_arm64_runtime_toolchain") register_toolchains("@nodejs_toolchains//:windows_arm64_toolchain") diff --git a/WORKSPACE b/WORKSPACE index 13728f4bdb..5fd9b3d346 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -60,6 +60,19 @@ http_archive( # Dependencies & toolchains needed for unit tests & generating documentation # +# workaround for https://github.com/bazelbuild/bazel/issues/25124 +zlib_version = "1.3.1" + +zlib_sha256 = "9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23" + +http_archive( + name = "zlib", + build_file = "@com_google_protobuf//:third_party/zlib.BUILD", + sha256 = zlib_sha256, + strip_prefix = "zlib-%s" % zlib_version, + urls = ["https://github.com/madler/zlib/releases/download/v{v}/zlib-{v}.tar.gz".format(v = zlib_version)], +) + load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies", "register_copy_directory_toolchains", "register_copy_to_directory_toolchains") aspect_bazel_lib_dependencies() diff --git a/docs/Core.md b/docs/Core.md index d0007c8a65..59804a1044 100644 --- a/docs/Core.md +++ b/docs/Core.md @@ -183,7 +183,7 @@ nodejs_toolchain( ``` Next, declare which execution platforms or target platforms the toolchain should be selected for -based on constraints. +based on constraints. A separate toolchain type is used for runtime target platform selection. ```starlark toolchain( @@ -195,6 +195,15 @@ toolchain( toolchain = ":toolchain", toolchain_type = "@rules_nodejs//nodejs:toolchain_type", ) +toolchain( + name = "my_nodejs_runtime", + target_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 diff --git a/docs/Toolchains.md b/docs/Toolchains.md index 5b94c6a694..69229df901 100644 --- a/docs/Toolchains.md +++ b/docs/Toolchains.md @@ -3,6 +3,16 @@ API docs for [Toolchain](https://docs.bazel.build/versions/main/toolchains.html) support. When you call `nodejs_register_toolchains()` in your `WORKSPACE` file it will setup a node toolchain for executing tools on all currently supported platforms. +In `bzlmod` default toolchains are registered automatically when you depend on `rules_nodejs`. + +There are two toolchain types: + +1) The transpilation toolchain, which provides the Node runtime used to execute the transpiler (and type checker), as well as various helper tools and settings. + (`@rules_nodejs//nodejs:toolchain_type`) +2) The Node runtime that executable Node outputs (e.g., js_binary) will run on. + (`@rules_nodejs//nodejs:runtime_toolchain_type`) + +See [//nodjes/BUILD.bazel](https://github.com/bazel-contrib/rules_nodejs/blob/main/nodejs/BUILD.bazel) for details. If you have an advanced use-case and want to use a version of node not supported by this repository, you can also register your own toolchains. @@ -13,9 +23,9 @@ To run a custom toolchain (i.e., to run a node binary not supported by the built 1) A rule which can build or load a node binary from your repository (a checked-in binary or a build using a relevant [`rules_foreign_cc` build rule](https://bazelbuild.github.io/rules_foreign_cc/) will do nicely). 2) A [`nodejs_toolchain` rule](Core.html#nodejs_toolchain) which depends on your binary defined in step 1 as its `node`. -3) A [`toolchain` rule](https://bazel.build/reference/be/platform#toolchain) that depends on your `nodejs_toolchain` rule defined in step 2 as its `toolchain` - and on `@rules_nodejs//nodejs:toolchain_type` as its `toolchain_type`. Make sure to define appropriate platform restrictions as described in the - documentation for the `toolchain` rule. +3) Two [`toolchain` rules](https://bazel.build/reference/be/platform#toolchain) each depends on your `nodejs_toolchain` rule defined in step 2 as its `toolchain` + and one on `@rules_nodejs//nodejs:toolchain_type` as its `toolchain_type` and the other one `@rules_nodejs//nodejs:runtime_toolchain_type`. + Make sure to define appropriate platform restrictions as described in the documentation for the `toolchain` rule. 4) A call to [the `register_toolchains` function](https://bazel.build/rules/lib/globals#register_toolchains) in your `WORKSPACE` that refers to the `toolchain` rule defined in step 3. diff --git a/e2e/smoke/BUILD.bazel b/e2e/smoke/BUILD.bazel index afbe9664e1..f19879be13 100644 --- a/e2e/smoke/BUILD.bazel +++ b/e2e/smoke/BUILD.bazel @@ -9,6 +9,12 @@ not_windows = select({ "//conditions:default": [], }) +not_silicon = select({ + # There isn't a published arm64 binary for Node 15 + "@platforms//cpu:arm64": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + # Trivial test fixture: a nodejs program that writes to a file write_file( name = "js", @@ -67,7 +73,6 @@ genrule( outs = ["actual1"], cmd = "$(NODE_PATH) $(execpath some.js) $@", toolchains = ["@nodejs_toolchains//:resolved_toolchain"], - tools = ["@nodejs_toolchains//:resolved_toolchain"], ) diff_test( @@ -253,7 +258,9 @@ my_nodejs( # you can also just provide an individual toolchain if you don't want to download them all toolchain = select({ "@bazel_tools//src/conditions:linux_x86_64": "@node17_linux_amd64//:toolchain", - "@bazel_tools//src/conditions:darwin": "@node17_darwin_amd64//:toolchain", + "@bazel_tools//src/conditions:linux_aarch64": "@node17_linux_arm64//:toolchain", + "@bazel_tools//src/conditions:darwin_x86_64": "@node17_darwin_amd64//:toolchain", + "@bazel_tools//src/conditions:darwin_arm64": "@node17_darwin_arm64//:toolchain", "@bazel_tools//src/conditions:windows": "@node17_windows_amd64//:toolchain", }), ) @@ -273,7 +280,9 @@ my_nodejs( # you can also just provide an individual toolchain if you don't want to download them all toolchain = select({ "@bazel_tools//src/conditions:linux_x86_64": "@nodejs_linux_amd64//:toolchain", - "@bazel_tools//src/conditions:darwin": "@nodejs_darwin_amd64//:toolchain", + "@bazel_tools//src/conditions:linux_aarch64": "@nodejs_linux_arm64//:toolchain", + "@bazel_tools//src/conditions:darwin_x86_64": "@nodejs_darwin_amd64//:toolchain", + "@bazel_tools//src/conditions:darwin_arm64": "@nodejs_darwin_arm64//:toolchain", "@bazel_tools//src/conditions:windows": "@nodejs_windows_amd64//:toolchain", }), ) @@ -288,11 +297,12 @@ my_nodejs( name = "run_15", out = "thing_toolchain_15", entry_point = "version.js", + target_compatible_with = not_silicon, # using the select statement will download toolchains for all three platforms # you can also just provide an individual toolchain if you don't want to download them all toolchain = select({ "@bazel_tools//src/conditions:linux_x86_64": "@node15_linux_amd64//:toolchain", - "@bazel_tools//src/conditions:darwin": "@node15_darwin_amd64//:toolchain", + "@bazel_tools//src/conditions:darwin_x86_64": "@node15_darwin_amd64//:toolchain", "@bazel_tools//src/conditions:windows": "@node15_windows_amd64//:toolchain", }), ) diff --git a/e2e/smoke/MODULE.bazel b/e2e/smoke/MODULE.bazel index ee6b2091b9..087721810d 100644 --- a/e2e/smoke/MODULE.bazel +++ b/e2e/smoke/MODULE.bazel @@ -30,10 +30,14 @@ use_repo( "node15_linux_amd64", "node15_windows_amd64", "node17_darwin_amd64", + "node17_darwin_arm64", "node17_linux_amd64", + "node17_linux_arm64", "node17_windows_amd64", "nodejs_darwin_amd64", + "nodejs_darwin_arm64", "nodejs_linux_amd64", + "nodejs_linux_arm64", "nodejs_toolchains", "nodejs_windows_amd64", ) diff --git a/nodejs/BUILD.bazel b/nodejs/BUILD.bazel index e66eda2d1b..6eb948568f 100644 --- a/nodejs/BUILD.bazel +++ b/nodejs/BUILD.bazel @@ -1,6 +1,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("//nodejs/private:nodejs_toolchains_repo.bzl", "PLATFORMS") load("//nodejs/private:user_build_settings.bzl", "user_args") +load(":node_toolchain_alias.bzl", "node_runtime_alias", "node_toolchain_alias") package(default_visibility = ["//visibility:public"]) @@ -19,12 +20,39 @@ bzl_library( ], ) -# This is the target rule authors should put in their "toolchains" -# attribute in order to get a node interpreter for the correct -# platform. -# See https://docs.bazel.build/versions/main/toolchains.html#writing-rules-that-use-toolchains +# A single binary distribution of a Node provides two different types of toolchains from the +# perspective of Bazel: + +# (1) The transpilation toolchain, which provides the Node runtime used to execute the transpiler +# (and type checker), as well as various helper tools and settings. +# +# Toolchains of this type typically have constraints on the execution platform so that their Node +# runtime can run the transpiler, but not on the target platform as Node transpilation outputs are +# platform independent. +# +# Obtain the associated NodeInfo via: +# ctx.toolchains["@bazel_tools//tools/jdk:toolchain_type"].nodeinfo toolchain_type(name = "toolchain_type") +# (2) The Node runtime that executable Node outputs (e.g., js_binary) will run on. +# +# Toolchains of this type typically have constraints on the target platform so that the runtime's +# native 'node' binary can be run there, but not on the execution platform as building an executable +# Node target only requires copying or symlinking the runtime, which can be done on any platform. +# +# Obtain the associated NodeRuntimeInfo via: +# ctx.toolchains["@bazel_tools//tools/jdk:runtime_toolchain_type"].nodeinfo +toolchain_type(name = "runtime_toolchain_type") + +# Points to toolchain[":runtime_toolchain_type"] +# Use this for executing and packaging Node applications for target platform (eg., js_binary, js_test or js_image_oci). +node_runtime_alias(name = "current_node_runtime") + +# Points to toolchain[":toolchain_type"] +# Use this for tools (eg., when action execution is needed). +node_toolchain_alias(name = "current_node_toolchain") + +# The platforms that are supported by the Node toolchains. [ platform( name = key, diff --git a/nodejs/node_toolchain_alias.bzl b/nodejs/node_toolchain_alias.bzl new file mode 100644 index 0000000000..a4170a8960 --- /dev/null +++ b/nodejs/node_toolchain_alias.bzl @@ -0,0 +1,53 @@ +# Copyright 2019 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. + +"""Node toolchain aliases using toolchain resolution.""" + +load(":semantics.bzl", "semantics") + +def _node_runtime_alias(ctx): + """Implementation of node_runtime_alias using toolchain resolution.""" + toolchain_info = ctx.toolchains[semantics.NODE_RUNTIME_TOOLCHAIN_TYPE] + toolchain = toolchain_info.nodeinfo + template_variable_info = toolchain_info.template_variables + default_info = toolchain_info.default + return [ + toolchain_info, + toolchain, + template_variable_info, + default_info, + ] + +node_runtime_alias = rule( + implementation = _node_runtime_alias, + toolchains = [semantics.NODE_RUNTIME_TOOLCHAIN], +) + +def _node_toolchain_alias(ctx): + """An implementation of node_toolchain_alias using toolchain resolution.""" + toolchain_info = ctx.toolchains[semantics.NODE_TOOLCHAIN_TYPE] + toolchain = toolchain_info.nodeinfo + template_variable_info = toolchain_info.template_variables + default_info = toolchain_info.default + return [ + toolchain_info, + toolchain, + template_variable_info, + default_info, + ] + +node_toolchain_alias = rule( + implementation = _node_toolchain_alias, + toolchains = [semantics.NODE_TOOLCHAIN], +) diff --git a/nodejs/private/nodejs_toolchains_repo.bzl b/nodejs/private/nodejs_toolchains_repo.bzl index 7758f3edb4..1550cab767 100644 --- a/nodejs/private/nodejs_toolchains_repo.bzl +++ b/nodejs/private/nodejs_toolchains_repo.bzl @@ -69,55 +69,42 @@ PLATFORMS = { } def _nodejs_toolchains_repo_impl(repository_ctx): - # Expose a concrete toolchain which is the result of Bazel resolving the toolchain - # for the execution or target platform. - # Workaround for https://github.com/bazelbuild/bazel/issues/14009 - starlark_content = """# Generated by nodejs_toolchains_repo.bzl - -# Forward all the providers -def _resolved_toolchain_impl(ctx): - toolchain_info = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"] - return [ - toolchain_info, - toolchain_info.default, - toolchain_info.nodeinfo, - toolchain_info.template_variables, - ] - -# Copied from java_toolchain_alias -# https://cs.opensource.google/bazel/bazel/+/master:tools/jdk/java_toolchain_alias.bzl -resolved_toolchain = rule( - implementation = _resolved_toolchain_impl, - toolchains = ["@rules_nodejs//nodejs:toolchain_type"], -) -""" - repository_ctx.file("defs.bzl", starlark_content) - - build_content = """# Generated by nodejs_toolchains_repo.bzl + # TODO(7.0) Drop support for deprecated alias + build_content = '''# Generated by nodejs_toolchains_repo.bzl # # These can be registered in the workspace file or passed to --extra_toolchains flag. # By default all these toolchains are registered by the nodejs_register_toolchains macro # so you don't normally need to interact with these targets. -load(":defs.bzl", "resolved_toolchain") - -resolved_toolchain(name = "resolved_toolchain", visibility = ["//visibility:public"]) +alias( + name = "resolved_toolchain", + actual = "@rules_nodejs//nodejs:current_node_runtime", + deprecation = """ +Use one of the following instead: +- @rules_nodejs//nodejs:current_node_runtime +- @rules_nodejs//nodejs:current_host_node_runtime +- @rules_nodejs//nodejs:current_node_toolchain +See https://github.com/bazel-contrib/rules_nodejs/issues/3795. +""", + visibility = ["//visibility:public"], +) -""" +''' for [platform, meta] in PLATFORMS.items(): build_content += """ toolchain( name = "{platform}_toolchain", exec_compatible_with = {compatible_with}, + target_compatible_with = {compatible_with}, # prevent Node from this toolchain being bundled by js_image_oci to incompatible target platforms (https://github.com/bazel-contrib/rules_nodejs/issues/3854) toolchain = "@{user_node_repository_name}_{platform}//:toolchain", toolchain_type = "@rules_nodejs//nodejs:toolchain_type", ) toolchain( - name = "{platform}_toolchain_target", + name = "{platform}_runtime_toolchain", target_compatible_with = {compatible_with}, toolchain = "@{user_node_repository_name}_{platform}//:toolchain", - toolchain_type = "@rules_nodejs//nodejs:toolchain_type", + toolchain_type = "@rules_nodejs//nodejs:runtime_toolchain_type", ) """.format( platform = platform, diff --git a/nodejs/repositories.bzl b/nodejs/repositories.bzl index 7d0cfbb76e..ac927a6a78 100644 --- a/nodejs/repositories.bzl +++ b/nodejs/repositories.bzl @@ -476,7 +476,7 @@ def nodejs_register_toolchains(name = DEFAULT_NODE_REPOSITORY, register = True, ) if register: native.register_toolchains( - "@%s_toolchains//:%s_toolchain_target" % (name, platform), + "@%s_toolchains//:%s_runtime_toolchain" % (name, platform), "@%s_toolchains//:%s_toolchain" % (name, platform), ) diff --git a/nodejs/semantics.bzl b/nodejs/semantics.bzl new file mode 100644 index 0000000000..830f84c64b --- /dev/null +++ b/nodejs/semantics.bzl @@ -0,0 +1,33 @@ +# Copyright 2021 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. +"""Rules NodeJS Semantics""" + +_NODE_TOOLCHAIN_TYPE = Label("//nodejs:toolchain_type") +_NODE_RUNTIME_TOOLCHAIN_TYPE = Label("//nodejs:runtime_toolchain_type") + +def _find_node_toolchain(ctx): + return ctx.toolchains[_NODE_TOOLCHAIN_TYPE].nodeinfo + +def _find_node_runtime_toolchain(ctx): + return ctx.toolchains[_NODE_RUNTIME_TOOLCHAIN_TYPE].nodeinfo + +semantics = struct( + NODE_TOOLCHAIN_LABEL = Label("//nodejs:current_node_toolchain"), + NODE_TOOLCHAIN_TYPE = _NODE_TOOLCHAIN_TYPE, + NODE_TOOLCHAIN = config_common.toolchain_type(_NODE_TOOLCHAIN_TYPE, mandatory = True), + find_node_toolchain = _find_node_toolchain, + NODE_RUNTIME_TOOLCHAIN_TYPE = _NODE_RUNTIME_TOOLCHAIN_TYPE, + NODE_RUNTIME_TOOLCHAIN = config_common.toolchain_type(_NODE_RUNTIME_TOOLCHAIN_TYPE, mandatory = True), + find_node_runtime_toolchain = _find_node_runtime_toolchain, +) diff --git a/nodejs/toolchain.bzl b/nodejs/toolchain.bzl index 804f8a3c95..9ebe8bda6c 100644 --- a/nodejs/toolchain.bzl +++ b/nodejs/toolchain.bzl @@ -162,7 +162,7 @@ def nodejs_toolchain( ``` Next, declare which execution platforms or target platforms the toolchain should be selected for - based on constraints. + based on constraints. A separate toolchain type is used for runtime target platform selection. ```starlark toolchain( @@ -174,6 +174,15 @@ def nodejs_toolchain( toolchain = ":toolchain", toolchain_type = "@rules_nodejs//nodejs:toolchain_type", ) + toolchain( + name = "my_nodejs_runtime", + target_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