Skip to content

Commit bda1c9f

Browse files
authored
Support WebAssembly target platforms wasm{32,64}-unknown-unknown (#405)
1 parent a80f2b4 commit bda1c9f

20 files changed

+325
-17
lines changed

platforms/BUILD.bazel

+16
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,19 @@ platform(
4545
"@platforms//cpu:aarch64",
4646
],
4747
)
48+
49+
platform(
50+
name = "wasm32",
51+
constraint_values = [
52+
"@platforms//os:none",
53+
"@platforms//cpu:wasm32",
54+
],
55+
)
56+
57+
platform(
58+
name = "wasm64",
59+
constraint_values = [
60+
"@platforms//os:none",
61+
"@platforms//cpu:wasm64",
62+
],
63+
)

tests/MODULE.bazel

+37
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,40 @@ llvm.toolchain(
179179
exec_arch = "amd64",
180180
)
181181
use_repo(llvm, "llvm_toolchain_linux_exec")
182+
183+
# Toolchain example for WebAssembly.
184+
llvm.toolchain(
185+
name = "llvm_toolchain_wasm",
186+
# WebAssembly tests use a separate (newer) version of LLVM to exercise
187+
# support for experimental features such as wasm64.
188+
llvm_versions = {
189+
# The most recent LLVM as of 2024-10-17
190+
"": "19.1.0",
191+
},
192+
stdlib = {
193+
"wasm32": "libc",
194+
"wasm64": "none",
195+
},
196+
libclang_rt = {
197+
"@libclang_rt_wasm32//:libclang_rt.builtins-wasm32.a": "wasm32-unknown-unknown/libclang_rt.builtins.a",
198+
},
199+
)
200+
llvm.sysroot(
201+
name = "llvm_toolchain_wasm",
202+
label = "@wasi_sdk_sysroots//wasm32-wasip2",
203+
targets = ["wasm32"],
204+
)
205+
llvm.sysroot(
206+
name = "llvm_toolchain_wasm",
207+
label = "@wasi_sdk_sysroots//empty",
208+
targets = ["wasm64"],
209+
)
210+
211+
use_repo(llvm, "llvm_toolchain_wasm")
212+
register_toolchains("@llvm_toolchain_wasm//:all")
213+
214+
wasi_sdk_sysroots = use_repo_rule("//wasm:wasi_sdk.bzl", "wasi_sdk_sysroots")
215+
wasi_sdk_sysroots(name = "wasi_sdk_sysroots")
216+
217+
libclang_rt_wasm32 = use_repo_rule("//wasm:wasi_sdk.bzl", "libclang_rt_wasm32")
218+
libclang_rt_wasm32(name = "libclang_rt_wasm32")

tests/WORKSPACE

+35
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,41 @@ llvm_toolchain(
156156
urls = {"": ["https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang+llvm-17.0.6-x86_64-linux-gnu-ubuntu-22.04.tar.xz"]},
157157
)
158158

159+
# Toolchain example for WebAssembly.
160+
llvm_toolchain(
161+
name = "llvm_toolchain_wasm",
162+
libclang_rt = {
163+
"@libclang_rt_wasm32//:libclang_rt.builtins-wasm32.a": "wasm32-unknown-unknown/libclang_rt.builtins.a",
164+
},
165+
# WebAssembly tests use a separate (newer) version of LLVM to exercise
166+
# support for experimental features such as wasm64.
167+
llvm_versions = {
168+
# The most recent LLVM as of 2024-10-17
169+
"": "19.1.0",
170+
},
171+
stdlib = {
172+
"wasm32": "libc",
173+
"wasm64": "none",
174+
},
175+
sysroot = {
176+
"wasm32": "@wasi_sdk_sysroots//wasm32-wasip2",
177+
"wasm64": "@wasi_sdk_sysroots//empty",
178+
},
179+
)
180+
181+
load(
182+
"@llvm_toolchain_wasm//:toolchains.bzl",
183+
llvm_register_toolchains_wasm = "llvm_register_toolchains",
184+
)
185+
186+
llvm_register_toolchains_wasm()
187+
188+
load("//wasm:wasi_sdk.bzl", "libclang_rt_wasm32", "wasi_sdk_sysroots")
189+
190+
libclang_rt_wasm32(name = "libclang_rt_wasm32")
191+
192+
wasi_sdk_sysroots(name = "wasi_sdk_sysroots")
193+
159194
## Test dependencies.
160195

