blob: 1f63d8a91486173b6b1abcd4f8904fc97dc2a17c [file]
# Copyright 2026 The IREE Authors
#
# Licensed under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Platform-adaptive test rule.
iree_cc_test wraps a cc_binary as a test target. On native platforms it
symlinks to the binary. On wasm32 platforms it bundles the .wasm with a
WASI test entry point and runs via Node.js.
On wasm32, the entry point is determined by:
1. If an iree_wasm_entry target is found in cc_deps, its main JS file
is used as the entry point (with its srcs as bundler sandbox inputs).
2. Otherwise, the default wasm_test_main.mjs generic WASI harness is used.
"""
load(
"//build_tools/bazel:iree_wasm_library.bzl",
"IreeWasmEntryCollectionInfo",
"collect_and_bundle",
"collect_wasm_js",
)
def _iree_cc_test_impl(ctx):
is_wasm = ctx.target_platform_has_constraint(
ctx.attr._wasm32_constraint[platform_common.ConstraintValueInfo],
)
binary_info = ctx.attr.binary[DefaultInfo]
binary_executable = binary_info.files_to_run.executable
# Collect data files into runfiles.
data_runfiles = ctx.runfiles(files = ctx.files.data)
# Build environment dict, expanding $(rootpath) for data labels.
env = {}
for key, value in ctx.attr.env.items():
env[key] = ctx.expand_location(value, ctx.attr.data)
if not is_wasm:
# Native: symlink to the cc_binary executable.
executable = ctx.actions.declare_file(ctx.label.name)
ctx.actions.symlink(
output = executable,
target_file = binary_executable,
)
runfiles = ctx.runfiles().merge(binary_info.default_runfiles).merge(data_runfiles)
return [
DefaultInfo(
executable = executable,
runfiles = runfiles,
),
testing.TestEnvironment(env),
]
# Wasm: discover entry point from deps, falling back to the generic
# WASI test harness if no iree_wasm_entry target is present.
main_js = None
main_srcs = []
for dep in ctx.attr.cc_deps:
if IreeWasmEntryCollectionInfo in dep:
for entry in dep[IreeWasmEntryCollectionInfo].entries.to_list():
if main_js != None:
fail("Multiple iree_wasm_entry targets found in deps " +
"of %s; expected at most one" % ctx.label)
main_js = entry.main
main_srcs = list(entry.srcs)
if main_js == None:
main_js = ctx.file._test_main
output_mjs = collect_and_bundle(
ctx = ctx,
wasm_binary = binary_executable,
main_js = main_js,
cc_deps = ctx.attr.cc_deps,
bundler = ctx.executable._bundler,
main_srcs = main_srcs,
)
# Shell wrapper: locates the bundled .mjs in the runfiles tree and
# executes it via node. Test arguments are forwarded.
executable = ctx.actions.declare_file(ctx.label.name)
wrapper_content = (
"#!/bin/bash\n" +
'RUNFILES="${{RUNFILES_DIR:-$0.runfiles}}"\n' +
'exec node "$RUNFILES/{workspace}/{mjs_path}" "$@"\n'
).format(
workspace = ctx.workspace_name,
mjs_path = output_mjs.short_path,
)
ctx.actions.write(
output = executable,
content = wrapper_content,
is_executable = True,
)
runfiles = ctx.runfiles(
files = [binary_executable, output_mjs],
).merge(binary_info.default_runfiles)
return [DefaultInfo(
executable = executable,
runfiles = runfiles,
)]
iree_cc_test = rule(
implementation = _iree_cc_test_impl,
test = True,
attrs = {
"binary": attr.label(
mandatory = True,
providers = [DefaultInfo],
doc = "The cc_binary target to wrap as a test.",
),
"cc_deps": attr.label_list(
aspects = [collect_wasm_js],
doc = "Same deps as the cc_binary (for wasm JS companion collection).",
),
"data": attr.label_list(
allow_files = True,
doc = "Data files available to the test at runtime.",
),
"env": attr.string_dict(
doc = "Environment variables set for the test.",
),
"_wasm32_constraint": attr.label(
default = "@platforms//cpu:wasm32",
),
"_test_main": attr.label(
default = "//build_tools/wasm:wasm_test_main.mjs",
allow_single_file = True,
),
"_bundler": attr.label(
default = "//build_tools/wasm:wasm_binary_bundler",
executable = True,
cfg = "exec",
),
},
doc = "Platform-adaptive test rule. On native platforms, runs the " +
"cc_binary directly. On wasm32 platforms, bundles with a WASI " +
"test entry point and runs via Node.js. If an iree_wasm_entry " +
"target is found in deps, it overrides the default entry point.",
)