diff --git a/ffi/cc/allocator_library/BUILD.bazel b/ffi/cc/allocator_library/BUILD.bazel index 570a8af09c..64b41a73dd 100644 --- a/ffi/cc/allocator_library/BUILD.bazel +++ b/ffi/cc/allocator_library/BUILD.bazel @@ -3,6 +3,9 @@ load("@rules_cc//cc:defs.bzl", "cc_library") cc_library( name = "allocator_library", srcs = select({ + # WASI doesn't need the allocator library - WASI runtime provides allocation + # Use empty srcs list to avoid needing archiving tools + "@platforms//os:wasi": [], # Windows doesn't support weak symbol linkage. # 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. diff --git a/ffi/cc/allocator_library/allocator_library.cc b/ffi/cc/allocator_library/allocator_library.cc index b058f282ea..331c7587e9 100644 --- a/ffi/cc/allocator_library/allocator_library.cc +++ b/ffi/cc/allocator_library/allocator_library.cc @@ -1,4 +1,11 @@ -#include +// 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 diff --git a/rust/platform/BUILD.bazel b/rust/platform/BUILD.bazel index 56ed34620b..d5513b1e79 100644 --- a/rust/platform/BUILD.bazel +++ b/rust/platform/BUILD.bazel @@ -5,6 +5,22 @@ 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 = [ diff --git a/rust/platform/platform.bzl b/rust/platform/platform.bzl index 23d3a1704b..5187993cd2 100644 --- a/rust/platform/platform.bzl +++ b/rust/platform/platform.bzl @@ -107,6 +107,16 @@ 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")), ], ) diff --git a/rust/platform/triple.bzl b/rust/platform/triple.bzl index 87cd624226..61bdf903c9 100644 --- a/rust/platform/triple.bzl +++ b/rust/platform/triple.bzl @@ -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" @@ -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], diff --git a/rust/platform/triple_mappings.bzl b/rust/platform/triple_mappings.bzl index d28fe7470d..15a0910912 100644 --- a/rust/platform/triple_mappings.bzl +++ b/rust/platform/triple_mappings.bzl @@ -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), @@ -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", @@ -155,6 +158,7 @@ _SYSTEM_TO_BUILTIN_SYS_SUFFIX = { "unknown": None, "wasi": None, "wasip1": None, + "wasip2": None, "windows": "windows", } @@ -179,6 +183,7 @@ _SYSTEM_TO_BINARY_EXT = { "unknown": ".wasm", "wasi": ".wasm", "wasip1": ".wasm", + "wasip2": ".wasm", "windows": ".exe", } @@ -200,6 +205,7 @@ _SYSTEM_TO_STATICLIB_EXT = { "unknown": "", "wasi": "", "wasip1": "", + "wasip2": "", "windows": ".lib", } @@ -221,6 +227,7 @@ _SYSTEM_TO_DYLIB_EXT = { "unknown": ".wasm", "wasi": ".wasm", "wasip1": ".wasm", + "wasip2": ".wasm", "windows": ".dll", } @@ -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"], } @@ -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", diff --git a/rust/private/repository_utils.bzl b/rust/private/repository_utils.bzl index 27c08e78ea..5f9f48bf5a 100644 --- a/rust/private/repository_utils.bzl +++ b/rust/private/repository_utils.bzl @@ -19,7 +19,7 @@ load("//rust/private:common.bzl", "DEFAULT_NIGHTLY_ISO_DATE") DEFAULT_TOOLCHAIN_NAME_PREFIX = "toolchain_for" DEFAULT_STATIC_RUST_URL_TEMPLATES = ["https://static.rust-lang.org/dist/{}.tar.xz"] DEFAULT_NIGHTLY_VERSION = "nightly/{}".format(DEFAULT_NIGHTLY_ISO_DATE) -DEFAULT_EXTRA_TARGET_TRIPLES = ["wasm32-unknown-unknown", "wasm32-wasip1"] +DEFAULT_EXTRA_TARGET_TRIPLES = ["wasm32-unknown-unknown", "wasm32-wasip1", "wasm32-wasip2"] TINYJSON_KWARGS = dict( name = "rules_rust_tinyjson", diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl index dcb6963bff..055836f2f9 100644 --- a/rust/toolchain.bzl +++ b/rust/toolchain.bzl @@ -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( @@ -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, diff --git a/test/unit/ffi/BUILD.bazel b/test/unit/ffi/BUILD.bazel new file mode 100644 index 0000000000..6ff1e47feb --- /dev/null +++ b/test/unit/ffi/BUILD.bazel @@ -0,0 +1,3 @@ +load(":allocator_library_test.bzl", "allocator_library_test_suite") + +allocator_library_test_suite(name = "allocator_library_test_suite") diff --git a/test/unit/ffi/allocator_library_test.bzl b/test/unit/ffi/allocator_library_test.bzl new file mode 100644 index 0000000000..6ee5dca74a --- /dev/null +++ b/test/unit/ffi/allocator_library_test.bzl @@ -0,0 +1,40 @@ +"""Analysis tests for allocator_library platform selection""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") + +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", + ], + ) diff --git a/test/unit/platform_triple/BUILD.bazel b/test/unit/platform_triple/BUILD.bazel index 5f59a41674..bb30c72b66 100644 --- a/test/unit/platform_triple/BUILD.bazel +++ b/test/unit/platform_triple/BUILD.bazel @@ -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", +) diff --git a/test/unit/platform_triple/platform_triple_test.bzl b/test/unit/platform_triple/platform_triple_test.bzl index e6da3d6c8e..68fe79fa23 100644 --- a/test/unit/platform_triple/platform_triple_test.bzl +++ b/test/unit/platform_triple/platform_triple_test.bzl @@ -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) diff --git a/test/unit/platform_triple/wasi_platform_test.bzl b/test/unit/platform_triple/wasi_platform_test.bzl new file mode 100644 index 0000000000..c40d7fa0be --- /dev/null +++ b/test/unit/platform_triple/wasi_platform_test.bzl @@ -0,0 +1,117 @@ +"""Tests for WASI platform constraint mappings""" + +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") +load("//rust/platform:triple_mappings.bzl", "triple_to_constraint_set") + +def _wasi_platform_constraints_test_impl(ctx): + env = unittest.begin(ctx) + + # Test WASI Preview 1 targets + wasm32_wasip1_constraints = triple_to_constraint_set("wasm32-wasip1") + asserts.equals( + env, + [ + "@platforms//cpu:wasm32", + "@platforms//os:wasi", + "@rules_rust//rust/platform:wasi_preview_1", + ], + wasm32_wasip1_constraints, + "wasm32-wasip1 should map to WASI preview 1 constraints", + ) + + # Test backward compatibility + wasm32_wasi_constraints = triple_to_constraint_set("wasm32-wasi") + asserts.equals( + env, + [ + "@platforms//cpu:wasm32", + "@platforms//os:wasi", + "@rules_rust//rust/platform:wasi_preview_1", + ], + wasm32_wasi_constraints, + "wasm32-wasi should map to WASI preview 1 for backward compatibility", + ) + + # Test WASI Preview 1 with threads + wasm32_wasip1_threads_constraints = triple_to_constraint_set("wasm32-wasip1-threads") + asserts.equals( + env, + [ + "@platforms//cpu:wasm32", + "@platforms//os:wasi", + "@rules_rust//rust/platform:wasi_preview_1", + ], + wasm32_wasip1_threads_constraints, + "wasm32-wasip1-threads should map to WASI preview 1 constraints", + ) + + # Test WASI Preview 2 + wasm32_wasip2_constraints = triple_to_constraint_set("wasm32-wasip2") + asserts.equals( + env, + [ + "@platforms//cpu:wasm32", + "@platforms//os:wasi", + "@rules_rust//rust/platform:wasi_preview_2", + ], + wasm32_wasip2_constraints, + "wasm32-wasip2 should map to WASI preview 2 constraints", + ) + + # Test non-WASI wasm targets + wasm32_unknown_constraints = triple_to_constraint_set("wasm32-unknown-unknown") + asserts.equals( + env, + [ + "@platforms//cpu:wasm32", + "@platforms//os:none", + ], + wasm32_unknown_constraints, + "wasm32-unknown-unknown should not have WASI constraints", + ) + + wasm32_emscripten_constraints = triple_to_constraint_set("wasm32-unknown-emscripten") + asserts.equals( + env, + [ + "@platforms//cpu:wasm32", + "@platforms//os:emscripten", + ], + wasm32_emscripten_constraints, + "wasm32-unknown-emscripten should map to emscripten OS", + ) + + # Test wasm64 + wasm64_unknown_constraints = triple_to_constraint_set("wasm64-unknown-unknown") + asserts.equals( + env, + [ + "@platforms//cpu:wasm64", + "@platforms//os:none", + ], + wasm64_unknown_constraints, + "wasm64-unknown-unknown should map to wasm64 CPU", + ) + + return unittest.end(env) + +wasi_platform_constraints_test = unittest.make(_wasi_platform_constraints_test_impl) + +def wasi_platform_test_suite(name, **kwargs): + """Define a test suite for WASI platform constraint mappings + + Args: + name (str): The name of the test suite. + **kwargs (dict): Additional keyword arguments for the test_suite. + """ + wasi_platform_constraints_test( + name = "wasi_platform_constraints_test", + ) + + native.test_suite( + name = name, + tests = [ + ":wasi_platform_constraints_test", + ], + **kwargs + )