161196
# Well known repos; present here only for testing.

tests/scripts/debian_test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ set -exuo pipefail
3030
# Common setup
3131
export DEBIAN_FRONTEND=noninteractive
3232
apt-get -qq update
33-
apt-get -qq -y install curl libtinfo5 zlib1g-dev >/dev/null
33+
apt-get -qq -y install curl libtinfo5 libxml2 zlib1g-dev >/dev/null
3434
# The above command gives some verbose output that can not be silenced easily.
3535
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=288778
3636

tests/scripts/linux_sysroot_test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ set -exuo pipefail
3030
# Common setup
3131
export DEBIAN_FRONTEND=noninteractive
3232
apt-get -qq update
33-
apt-get -qq -y install curl libtinfo5 zlib1g-dev >/dev/null
33+
apt-get -qq -y install curl libtinfo5 libxml2 zlib1g-dev >/dev/null
3434
# The above command gives some verbose output that can not be silenced easily.
3535
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=288778
3636

tests/scripts/run_docker_exec_test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ docker build --platform=linux/amd64 --pull --tag=bazel-docker-sandbox - <<-EOF
4040
FROM ${base_image}
4141
ENV DEBIAN_FRONTEND=noninteractive
4242
RUN apt-get -qq update && \
43-
apt-get -qq -y install libtinfo5 zlib1g-dev libxml2
43+
apt-get -qq -y install libtinfo5 libxml2 zlib1g-dev libxml2
4444
EOF
4545

4646
build_args=(

tests/scripts/run_tests.sh

+26-1
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616
set -euo pipefail
1717

1818
toolchain_name=""
19+
disable_wasm_tests=""
1920

20-
while getopts "t:h" opt; do
21+
while getopts "t:hW" opt; do
2122
case "${opt}" in
2223
"t") toolchain_name="${OPTARG}" ;;
2324
"h")
2425
echo "Usage:"
2526
echo "-t - Toolchain name to use for testing; default is llvm_toolchain"
2627
exit 2
2728
;;
29+
"W")
30+
disable_wasm_tests="yes"
31+
;;
2832
*)
2933
echo "invalid option: -${OPTARG}"
3034
exit 1
@@ -62,3 +66,24 @@ fi
6266
# Note that the following flags are currently known to cause issues in migration tests:
6367
# --incompatible_disallow_struct_provider_syntax # https://github.com/bazelbuild/bazel/issues/7347
6468
# --incompatible_no_rule_outputs_param # from rules_rust
69+
70+
# WebAssembly tests use a separate (newer) version of LLVM to exercise support
71+
# for experimental features such as wasm64, which can cause the CI environment
72+
# to run out of disk space.
73+
#
74+
# Mitigate this by expunging the workspace before trying to build Wasm targets.
75+
if [[ -z ${toolchain_name} && -z ${disable_wasm_tests} ]]; then
76+
# Redefine `test_args` without `--linkopt=-Wl,-v`, which breaks `wasm-ld`.
77+
#
78+
# https://github.com/llvm/llvm-project/issues/112836
79+
test_args=(
80+
"--copt=-v"
81+
"--linkopt=-Wl,-t"
82+
)
83+
wasm_targets=(
84+
"//wasm:all"
85+
)
86+
"${bazel}" clean --expunge
87+
"${bazel}" ${TEST_MIGRATION:+"--strict"} --bazelrc=/dev/null test \
88+
"${common_test_args[@]}" "${test_args[@]}" "${wasm_targets[@]}"
89+
fi

tests/scripts/ubuntu_20_04_test.sh

