WebAssembly
Source: examples/wasm/
Cross-compile Fortran to WebAssembly using Emscripten.
Prerequisites
Add emsdk to your MODULE.bazel:
starlark
bazel_dep(name = "emsdk", version = "4.0.7")3.A. Hello World
wasm/
├── BUILD.bazel
└── hello.f90fortran
program hello
implicit none
print *, "Hello from wasm32 with rules_fortran!"
end program hellostarlark
# cross compilation to webassembly
load("@emsdk//emscripten_toolchain:wasm_cc_binary.bzl", "wasm_cc_binary")
load("@rules_cc//cc:defs.bzl", "cc_binary")
load("@rules_fortran//fortran:defs.bzl", "fortran_library")
# Example-3.A hello world
fortran_library(
name = "hello",
srcs = ["hello.f90"], # compiles the .f90 to an object file (.o)
)
# _QQmain: # internal Fortran program entry (called by main)
# (whole bunch of fortran asm...)
# main: # the standard C entry point
# call 5e <main+0xe> # call 1: _FortranAProgramStart
# call 63 <main+0x13> # call 2: _QQmain
# call 68 <main+0x18> # call 3: _FortranAProgramEndStatement
# xor %eax,%eax
# ret
# this `cc_binary` just wraps fortran intermediaries. main entry point from the
# original source is preserved. in this case, `main` and `_QQmain`.
# since there's no C main(), the linker picks up main from the Fortran library
cc_binary(
name = "hello_cc",
srcs = [], # look ma no source!
deps = [":hello"],
)
# produce final wasm output
wasm_cc_binary(
name = "hello_wasm",
cc_target = ":hello_cc",
outputs = [
"hello_cc.js",
"hello_cc.wasm",
],
)
# Example-3.B full lapacke client, only single for faster build
cc_binary(
name = "full",
srcs = [
"full.c",
],
deps = [
"@blas//:single",
"@lapack//:single",
"@lapacke//:single",
],
)
wasm_cc_binary(
name = "full_wasm",
cc_target = ":full",
outputs = [
"full.js",
"full.wasm",
],
)bash
bazel build //wasm:hello_wasm
node bazel-bin/wasm/hello_cc.jsHello from wasm32 with rules_fortran!The cc_binary target works as a native executable. Wrapping it with wasm_cc_binary produces WebAssembly output instead.
3.B. LAPACK
wasm/
├── BUILD.bazel
└── full.cc
#include <lapacke.h>
#include <stdio.h>
int main() {
float A[9] = {1, 2, 3, 4, 5, 6, 7, 8, 10};
int ipiv[3];
int info = LAPACKE_sgetrf(LAPACK_COL_MAJOR, 3, 3, A, 3, ipiv);
printf(info ? "FAIL\n" : "OK\n");
for (int i = 0; i < 9; i++)
printf("%8.2f%c", A[i], (i+1)%3 ? ' ' : '\n');
return info;
}starlark
cc_binary(
name = "full",
srcs = ["full.c"],
deps = [
"@blas//:single",
"@lapack//:single",
"@lapacke//:single",
],
)
wasm_cc_binary(
name = "full_wasm",
cc_target = ":full",
outputs = ["full.js", "full.wasm"],
)bash
bazel build //wasm:full_wasm
node bazel-bin/wasm/full.jsOK
3.00 0.33 0.67
6.00 2.00 0.50
10.00 3.67 -0.50