Skip to content

feat: Add WASI Preview 2 support and enhanced target coverage #3507

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

This repository provides rules for building [Rust](https://www.rust-lang.org/) projects with [Bazel](https://bazel.build/).

### Features

- Build Rust crates and binaries
- Automatic toolchain fetching and configuration
- Cross-compilation support
- Proto/gRPC support
- WebAssembly and WASI support (including wasm32-wasip1 and wasm32-wasip2)
- Interoperability with cc rules for mixed Rust/C/C++ projects
- Cargo workspace integration

## Community

General discussions and announcements take place in the [GitHub Discussions](https://github.com/bazelbuild/rules_rust/discussions), but there are
Expand Down
3 changes: 3 additions & 0 deletions ffi/cc/allocator_library/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ cc_library(
# If someone can make this work on Windows, please do!
# For now we will silently not supply any symbols, because it would be very messy to conditionally define the default allocator library on toolchains depending on the platform.
"@platforms//os:windows": ["empty.cc"],
# WASI doesn't need the allocator library - WASI runtime provides allocation
# Use empty srcs list to avoid needing archiving tools
"@platforms//os:wasi": [],
"//conditions:default": ["allocator_library.cc"],
}),
tags = ["manual"],
Expand Down
9 changes: 8 additions & 1 deletion ffi/cc/allocator_library/allocator_library.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
#include <stdint.h>
// Define types directly without including stdint.h
// This avoids absolute path inclusion issues with cross-compilation toolchains
typedef unsigned char uint8_t;
#ifdef _WIN32
typedef unsigned __int64 uintptr_t;
#else
typedef __SIZE_TYPE__ uintptr_t;
#endif

// This file has some exciting magic to get Rust code linking in a cc_binary.
// The Rust compiler generates some similar symbol aliases when it links, so we
Expand Down
17 changes: 17 additions & 0 deletions rust/platform/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ package(default_visibility = ["//visibility:public"])

declare_config_settings()

# WASI Preview version constraint settings
constraint_setting(
name = "wasi_version",
default_constraint_value = ":wasi_preview_1",
)

constraint_value(
name = "wasi_preview_1",
constraint_setting = ":wasi_version",
)

constraint_value(
name = "wasi_preview_2",
constraint_setting = ":wasi_version",
)


package_group(
name = "function_transition_allowlist",
packages = [
Expand Down
11 changes: 11 additions & 0 deletions rust/platform/platform.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,20 @@ def declare_config_settings():
constraint_values = [
"@platforms//cpu:wasm32",
"@platforms//os:wasi",
str(Label("//rust/platform:wasi_preview_1")),
],
)

native.platform(
name = "wasip2",
constraint_values = [
"@platforms//cpu:wasm32",
"@platforms//os:wasi",
str(Label("//rust/platform:wasi_preview_2")),
],
)


# Add alias for wasi to maintain backwards compatibility.
native.alias(
name = "wasi",
Expand Down
10 changes: 9 additions & 1 deletion rust/platform/triple.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def triple(triple):
- abi (str, optional): The abi to use or None if abi does not apply.
- str (str): Original string representation of the triple
"""
if triple in ("wasm32-wasi", "wasm32-wasip1"):
if triple in ("wasm32-wasi", "wasm32-wasip1", "wasm32-wasip2"):
trip = triple
if trip == "wasm32-wasi":
trip = "wasm32-wasip1"
Expand All @@ -32,6 +32,14 @@ def triple(triple):
abi = None,
str = trip,
)
elif triple == "wasm32v1-none":
return struct(
arch = "wasm32",
vendor = "v1",
system = "none",
abi = None,
str = triple,
)
elif triple in ("aarch64-fuchsia", "x86_64-fuchsia"):
return struct(
arch = triple.split("-")[0],
Expand Down
31 changes: 29 additions & 2 deletions rust/platform/triple_mappings.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ SUPPORTED_T2_PLATFORM_TRIPLES = {
"s390x-unknown-linux-gnu": _support(std = True, host_tools = True),
"thumbv7em-none-eabi": _support(std = True, host_tools = False),
"thumbv8m.main-none-eabi": _support(std = True, host_tools = False),
"wasm32-unknown-emscripten": _support(std = True, host_tools = False),
"wasm32-unknown-unknown": _support(std = True, host_tools = False),
"wasm32-wasip1": _support(std = True, host_tools = False),
"wasm32-wasip1-threads": _support(std = True, host_tools = False),
"wasm32-wasip2": _support(std = True, host_tools = False),
"x86_64-apple-ios": _support(std = True, host_tools = False),
"x86_64-linux-android": _support(std = True, host_tools = False),
"x86_64-unknown-freebsd": _support(std = True, host_tools = True),
Expand Down Expand Up @@ -138,7 +141,7 @@ _SYSTEM_TO_BUILTIN_SYS_SUFFIX = {
"dragonfly": None,
"eabi": "none",
"eabihf": "none",
"emscripten": None,
"emscripten": "emscripten",
"freebsd": "freebsd",
"fuchsia": "fuchsia",
"ios": "ios",
Expand All @@ -155,6 +158,7 @@ _SYSTEM_TO_BUILTIN_SYS_SUFFIX = {
"unknown": None,
"wasi": None,
"wasip1": None,
"wasip2": None,
"windows": "windows",
}

Expand All @@ -179,6 +183,7 @@ _SYSTEM_TO_BINARY_EXT = {
"unknown": ".wasm",
"wasi": ".wasm",
"wasip1": ".wasm",
"wasip2": ".wasm",
"windows": ".exe",
}

Expand All @@ -200,6 +205,7 @@ _SYSTEM_TO_STATICLIB_EXT = {
"unknown": "",
"wasi": "",
"wasip1": "",
"wasip2": "",
"windows": ".lib",
}

Expand All @@ -221,6 +227,7 @@ _SYSTEM_TO_DYLIB_EXT = {
"unknown": ".wasm",
"wasi": ".wasm",
"wasip1": ".wasm",
"wasip2": ".wasm",
"windows": ".dll",
}

Expand Down Expand Up @@ -270,6 +277,7 @@ _SYSTEM_TO_STDLIB_LINKFLAGS = {
"uwp": ["ws2_32.lib"],
"wasi": [],
"wasip1": [],
"wasip2": [],
"windows": ["advapi32.lib", "ws2_32.lib", "userenv.lib", "Bcrypt.lib"],
}

Expand Down Expand Up @@ -407,21 +415,40 @@ def triple_to_constraint_set(target_triple):
Returns:
list: A list of constraints (each represented by a list of strings)
"""
if target_triple in "wasm32-wasi":
if target_triple == "wasm32-wasi":
return [
"@platforms//cpu:wasm32",
"@platforms//os:wasi",
"@rules_rust//rust/platform:wasi_preview_1",
]
if target_triple == "wasm32-wasip1":
return [
"@platforms//cpu:wasm32",
"@platforms//os:wasi",
"@rules_rust//rust/platform:wasi_preview_1",
]
if target_triple == "wasm32-wasip2":
return [
"@platforms//cpu:wasm32",
"@platforms//os:wasi",
"@rules_rust//rust/platform:wasi_preview_2",
]
if target_triple == "wasm32-unknown-emscripten":
return [
"@platforms//cpu:wasm32",
"@platforms//os:emscripten",
]
if target_triple == "wasm32-unknown-unknown":
return [
"@platforms//cpu:wasm32",
"@platforms//os:none",
]
if target_triple == "wasm32-wasip1-threads":
return [
"@platforms//cpu:wasm32",
"@platforms//os:wasi",
"@rules_rust//rust/platform:wasi_preview_1",
]
if target_triple == "wasm64-unknown-unknown":
return [
"@platforms//cpu:wasm64",
Expand Down
14 changes: 13 additions & 1 deletion rust/toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,18 @@ def _make_libstd_and_allocator_ccinfo(
objects = depset(rust_stdlib_info.self_contained_files),
)

# Include C++ toolchain files as additional inputs for cross-compilation scenarios
additional_inputs = []
if cc_toolchain and cc_toolchain.all_files:
additional_inputs = cc_toolchain.all_files.to_list()

linking_context, _linking_outputs = cc_common.create_linking_context_from_compilation_outputs(
name = label.name,
actions = actions,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
compilation_outputs = compilation_outputs,
additional_inputs = additional_inputs,
)

cc_infos.append(CcInfo(
Expand Down Expand Up @@ -697,8 +703,14 @@ def _rust_toolchain_impl(ctx):
std,
)

# Include C++ toolchain files to ensure tools like 'ar' are available for cross-compilation
cc_toolchain, _ = find_cc_toolchain(ctx)
all_files_depsets = [sysroot.all_files]
if cc_toolchain and cc_toolchain.all_files:
all_files_depsets.append(cc_toolchain.all_files)

toolchain = platform_common.ToolchainInfo(
all_files = sysroot.all_files,
all_files = depset(transitive = all_files_depsets),
binary_ext = ctx.attr.binary_ext,
cargo = sysroot.cargo,
clippy_driver = sysroot.clippy,
Expand Down
3 changes: 3 additions & 0 deletions test/unit/ffi/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
load(":allocator_library_test.bzl", "allocator_library_test_suite")

allocator_library_test_suite(name = "allocator_library_test_suite")
40 changes: 40 additions & 0 deletions test/unit/ffi/allocator_library_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Analysis tests for allocator_library platform selection"""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("@rules_cc//cc:defs.bzl", "cc_library")

def _allocator_library_provides_ccinfo_test_impl(ctx):
env = analysistest.begin(ctx)

# Get the target under test
target_under_test = analysistest.target_under_test(env)

# Basic test: ensure the target provides CcInfo (this means it analyzed successfully)
asserts.true(env, CcInfo in target_under_test, "allocator_library should provide CcInfo")

# The fact that this test passes means the select() logic worked correctly
# and didn't fail due to missing WASI toolchain tools

return analysistest.end(env)

# Create analysis test rule that works without needing WASI toolchain
allocator_library_analysis_test = analysistest.make(
_allocator_library_provides_ccinfo_test_impl,
)

def allocator_library_test_suite(name):
"""Test suite for allocator_library platform behavior"""

# Test that allocator_library can be analyzed successfully
# This indirectly tests that our WASI select() fix works
allocator_library_analysis_test(
name = "allocator_library_analysis_test",
target_under_test = "//ffi/cc/allocator_library:allocator_library",
)

native.test_suite(
name = name,
tests = [
":allocator_library_analysis_test",
],
)
5 changes: 5 additions & 0 deletions test/unit/platform_triple/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
load(":platform_triple_test.bzl", "platform_triple_test_suite")
load(":wasi_platform_test.bzl", "wasi_platform_test_suite")

platform_triple_test_suite(
name = "platform_triple_test_suite",
)

wasi_platform_test_suite(
name = "wasi_platform_test_suite",
)
15 changes: 15 additions & 0 deletions test/unit/platform_triple/platform_triple_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,24 @@ def _construct_known_triples_test_impl(ctx):
_assert_parts(env, triple("aarch64-unknown-linux-musl"), "aarch64", "unknown", "linux", "musl")
_assert_parts(env, triple("thumbv7em-none-eabi"), "thumbv7em", None, "none", "eabi")
_assert_parts(env, triple("thumbv8m.main-none-eabi"), "thumbv8m.main", None, "none", "eabi")

# Test all WASM32 targets
_assert_parts(env, triple("wasm32-unknown-unknown"), "wasm32", "unknown", "unknown", None)
_assert_parts(env, triple("wasm32-unknown-emscripten"), "wasm32", "unknown", "emscripten", None)

# WASI targets - backward compatibility
_assert_parts(env, triple("wasm32-wasi"), "wasm32", "wasip1", "wasip1", None)

# WASI Preview 1
_assert_parts(env, triple("wasm32-wasip1"), "wasm32", "wasip1", "wasip1", None)
_assert_parts(env, triple("wasm32-wasip1-threads"), "wasm32", "wasip1", "threads", None)

# WASI Preview 2
_assert_parts(env, triple("wasm32-wasip2"), "wasm32", "wasip2", "wasip2", None)

# WebAssembly MVP target
_assert_parts(env, triple("wasm32v1-none"), "wasm32", "v1", "none", None)

_assert_parts(env, triple("x86_64-fuchsia"), "x86_64", "unknown", "fuchsia", None)

return unittest.end(env)
Expand Down
Loading