+6-2
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@ set -exuo pipefail
3030
# Common setup
3131
export DEBIAN_FRONTEND=noninteractive
3232
apt-get -qq update
33-
apt-get -qq -y install apt-utils curl libtinfo5 pkg-config zlib1g-dev >/dev/null
33+
apt-get -qq -y install apt-utils curl libtinfo5 libxml2 pkg-config zlib1g-dev >/dev/null
3434
# The above command gives some verbose output that can not be silenced easily.
3535
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=288778
3636
37+
# The WebAssembly tests use an LLVM version that is too new for the GNU libc
38+
# distributed in Ubuntu 20.04.
39+
disable_wasm_tests='-W'
40+
3741
# Run tests
3842
cd /src
39-
tests/scripts/run_tests.sh
43+
tests/scripts/run_tests.sh \${disable_wasm_tests}
4044
"""
4145
done

tests/scripts/ubuntu_22_04_test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ set -exuo pipefail
3030
# Common setup
3131
export DEBIAN_FRONTEND=noninteractive
3232
apt-get -qq update
33-
apt-get -qq -y install curl libtinfo5 zlib1g-dev >/dev/null
33+
apt-get -qq -y install curl libtinfo5 libxml2 zlib1g-dev >/dev/null
3434
# The above command gives some verbose output that can not be silenced easily.
3535
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=288778
3636

tests/transitions.bzl

+24-4
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ dwp_file = rule(
9797
},
9898
)
9999

100-
def _transition_library_to_platform_transition_impl(_, attr):
100+
def _transition_to_platform_transition_impl(_, attr):
101101
return {"//command_line_option:platforms": str(attr.platform)}
102102

103-
_transition_library_to_platform_transition = transition(
104-
implementation = _transition_library_to_platform_transition_impl,
103+
_transition_to_platform_transition = transition(
104+
implementation = _transition_to_platform_transition_impl,
105105
inputs = [],
106106
outputs = ["//command_line_option:platforms"],
107107
)
@@ -114,7 +114,27 @@ def _transition_library_to_platform_impl(ctx):
114114
transition_library_to_platform = rule(
115115
implementation = _transition_library_to_platform_impl,
116116
attrs = {
117-
"lib": attr.label(mandatory = True, cfg = _transition_library_to_platform_transition),
117+
"lib": attr.label(mandatory = True, cfg = _transition_to_platform_transition),
118+
"platform": attr.label(mandatory = True),
119+
"_allowlist_function_transition": attr.label(
120+
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
121+
),
122+
},
123+
)
124+
125+
def _transition_binary_to_platform_impl(ctx):
126+
out = ctx.actions.declare_file(ctx.attr.name)
127+
ctx.actions.symlink(output = out, target_file = ctx.file.bin)
128+
return DefaultInfo(files = depset([out]))
129+
130+
transition_binary_to_platform = rule(
131+
implementation = _transition_binary_to_platform_impl,
132+
attrs = {
133+
"bin": attr.label(
134+
mandatory = True,
135+
allow_single_file = True,
136+
cfg = _transition_to_platform_transition,
137+
),
118138
"platform": attr.label(mandatory = True),
119139
"_allowlist_function_transition": attr.label(
120140
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",

tests/wasm/BUILD.bazel

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
load("@bazel_skylib//rules:build_test.bzl", "build_test")
2+
load("@rules_cc//cc:defs.bzl", "cc_binary")
3+
load("//:transitions.bzl", "transition_binary_to_platform")
4+
5+
build_test(
6+
name = "wasm_targets_test",
7+
targets = [
8+
":wasm32_strlen",
9+
":wasm32_strlen_nolibc",
10+
":wasm64_strlen_nolibc",
11+
],
12+
)
13+
14+
cc_binary(
15+
name = "wasm_strlen",
16+
srcs = ["wasm_strlen.c"],
17+
linkopts = ["-Wl,--no-entry"],
18+
tags = ["manual"],
19+
)
20+
21+
transition_binary_to_platform(
22+
name = "wasm32_strlen",
23+
bin = ":wasm_strlen",
24+
platform = "@toolchains_llvm//platforms:wasm32",
25+
)
26+
27+
cc_binary(
28+
name = "wasm_strlen_nolibc",
29+
srcs = ["wasm_strlen_nolibc.c"],
30+
linkopts = ["-Wl,--no-entry"],
31+
tags = ["manual"],
32+
)
33+
34+
transition_binary_to_platform(
35+
name = "wasm32_strlen_nolibc",
36+
bin = ":wasm_strlen_nolibc",
37+
platform = "@toolchains_llvm//platforms:wasm32",
38+
)
39+
40+
transition_binary_to_platform(
41+
name = "wasm64_strlen_nolibc",
42+
bin = ":wasm_strlen_nolibc",
43+
platform = "@toolchains_llvm//platforms:wasm64",
44+
)

tests/wasm/wasi_sdk.bzl

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
_SYSROOT_BUILD = """
2+
filegroup(
3+
name = {name},
4+
srcs = glob(["include/**/*", "lib/**/*", "share/**/*"], allow_empty=True),
5+
visibility = ["//visibility:public"],
6+
)
7+
"""
8+
9+
_WASI_SDK_ABIS = [
10+
"wasm32-wasi",
11+
"wasm32-wasip1",
12+
"wasm32-wasip1-threads",
13+
"wasm32-wasip2",
14+
"wasm32-wasi-threads",
15+
]
16+
17+
def _wasi_sdk_sysroots(ctx):
18+
ctx.download_and_extract(
19+
integrity = "sha256-NRcvfSeZSFsVpGsdh/UKWF2RXsZiCA8AXZkVOlCIjwg=",
20+
stripPrefix = "wasi-sysroot-24.0",
21+
url = ["https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sysroot-24.0.tar.gz"],
22+
)
23+
24+
ctx.file("empty/BUILD.bazel", _SYSROOT_BUILD.format(
25+
name = repr("empty"),
26+
))
27+
28+
for abi in _WASI_SDK_ABIS:
29+
ctx.file("%s/BUILD.bazel" % (abi,), _SYSROOT_BUILD.format(
30+
name = repr(abi),
31+
))
32+
ctx.execute(["mv", "include/" + abi, "%s/include" % (abi,)])
33+
ctx.execute(["mv", "lib/" + abi, "%s/lib" % (abi,)])
34+
ctx.execute(["mv", "share/" + abi, "%s/share" % (abi,)])
35+
36+
wasi_sdk_sysroots = repository_rule(_wasi_sdk_sysroots)
37+
38+
def _libclang_rt_wasm32(ctx):
39+
ctx.file("BUILD.bazel", """
40+
exports_files(glob(["*.a"]))
41+
""")
42+
43+
ctx.download_and_extract(
44+
integrity = "sha256-fjPA33WLkEabHePKFY4tCn9xk01YhFJbpqNy3gs7Dsc=",
45+
stripPrefix = "libclang_rt.builtins-wasm32-wasi-24.0",
46+
url = ["https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/libclang_rt.builtins-wasm32-wasi-24.0.tar.gz"],
47+
)
48+
49+
libclang_rt_wasm32 = repository_rule(_libclang_rt_wasm32)

tests/wasm/wasm_strlen.c

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <stdint.h>
2+
#include <string.h>
3+
4+
__attribute__((export_name("strlen")))
5+
uint32_t wasm_strlen(char *s) {
6+
return strlen(s);
7+
}

tests/wasm/wasm_strlen_nolibc.c

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__attribute__((export_name("strlen")))
2+
unsigned long wasm_strlen(char *s) {
3+
unsigned long len = 0;
4+
for (; *s; len++) {}
5+
return len;
6+
}

toolchain/BUILD.llvm_repo

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ filegroup(
4141
srcs = [
4242
"bin/ld.lld",
4343
"bin/ld64.lld",
44+
"bin/wasm-ld",
4445
],
4546
)
4647

0 commit comments

Comments
 (0)