From 4bb5fb65a9cdd35b5442273efa8c9bf0bb1a2130 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Mon, 1 Jun 2026 12:42:08 +0200 Subject: [PATCH 1/3] Cursor: Refactor using best practices so that the build can create wasm targets without breaking "bazel build --config=wasm //..." --- .bazelrc | 4 + .github/workflows/ci_wasm.yml | 4 +- BUILD.bazel | 2 + docs/wasm_build.md | 108 +++++----------- examples/BUILD.bazel | 118 ++++++------------ examples/wasm/BUILD.bazel | 28 +++++ library/src/BUILD.bazel | 10 -- library/src/heuristic_sorting/BUILD.bazel | 8 -- library/src/lookup_tables/BUILD.bazel | 8 -- library/src/moves/BUILD.bazel | 8 -- library/src/solver_context/BUILD.bazel | 8 -- library/src/system/BUILD.bazel | 8 -- library/src/trans_table/BUILD.bazel | 11 -- library/src/utility/BUILD.bazel | 9 -- library/tests/BUILD.bazel | 4 + library/tests/heuristic_sorting/BUILD.bazel | 9 +- library/tests/moves/BUILD.bazel | 3 +- .../regression/heuristic_sorting/BUILD.bazel | 3 + library/tests/solve_board/BUILD.bazel | 4 + library/tests/system/BUILD.bazel | 17 +++ library/tests/trans_table/BUILD.bazel | 5 +- library/tests/utility/BUILD.bazel | 5 + wasm/BUILD.bazel | 1 + wasm_compat.bzl | 15 +++ 24 files changed, 164 insertions(+), 236 deletions(-) create mode 100644 examples/wasm/BUILD.bazel create mode 100644 wasm/BUILD.bazel create mode 100644 wasm_compat.bzl diff --git a/.bazelrc b/.bazelrc index d0ae7bf8..f637e4eb 100644 --- a/.bazelrc +++ b/.bazelrc @@ -49,8 +49,12 @@ build:tsan --compilation_mode=dbg # WebAssembly (WASM) configuration # Usage: bazel build --config=wasm //... # Compiles using the hermetic emsdk toolchain downloaded automatically by Bazel. +# Targets tagged "native-only" (Python, tests, most examples) are skipped. build:wasm --platforms=@emsdk//:platform_wasm build:wasm --cpu=wasm build:wasm --cxxopt=-std=c++20 build:wasm --host_cxxopt=-std=c++20 build:wasm --compilation_mode=opt +build:wasm --build_tag_filters=-native-only +# Python bindings and C++ unit tests require the host toolchain. +build:wasm --deleted_packages=python,library/tests diff --git a/.github/workflows/ci_wasm.yml b/.github/workflows/ci_wasm.yml index 7b0d9fcb..516ee02c 100644 --- a/.github/workflows/ci_wasm.yml +++ b/.github/workflows/ci_wasm.yml @@ -22,8 +22,8 @@ jobs: # 3️⃣ Build WASM targets (hermetic emsdk toolchain downloaded by Bazel) - name: Build WASM targets - run: bazel build --config=wasm --verbose_failures //examples:all_examples_wasm + run: bazel build --config=wasm --verbose_failures //... # 4️⃣ Smoke test: run solve_board under Node.js — pass if it does not crash - name: Smoke test solve_board_wasm - run: node bazel-bin/examples/solve_board.js + run: node bazel-bin/examples/wasm/solve_board.js diff --git a/BUILD.bazel b/BUILD.bazel index 02ea9a23..75eb3a9a 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -121,6 +121,7 @@ EOF tags = [ "manual", "local", + "native-only", "no-remote", "no-remote-cache", ], @@ -134,6 +135,7 @@ cc_library( cc_library( name = "testable_dds", + tags = ["native-only"], deps = ["//library/src:testable_dds"], visibility = [ "//library/tests:__pkg__", diff --git a/docs/wasm_build.md b/docs/wasm_build.md index 9cfca6db..2d2a2157 100644 --- a/docs/wasm_build.md +++ b/docs/wasm_build.md @@ -13,107 +13,70 @@ The Emscripten SDK (emsdk) does NOT need to be manually installed. Bazel will au ## Building WASM Examples -### Build All Examples +### Build all WASM-compatible targets + +Native-only targets (Python bindings, C++ tests, most examples) are skipped automatically: ```bash -cd /workspaces/dds -bazel build //examples:all_examples_wasm +bazel build --config=wasm //... ``` -### Build Specific Example +### Build WASM examples only ```bash -bazel build //examples:solve_board_wasm +bazel build --config=wasm //examples/wasm:all_examples_wasm ``` -### Output Files +The alias `//examples:all_examples_wasm` points at the same filegroup. -the output files will be located in: -``` -bazel-bin/examples/ +### Build a specific example + +```bash +bazel build --config=wasm //examples/wasm:solve_board_wasm ``` -Depending on the target, you'll get: -- `target.js` - JavaScript bindings -- `target.wasm` - WebAssembly binary +### Output Files +Output files are under `bazel-bin/examples/wasm/` (wasm_cc_binary output layout): -## Available WASM Targets +- `solve_board.js` / `solve_board.wasm` +- `AnalysePlayBin.js` / `AnalysePlayBin.wasm` -The following example targets are available for WASM builds: - -### Implemented Examples -- `solve_board` - Solves a single board (produces .js and .wasm) +## Available WASM Targets -- `analyse_play_bin` - Analyze play from binary format +WASM rules live in `examples/wasm/BUILD.bazel` and wrap native `cc_binary` targets in `examples/`: +- `solve_board_wasm` — solves a single board +- `analyse_play_bin_wasm` — analyze play from binary format ## WASM Build Configuration -The WASM build is configured through: - -1. **BUILD.bazel** - Defines the WASM config_setting: - ```python - config_setting( - name = "build_wasm", - values = {"cpu": "wasm"}, - ) - ``` - -2. **CPPVARIABLES.bzl** - Specifies WASM-specific compiler flags: - - Optimization: `-O3 -flto` - - Exceptions: `-fexceptions` - - Define: `-D__WASM__` - -3. **.bazelrc** - Contains the `wasm` profile: - ``` - build:wasm --platforms=@emsdk//:platform_wasm - build:wasm --cpu=wasm - build:wasm --cxxopt=-std=c++20 - build:wasm --host_cxxopt=-std=c++20 - build:wasm --compilation_mode=opt - ``` - -## Running WASM Examples - -After building, you can run the examples: +1. **`BUILD.bazel`** — `//:build_wasm` matches `--cpu=wasm` from the `wasm` config +2. **`wasm_compat.bzl`** — shared Emscripten link flags (`WASM_LINKOPTS`) +3. **`CPPVARIABLES.bzl`** — WASM compiler flags and `__WASM__` define +4. **`.bazelrc`** — `wasm` config (platform, `--build_tag_filters=-native-only`) -### Node.js (requires Node.js installed) +Targets tagged `native-only` are excluded from `bazel build --config=wasm //...` (most examples, Doxygen). The `python` and `library/tests` packages are omitted entirely via `--deleted_packages`. -```bash -node bazel-bin/examples/solve_board.js -``` +## Running WASM Examples -### Web Browser (TODO) +### Node.js -For HTML targets, open the generated HTML file in a web browser: ```bash -# Copy the output files to a web-accessible location -cp bazel-bin/examples/solve_board.* /path/to/webserver/ - -# Then open in browser at http://localhost:8000/solve_board.html +node bazel-bin/examples/wasm/solve_board.js ``` ## Compilation Flags -The WASM build uses the following key flags: - | Flag | Purpose | |------|---------| | `-O3` | Aggressive optimization | | `-flto` | Link-time optimization | | `-fexceptions` | Enable C++ exceptions | -| `-D__WASM__` | Defines `__WASM__` preprocessor constant | +| `-D__WASM__` | Preprocessor constant for WASM builds | | `-sWASM=1` | Emscripten WASM output (link flag) | | `-sALLOW_MEMORY_GROWTH=1` | Allow heap growth at runtime | -| `-sINITIAL_MEMORY=268435456` | Configure 256MB initial memory | - -## C++ Standard - -The WASM build uses C++20 as specified in `.bazelrc`: -``` -build:wasm --cxxopt=-std=c++20 -``` +| `-sINITIAL_MEMORY=268435456` | 256MB initial memory | ## Related Documentation @@ -121,16 +84,3 @@ build:wasm --cxxopt=-std=c++20 - [Bazel Build System](https://bazel.build/docs) - [DDS C++ API](c++_interface.md) - [Build System Overview](BUILD_SYSTEM.md) - -## Next Steps - -To integrate WASM builds into CI/CD: -1. See `.github/workflows/ci_linux.yml` and `.github/workflows/ci_macos.yml` -2. Store WASM artifacts for download/release - -## Development Notes - -- The `__WASM__` preprocessor constant is added initially to bypass error, need to check again whether we can remove -- Some threading and platform-specific features are disabled for WASM -- The build flow for a reusable library wasm -- A good HTML example diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index e577e567..4e6f1000 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -1,60 +1,6 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//:CPPVARIABLES.bzl", "DDS_CPPOPTS", "DDS_LINKOPTS", "DDS_LOCAL_DEFINES") -load("@emsdk//emscripten_toolchain:wasm_rules.bzl", "wasm_cc_binary") - -filegroup( - name = "solve_board_wasm_inputs", - srcs = [ - "hands.cpp", - "solve_board.cpp", - "//library/src:dds_wasm_sources", - "//library/src:testable_dds_headers", - "//library/src/heuristic_sorting:wasm_sources", - "//library/src/lookup_tables:wasm_sources", - "//library/src/moves:wasm_sources", - "//library/src/solver_context:wasm_sources", - "//library/src/system:wasm_sources", - "//library/src/trans_table:wasm_sources", - "//library/src/utility:wasm_sources", - ], -) - -filegroup( - name = "analyse_play_bin_wasm_inputs", - srcs = [ - "hands.cpp", - "analyse_play_bin.cpp", - "//library/src:dds_wasm_sources", - "//library/src:testable_dds_headers", - "//library/src/heuristic_sorting:wasm_sources", - "//library/src/lookup_tables:wasm_sources", - "//library/src/moves:wasm_sources", - "//library/src/solver_context:wasm_sources", - "//library/src/system:wasm_sources", - "//library/src/trans_table:wasm_sources", - "//library/src/utility:wasm_sources", - ], -) - -wasm_cc_binary( - name = "solve_board_wasm", - cc_target = ":solve_board", - outputs = [ - "solve_board.js", - "solve_board.wasm", - ], - tags = ["manual"], -) - -wasm_cc_binary( - name = "analyse_play_bin_wasm", - cc_target = ":AnalysePlayBin", - outputs = [ - "AnalysePlayBin.js", - "AnalysePlayBin.wasm", - ], - tags = ["manual"], -) +load("//:wasm_compat.bzl", "WASM_LINKOPTS") # Examples use legacy C-style code, so we need to suppress certain warnings EXAMPLES_CPPOPTS = DDS_CPPOPTS + select({ @@ -73,14 +19,9 @@ EXAMPLES_LOCAL_DEFINES = DDS_LOCAL_DEFINES + select({ "//conditions:default": [], }) -# WASM-specific link flags for em++ output (produces .html, .js, .wasm) +# Emscripten link flags for examples built as WASM (see //examples/wasm). EXAMPLES_LINKOPTS_WASM = select({ - "//:build_wasm": [ - "-sWASM=1", - "-fexceptions", - "-sALLOW_MEMORY_GROWTH=1", - "-sINITIAL_MEMORY=268435456", - ], + "//:build_wasm": WASM_LINKOPTS, "//conditions:default": [], }) @@ -102,8 +43,9 @@ cc_binary( name = "analyse_all_plays_bin", srcs = ["analyse_all_plays_bin.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -115,8 +57,9 @@ cc_binary( name = "analyse_all_plays_pbn", srcs = ["analyse_all_plays_pbn.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -130,6 +73,7 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, local_defines = EXAMPLES_LOCAL_DEFINES, + visibility = ["//examples/wasm:__pkg__"], deps = [ ":hands", "//library/src:dds", @@ -141,8 +85,9 @@ cc_binary( name = "analyse_play_pbn", srcs = ["analyse_play_pbn.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -154,8 +99,9 @@ cc_binary( name = "calc_all_tables", srcs = ["calc_all_tables.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -167,8 +113,9 @@ cc_binary( name = "calc_all_tables_pbn", srcs = ["calc_all_tables_pbn.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -180,8 +127,9 @@ cc_binary( name = "calc_dd_table", srcs = ["calc_dd_table.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -193,8 +141,9 @@ cc_binary( name = "calc_dd_table_pbn", srcs = ["calc_dd_table_pbn.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -206,8 +155,9 @@ cc_binary( name = "dealer_par", srcs = ["dealer_par.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -219,8 +169,9 @@ cc_binary( name = "par", srcs = ["par.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -232,8 +183,9 @@ cc_binary( name = "solve_all_boards", srcs = ["solve_all_boards.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -247,6 +199,7 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, local_defines = EXAMPLES_LOCAL_DEFINES, + visibility = ["//examples/wasm:__pkg__"], deps = [ ":hands", "//library/src:dds", @@ -258,8 +211,9 @@ cc_binary( name = "solve_board_pbn", srcs = ["solve_board_pbn.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -271,8 +225,9 @@ cc_binary( name = "migration_example", srcs = ["migration_example.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ "//library/src:dds", "//library/src/api:api_definitions", @@ -283,8 +238,9 @@ cc_binary( name = "calc_par_context_example", srcs = ["calc_par_context_example.cpp"], copts = EXAMPLES_CPPOPTS, - linkopts = DDS_LINKOPTS + EXAMPLES_LINKOPTS_WASM, + linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, + tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -293,9 +249,10 @@ cc_binary( ], ) -# Convenience target to build all examples +# Convenience target to build all native examples filegroup( name = "all_examples", + tags = ["native-only"], srcs = [ ":analyse_all_plays_bin", ":analyse_all_plays_pbn", @@ -315,11 +272,8 @@ filegroup( ], ) -filegroup( +# Backward-compatible alias; prefer //examples/wasm:all_examples_wasm. +alias( name = "all_examples_wasm", - srcs = [ - ":analyse_play_bin_wasm", - ":solve_board_wasm", - ], - tags = ["manual"], + actual = "//examples/wasm:all_examples_wasm", ) diff --git a/examples/wasm/BUILD.bazel b/examples/wasm/BUILD.bazel new file mode 100644 index 00000000..58ac4d7a --- /dev/null +++ b/examples/wasm/BUILD.bazel @@ -0,0 +1,28 @@ +load("@emsdk//emscripten_toolchain:wasm_rules.bzl", "wasm_cc_binary") + +wasm_cc_binary( + name = "solve_board_wasm", + cc_target = "//examples:solve_board", + outputs = [ + "solve_board.js", + "solve_board.wasm", + ], +) + +wasm_cc_binary( + name = "analyse_play_bin_wasm", + cc_target = "//examples:AnalysePlayBin", + outputs = [ + "AnalysePlayBin.js", + "AnalysePlayBin.wasm", + ], +) + +filegroup( + name = "all_examples_wasm", + srcs = [ + ":analyse_play_bin_wasm", + ":solve_board_wasm", + ], + visibility = ["//visibility:public"], +) diff --git a/library/src/BUILD.bazel b/library/src/BUILD.bazel index ca141ddd..730bc3b7 100644 --- a/library/src/BUILD.bazel +++ b/library/src/BUILD.bazel @@ -64,16 +64,6 @@ filegroup( ], ) -filegroup( - name = "dds_wasm_sources", - srcs = glob([ - "**/*.cpp", - ]), - visibility = [ - "//examples:__pkg__", - ], -) - cc_library( name = "testable_dds", srcs = ["//library/src:testable_dds_sources"], diff --git a/library/src/heuristic_sorting/BUILD.bazel b/library/src/heuristic_sorting/BUILD.bazel index e6e7ffb1..6ce9cdcd 100644 --- a/library/src/heuristic_sorting/BUILD.bazel +++ b/library/src/heuristic_sorting/BUILD.bazel @@ -44,12 +44,4 @@ cc_library( "//library/tests/heuristic_sorting:__pkg__", "//library/tests/regression/heuristic_sorting:__pkg__", ], -) - -filegroup( - name = "wasm_sources", - srcs = ["heuristic_sorting.cpp"], - visibility = [ - "//examples:__pkg__", - ], ) \ No newline at end of file diff --git a/library/src/lookup_tables/BUILD.bazel b/library/src/lookup_tables/BUILD.bazel index 2e35514c..76f9c93f 100644 --- a/library/src/lookup_tables/BUILD.bazel +++ b/library/src/lookup_tables/BUILD.bazel @@ -14,11 +14,3 @@ cc_library( linkopts = DDS_LINKOPTS, local_defines = DDS_LOCAL_DEFINES, ) - -filegroup( - name = "wasm_sources", - srcs = ["lookup_tables.cpp"], - visibility = [ - "//examples:__pkg__", - ], -) diff --git a/library/src/moves/BUILD.bazel b/library/src/moves/BUILD.bazel index 75d13fff..317f5645 100644 --- a/library/src/moves/BUILD.bazel +++ b/library/src/moves/BUILD.bazel @@ -35,12 +35,4 @@ cc_library( visibility = [ "//library/tests/moves:__pkg__", ], -) - -filegroup( - name = "wasm_sources", - srcs = glob(["*.cpp"]), - visibility = [ - "//examples:__pkg__", - ], ) \ No newline at end of file diff --git a/library/src/solver_context/BUILD.bazel b/library/src/solver_context/BUILD.bazel index d25dea9e..a566211b 100644 --- a/library/src/solver_context/BUILD.bazel +++ b/library/src/solver_context/BUILD.bazel @@ -51,11 +51,3 @@ cc_library( linkopts = DDS_LINKOPTS, local_defines = DDS_LOCAL_DEFINES + DDS_SCHEDULER_DEFINE + ["DDS_UTILITIES_STATS"], ) - -filegroup( - name = "wasm_sources", - srcs = ["solver_context.cpp"], - visibility = [ - "//examples:__pkg__", - ], -) diff --git a/library/src/system/BUILD.bazel b/library/src/system/BUILD.bazel index 8ef12ac3..fb05075a 100644 --- a/library/src/system/BUILD.bazel +++ b/library/src/system/BUILD.bazel @@ -59,11 +59,3 @@ cc_library( linkopts = DDS_LINKOPTS, local_defines = DDS_LOCAL_DEFINES + DDS_SCHEDULER_DEFINE + ["DDS_UTILITIES_STATS"], ) - -filegroup( - name = "wasm_sources", - srcs = glob(["*.cpp"]), - visibility = [ - "//examples:__pkg__", - ], -) diff --git a/library/src/trans_table/BUILD.bazel b/library/src/trans_table/BUILD.bazel index b3cf2f13..d9caef65 100644 --- a/library/src/trans_table/BUILD.bazel +++ b/library/src/trans_table/BUILD.bazel @@ -47,15 +47,4 @@ cc_library( visibility = [ "//library/tests/trans_table:__pkg__", ], -) - -filegroup( - name = "wasm_sources", - srcs = [ - "trans_table_l.cpp", - "trans_table_s.cpp", - ], - visibility = [ - "//examples:__pkg__", - ], ) \ No newline at end of file diff --git a/library/src/utility/BUILD.bazel b/library/src/utility/BUILD.bazel index 874ade9b..214f0e9f 100644 --- a/library/src/utility/BUILD.bazel +++ b/library/src/utility/BUILD.bazel @@ -19,12 +19,3 @@ cc_library( deps = [], ) -filegroup( - name = "wasm_sources", - srcs = ["constants.cpp"], - visibility = [ - "//examples:__pkg__", - ], -) - - diff --git a/library/tests/BUILD.bazel b/library/tests/BUILD.bazel index 0781deee..b994317d 100644 --- a/library/tests/BUILD.bazel +++ b/library/tests/BUILD.bazel @@ -1,5 +1,6 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test") load("//:CPPVARIABLES.bzl", "DDS_CPPOPTS", "DDS_LINKOPTS", "DDS_LOCAL_DEFINES", "DDS_SCHEDULER_DEFINE") +load("//:wasm_compat.bzl", "NATIVE_ONLY") # Test utility sources (glob used for convenience; excludes integration/context equivalence tests) filegroup( @@ -17,6 +18,7 @@ filegroup( # Main test executable for manual invocation cc_binary( name = "dtest", + target_compatible_with = NATIVE_ONLY, srcs = [":test_sources"], copts = DDS_CPPOPTS, linkopts = DDS_LINKOPTS, @@ -32,6 +34,7 @@ cc_binary( # Uses testable_dds to expose internal symbols for unit testing cc_test( name = "unit_tests", + target_compatible_with = NATIVE_ONLY, srcs = [":test_sources"], size = "small", copts = DDS_CPPOPTS, @@ -46,6 +49,7 @@ cc_test( # Standalone calc_par API test cc_test( name = "calc_par_test", + target_compatible_with = NATIVE_ONLY, srcs = ["calc_par_test.cpp"], size = "small", copts = DDS_CPPOPTS, diff --git a/library/tests/heuristic_sorting/BUILD.bazel b/library/tests/heuristic_sorting/BUILD.bazel index 80e0db94..09dbcfbf 100644 --- a/library/tests/heuristic_sorting/BUILD.bazel +++ b/library/tests/heuristic_sorting/BUILD.bazel @@ -1,8 +1,11 @@ load("//:CPPVARIABLES.bzl", "DDS_CPPOPTS", "DDS_LINKOPTS", "DDS_LOCAL_DEFINES") load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_cc//cc:defs.bzl", "cc_test", "cc_binary") +load("//:wasm_compat.bzl", "NATIVE_ONLY") + cc_test( + target_compatible_with = NATIVE_ONLY, name = "heuristic_sorting_test", size = "small", srcs = ["heuristic_sorting_test.cpp"], @@ -14,6 +17,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "merge_scratch_test", size = "small", srcs = ["merge_scratch_test.cpp"], @@ -27,6 +31,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "minimal_new_test", size = "small", srcs = ["minimal_new_test.cpp"], @@ -37,6 +42,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "minimal_weight_test", size = "small", srcs = ["minimal_weight_test.cpp"], @@ -49,6 +55,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "targeted_unit_tests", size = "small", srcs = [ @@ -63,4 +70,4 @@ cc_test( "//library/src/moves:moves", "@googletest//:gtest_main", ], -) +) \ No newline at end of file diff --git a/library/tests/moves/BUILD.bazel b/library/tests/moves/BUILD.bazel index 47939520..83290411 100644 --- a/library/tests/moves/BUILD.bazel +++ b/library/tests/moves/BUILD.bazel @@ -1,8 +1,9 @@ load("@rules_cc//cc:defs.bzl", "cc_test") +load("//:wasm_compat.bzl", "NATIVE_ONLY") -package(default_visibility = ["//visibility:public"]) cc_test( + target_compatible_with = NATIVE_ONLY, name = "moves_test", size = "small", srcs = ["moves_test.cpp"], diff --git a/library/tests/regression/heuristic_sorting/BUILD.bazel b/library/tests/regression/heuristic_sorting/BUILD.bazel index 2c7ef1c9..04be2ca8 100644 --- a/library/tests/regression/heuristic_sorting/BUILD.bazel +++ b/library/tests/regression/heuristic_sorting/BUILD.bazel @@ -1,8 +1,11 @@ load("@rules_cc//cc:defs.bzl", "cc_test") +load("//:wasm_compat.bzl", "NATIVE_ONLY") + # Regression tests for heuristic sorting behavior cc_test( + target_compatible_with = NATIVE_ONLY, name = "heuristic_sorting", size = "small", srcs = ["heuristic_sorting_test.cpp"], diff --git a/library/tests/solve_board/BUILD.bazel b/library/tests/solve_board/BUILD.bazel index 222909fd..8a672cf1 100644 --- a/library/tests/solve_board/BUILD.bazel +++ b/library/tests/solve_board/BUILD.bazel @@ -1,8 +1,11 @@ # Solve_board regression tests load("@rules_cc//cc:defs.bzl", "cc_test") +load("//:wasm_compat.bzl", "NATIVE_ONLY") + cc_test( + target_compatible_with = NATIVE_ONLY, name = "solve_board_test", size = "small", srcs = [ @@ -15,6 +18,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "analyse_play_consistency_test", size = "small", srcs = [ diff --git a/library/tests/system/BUILD.bazel b/library/tests/system/BUILD.bazel index 5570c184..62038783 100644 --- a/library/tests/system/BUILD.bazel +++ b/library/tests/system/BUILD.bazel @@ -1,6 +1,8 @@ load("@rules_cc//cc:defs.bzl", "cc_test") +load("//:wasm_compat.bzl", "NATIVE_ONLY") cc_test( + target_compatible_with = NATIVE_ONLY, name = "concurrency_validation_test", size = "small", srcs = ["concurrency_validation_test.cpp"], @@ -13,6 +15,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "configure_tt_api_test", size = "small", srcs = ["configure_tt_api_test.cpp"], @@ -24,6 +27,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "context_equivalence_test", size = "small", srcs = ["context_equivalence_test.cpp"], @@ -37,6 +41,7 @@ cc_test( # Same parity test, but with context TT ownership enabled to validate lazy TT path cc_test( + target_compatible_with = NATIVE_ONLY, name = "context_equivalence_test_ctx_tt", size = "small", srcs = ["context_equivalence_test.cpp"], @@ -51,6 +56,7 @@ cc_test( # New lifecycle test that validates SolverContext-managed TT behavior cc_test( + target_compatible_with = NATIVE_ONLY, name = "context_tt_facade_test", size = "small", srcs = ["context_tt_facade_test.cpp"], @@ -64,6 +70,7 @@ cc_test( # Utilities feature flags tests cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_feature_flags_test", size = "small", srcs = ["utilities_feature_flags_test.cpp"], @@ -75,6 +82,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_feature_flags_test_with_log", size = "small", srcs = ["utilities_feature_flags_test_with_log.cpp"], @@ -86,6 +94,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_feature_flags_test_with_stats", size = "small", srcs = ["utilities_feature_flags_test_with_stats.cpp"], @@ -98,6 +107,7 @@ cc_test( # Utilities logging tests cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_log_contains_test", size = "small", srcs = ["utilities_log_contains_test.cpp"], @@ -109,6 +119,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_log_ctx_ops_test", size = "small", srcs = ["utilities_log_ctx_ops_test.cpp"], @@ -120,6 +131,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_log_ctx_ops_test_with_define", size = "small", srcs = ["utilities_log_ctx_ops_test_with_define.cpp"], @@ -131,6 +143,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_log_test", size = "small", srcs = ["utilities_log_test.cpp"], @@ -143,6 +156,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_log_test_with_define", size = "small", srcs = ["utilities_log_test_with_define.cpp"], @@ -156,6 +170,7 @@ cc_test( # Utilities snapshot tests # DISABLED: Tests for unimplemented log_snapshot() feature cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_log_snapshot_test", srcs = ["utilities_log_snapshot_test.cpp"], tags = ["manual"], @@ -168,6 +183,7 @@ cc_test( # Utilities stats tests cc_test( + target_compatible_with = NATIVE_ONLY, name = "utilities_stats_test", size = "small", srcs = ["utilities_stats_test.cpp"], @@ -181,6 +197,7 @@ cc_test( # Transposition table sharing tests # DISABLED: Tests for SolverContext TT sharing (incomplete API) cc_test( + target_compatible_with = NATIVE_ONLY, name = "tt_sharing_test", srcs = ["tt_sharing_test.cpp"], tags = ["manual"], diff --git a/library/tests/trans_table/BUILD.bazel b/library/tests/trans_table/BUILD.bazel index 56a4e0cb..0cc4b5af 100644 --- a/library/tests/trans_table/BUILD.bazel +++ b/library/tests/trans_table/BUILD.bazel @@ -1,4 +1,6 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") +load("//:wasm_compat.bzl", "NATIVE_ONLY") + cc_library( name = "test_utilities", @@ -19,6 +21,7 @@ cc_library( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "trans_table", size = "small", srcs = [ @@ -31,4 +34,4 @@ cc_test( ":test_utilities", "@googletest//:gtest_main", ], -) +) \ No newline at end of file diff --git a/library/tests/utility/BUILD.bazel b/library/tests/utility/BUILD.bazel index 5504c7c4..b5080fe6 100644 --- a/library/tests/utility/BUILD.bazel +++ b/library/tests/utility/BUILD.bazel @@ -1,8 +1,11 @@ load("@rules_cc//cc:defs.bzl", "cc_test") +load("//:wasm_compat.bzl", "NATIVE_ONLY") + # Utility tests: constants, lookup tables, and RNG determinism validation cc_test( + target_compatible_with = NATIVE_ONLY, name = "constants_test", size = "small", srcs = ["constants_test.cpp"], @@ -13,6 +16,7 @@ cc_test( ) cc_test( + target_compatible_with = NATIVE_ONLY, name = "lookup_tables_test", size = "small", srcs = ["lookup_tables_test.cpp"], @@ -24,6 +28,7 @@ cc_test( # Aggregate test suite combining constants and lookup tables tests cc_test( + target_compatible_with = NATIVE_ONLY, name = "utility_test_suite", size = "small", srcs = [ diff --git a/wasm/BUILD.bazel b/wasm/BUILD.bazel new file mode 100644 index 00000000..9bb72912 --- /dev/null +++ b/wasm/BUILD.bazel @@ -0,0 +1 @@ +# WASM helpers live in //:wasm_compat.bzl (no build targets in this package). diff --git a/wasm_compat.bzl b/wasm_compat.bzl new file mode 100644 index 00000000..1640ea55 --- /dev/null +++ b/wasm_compat.bzl @@ -0,0 +1,15 @@ +"""Shared attributes for native vs WebAssembly builds.""" + +# Mark targets incompatible when building with --config=wasm. +NATIVE_ONLY = select({ + "//:build_wasm": ["@platforms//:incompatible"], + "//conditions:default": [], +}) + +# Emscripten link flags for cc_binary targets wrapped by wasm_cc_binary. +WASM_LINKOPTS = [ + "-sWASM=1", + "-fexceptions", + "-sALLOW_MEMORY_GROWTH=1", + "-sINITIAL_MEMORY=268435456", +] From d0928c3da5d17cc31f91a6140cd4b4cbe2380aa8 Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Mon, 1 Jun 2026 12:47:11 +0200 Subject: [PATCH 2/3] Cursor: get rid of the "--config=wasm" --- .bazelrc | 13 ------ .github/workflows/ci_wasm.yml | 2 +- BUILD.bazel | 5 +-- docs/wasm_build.md | 43 ++++++++----------- examples/BUILD.bazel | 14 ------ library/tests/BUILD.bazel | 4 -- library/tests/heuristic_sorting/BUILD.bazel | 6 --- library/tests/moves/BUILD.bazel | 2 - .../regression/heuristic_sorting/BUILD.bazel | 2 - library/tests/solve_board/BUILD.bazel | 3 -- library/tests/system/BUILD.bazel | 17 -------- library/tests/trans_table/BUILD.bazel | 2 - library/tests/utility/BUILD.bazel | 4 -- wasm_compat.bzl | 8 +--- 14 files changed, 21 insertions(+), 104 deletions(-) diff --git a/.bazelrc b/.bazelrc index f637e4eb..a0490fc5 100644 --- a/.bazelrc +++ b/.bazelrc @@ -45,16 +45,3 @@ build:tsan --linkopt=-fsanitize=thread build:tsan --strip=never build:tsan --features=dbg build:tsan --compilation_mode=dbg - -# WebAssembly (WASM) configuration -# Usage: bazel build --config=wasm //... -# Compiles using the hermetic emsdk toolchain downloaded automatically by Bazel. -# Targets tagged "native-only" (Python, tests, most examples) are skipped. -build:wasm --platforms=@emsdk//:platform_wasm -build:wasm --cpu=wasm -build:wasm --cxxopt=-std=c++20 -build:wasm --host_cxxopt=-std=c++20 -build:wasm --compilation_mode=opt -build:wasm --build_tag_filters=-native-only -# Python bindings and C++ unit tests require the host toolchain. -build:wasm --deleted_packages=python,library/tests diff --git a/.github/workflows/ci_wasm.yml b/.github/workflows/ci_wasm.yml index 516ee02c..114c5eab 100644 --- a/.github/workflows/ci_wasm.yml +++ b/.github/workflows/ci_wasm.yml @@ -22,7 +22,7 @@ jobs: # 3️⃣ Build WASM targets (hermetic emsdk toolchain downloaded by Bazel) - name: Build WASM targets - run: bazel build --config=wasm --verbose_failures //... + run: bazel build --verbose_failures //examples/wasm:all_examples_wasm # 4️⃣ Smoke test: run solve_board under Node.js — pass if it does not crash - name: Smoke test solve_board_wasm diff --git a/BUILD.bazel b/BUILD.bazel index 75eb3a9a..8a672088 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -72,8 +72,7 @@ config_setting( define_values = {"asan": "true"}, ) -# WebAssembly (WASM) build configuration -# Usage: bazel build --config=wasm //... +# Matches cc_* targets built under the wasm_cc_binary platform transition (cpu=wasm). config_setting( name = "build_wasm", values = {"cpu": "wasm"}, @@ -121,7 +120,6 @@ EOF tags = [ "manual", "local", - "native-only", "no-remote", "no-remote-cache", ], @@ -135,7 +133,6 @@ cc_library( cc_library( name = "testable_dds", - tags = ["native-only"], deps = ["//library/src:testable_dds"], visibility = [ "//library/tests:__pkg__", diff --git a/docs/wasm_build.md b/docs/wasm_build.md index 2d2a2157..15c5e780 100644 --- a/docs/wasm_build.md +++ b/docs/wasm_build.md @@ -1,6 +1,6 @@ # WebAssembly (WASM) Build Guide -This document explains how to build the DDS library and examples for WebAssembly using Bazel. +This document explains how to build DDS examples for WebAssembly using Bazel. ## Prerequisites @@ -9,22 +9,16 @@ This document explains how to build the DDS library and examples for WebAssembly Bazel 7.x or later is required. Install using your package manager or download from: https://bazel.build/install -The Emscripten SDK (emsdk) does NOT need to be manually installed. Bazel will automatically download, configure, and cache the appropriate hermetic Emscripten toolchain for your host platform as part of the build process. +The Emscripten SDK (emsdk) does NOT need to be manually installed. Bazel downloads and caches a hermetic Emscripten toolchain when you build a `wasm_cc_binary` target. ## Building WASM Examples -### Build all WASM-compatible targets +WASM targets use `wasm_cc_binary`, which applies an Emscripten **platform transition** to the underlying `cc_binary`. You do **not** need `--config=wasm` or any other `.bazelrc` profile. -Native-only targets (Python bindings, C++ tests, most examples) are skipped automatically: +### Build all WASM examples ```bash -bazel build --config=wasm //... -``` - -### Build WASM examples only - -```bash -bazel build --config=wasm //examples/wasm:all_examples_wasm +bazel build //examples/wasm:all_examples_wasm ``` The alias `//examples:all_examples_wasm` points at the same filegroup. @@ -32,33 +26,32 @@ The alias `//examples:all_examples_wasm` points at the same filegroup. ### Build a specific example ```bash -bazel build --config=wasm //examples/wasm:solve_board_wasm +bazel build //examples/wasm:solve_board_wasm ``` -### Output Files +### Output files -Output files are under `bazel-bin/examples/wasm/` (wasm_cc_binary output layout): +Outputs are under `bazel-bin/examples/wasm/`: - `solve_board.js` / `solve_board.wasm` - `AnalysePlayBin.js` / `AnalysePlayBin.wasm` -## Available WASM Targets +## Available WASM targets -WASM rules live in `examples/wasm/BUILD.bazel` and wrap native `cc_binary` targets in `examples/`: +Rules in `examples/wasm/BUILD.bazel` wrap native examples in `examples/`: - `solve_board_wasm` — solves a single board - `analyse_play_bin_wasm` — analyze play from binary format -## WASM Build Configuration +## How it works -1. **`BUILD.bazel`** — `//:build_wasm` matches `--cpu=wasm` from the `wasm` config -2. **`wasm_compat.bzl`** — shared Emscripten link flags (`WASM_LINKOPTS`) -3. **`CPPVARIABLES.bzl`** — WASM compiler flags and `__WASM__` define -4. **`.bazelrc`** — `wasm` config (platform, `--build_tag_filters=-native-only`) +1. **`wasm_cc_binary`** (from `@emsdk`) transitions its `cc_target` to `@emsdk//:platform_wasm` and sets `--cpu=wasm`. +2. **`//:build_wasm`** in the root `BUILD.bazel` matches that CPU for `select()` in `CPPVARIABLES.bzl` and example link flags. +3. **`wasm_compat.bzl`** — shared Emscripten link flags (`WASM_LINKOPTS`) on the WASM-capable `cc_binary` targets. -Targets tagged `native-only` are excluded from `bazel build --config=wasm //...` (most examples, Doxygen). The `python` and `library/tests` packages are omitted entirely via `--deleted_packages`. +Native builds (`bazel build //...`, `bazel test //library/tests/...`, Python bindings) are unchanged and use the host LLVM toolchain. -## Running WASM Examples +## Running WASM examples ### Node.js @@ -66,7 +59,7 @@ Targets tagged `native-only` are excluded from `bazel build --config=wasm //...` node bazel-bin/examples/wasm/solve_board.js ``` -## Compilation Flags +## Compilation flags | Flag | Purpose | |------|---------| @@ -78,7 +71,7 @@ node bazel-bin/examples/wasm/solve_board.js | `-sALLOW_MEMORY_GROWTH=1` | Allow heap growth at runtime | | `-sINITIAL_MEMORY=268435456` | 256MB initial memory | -## Related Documentation +## Related documentation - [Emscripten Documentation](https://emscripten.org/docs/) - [Bazel Build System](https://bazel.build/docs) diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index 4e6f1000..1ae72944 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -45,7 +45,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -59,7 +58,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -87,7 +85,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -101,7 +98,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -115,7 +111,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -129,7 +124,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -143,7 +137,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -157,7 +150,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -171,7 +163,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -185,7 +176,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -213,7 +203,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -227,7 +216,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ "//library/src:dds", "//library/src/api:api_definitions", @@ -240,7 +228,6 @@ cc_binary( copts = EXAMPLES_CPPOPTS, linkopts = DDS_LINKOPTS, local_defines = EXAMPLES_LOCAL_DEFINES, - tags = ["native-only"], deps = [ ":hands", "//library/src:dds", @@ -252,7 +239,6 @@ cc_binary( # Convenience target to build all native examples filegroup( name = "all_examples", - tags = ["native-only"], srcs = [ ":analyse_all_plays_bin", ":analyse_all_plays_pbn", diff --git a/library/tests/BUILD.bazel b/library/tests/BUILD.bazel index b994317d..0781deee 100644 --- a/library/tests/BUILD.bazel +++ b/library/tests/BUILD.bazel @@ -1,6 +1,5 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test") load("//:CPPVARIABLES.bzl", "DDS_CPPOPTS", "DDS_LINKOPTS", "DDS_LOCAL_DEFINES", "DDS_SCHEDULER_DEFINE") -load("//:wasm_compat.bzl", "NATIVE_ONLY") # Test utility sources (glob used for convenience; excludes integration/context equivalence tests) filegroup( @@ -18,7 +17,6 @@ filegroup( # Main test executable for manual invocation cc_binary( name = "dtest", - target_compatible_with = NATIVE_ONLY, srcs = [":test_sources"], copts = DDS_CPPOPTS, linkopts = DDS_LINKOPTS, @@ -34,7 +32,6 @@ cc_binary( # Uses testable_dds to expose internal symbols for unit testing cc_test( name = "unit_tests", - target_compatible_with = NATIVE_ONLY, srcs = [":test_sources"], size = "small", copts = DDS_CPPOPTS, @@ -49,7 +46,6 @@ cc_test( # Standalone calc_par API test cc_test( name = "calc_par_test", - target_compatible_with = NATIVE_ONLY, srcs = ["calc_par_test.cpp"], size = "small", copts = DDS_CPPOPTS, diff --git a/library/tests/heuristic_sorting/BUILD.bazel b/library/tests/heuristic_sorting/BUILD.bazel index 09dbcfbf..3f564dd7 100644 --- a/library/tests/heuristic_sorting/BUILD.bazel +++ b/library/tests/heuristic_sorting/BUILD.bazel @@ -1,11 +1,9 @@ load("//:CPPVARIABLES.bzl", "DDS_CPPOPTS", "DDS_LINKOPTS", "DDS_LOCAL_DEFINES") load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_cc//cc:defs.bzl", "cc_test", "cc_binary") -load("//:wasm_compat.bzl", "NATIVE_ONLY") cc_test( - target_compatible_with = NATIVE_ONLY, name = "heuristic_sorting_test", size = "small", srcs = ["heuristic_sorting_test.cpp"], @@ -17,7 +15,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "merge_scratch_test", size = "small", srcs = ["merge_scratch_test.cpp"], @@ -31,7 +28,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "minimal_new_test", size = "small", srcs = ["minimal_new_test.cpp"], @@ -42,7 +38,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "minimal_weight_test", size = "small", srcs = ["minimal_weight_test.cpp"], @@ -55,7 +50,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "targeted_unit_tests", size = "small", srcs = [ diff --git a/library/tests/moves/BUILD.bazel b/library/tests/moves/BUILD.bazel index 83290411..5eb94e20 100644 --- a/library/tests/moves/BUILD.bazel +++ b/library/tests/moves/BUILD.bazel @@ -1,9 +1,7 @@ load("@rules_cc//cc:defs.bzl", "cc_test") -load("//:wasm_compat.bzl", "NATIVE_ONLY") cc_test( - target_compatible_with = NATIVE_ONLY, name = "moves_test", size = "small", srcs = ["moves_test.cpp"], diff --git a/library/tests/regression/heuristic_sorting/BUILD.bazel b/library/tests/regression/heuristic_sorting/BUILD.bazel index 04be2ca8..0671095c 100644 --- a/library/tests/regression/heuristic_sorting/BUILD.bazel +++ b/library/tests/regression/heuristic_sorting/BUILD.bazel @@ -1,11 +1,9 @@ load("@rules_cc//cc:defs.bzl", "cc_test") -load("//:wasm_compat.bzl", "NATIVE_ONLY") # Regression tests for heuristic sorting behavior cc_test( - target_compatible_with = NATIVE_ONLY, name = "heuristic_sorting", size = "small", srcs = ["heuristic_sorting_test.cpp"], diff --git a/library/tests/solve_board/BUILD.bazel b/library/tests/solve_board/BUILD.bazel index 8a672cf1..e1d11fe1 100644 --- a/library/tests/solve_board/BUILD.bazel +++ b/library/tests/solve_board/BUILD.bazel @@ -1,11 +1,9 @@ # Solve_board regression tests load("@rules_cc//cc:defs.bzl", "cc_test") -load("//:wasm_compat.bzl", "NATIVE_ONLY") cc_test( - target_compatible_with = NATIVE_ONLY, name = "solve_board_test", size = "small", srcs = [ @@ -18,7 +16,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "analyse_play_consistency_test", size = "small", srcs = [ diff --git a/library/tests/system/BUILD.bazel b/library/tests/system/BUILD.bazel index 62038783..5570c184 100644 --- a/library/tests/system/BUILD.bazel +++ b/library/tests/system/BUILD.bazel @@ -1,8 +1,6 @@ load("@rules_cc//cc:defs.bzl", "cc_test") -load("//:wasm_compat.bzl", "NATIVE_ONLY") cc_test( - target_compatible_with = NATIVE_ONLY, name = "concurrency_validation_test", size = "small", srcs = ["concurrency_validation_test.cpp"], @@ -15,7 +13,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "configure_tt_api_test", size = "small", srcs = ["configure_tt_api_test.cpp"], @@ -27,7 +24,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "context_equivalence_test", size = "small", srcs = ["context_equivalence_test.cpp"], @@ -41,7 +37,6 @@ cc_test( # Same parity test, but with context TT ownership enabled to validate lazy TT path cc_test( - target_compatible_with = NATIVE_ONLY, name = "context_equivalence_test_ctx_tt", size = "small", srcs = ["context_equivalence_test.cpp"], @@ -56,7 +51,6 @@ cc_test( # New lifecycle test that validates SolverContext-managed TT behavior cc_test( - target_compatible_with = NATIVE_ONLY, name = "context_tt_facade_test", size = "small", srcs = ["context_tt_facade_test.cpp"], @@ -70,7 +64,6 @@ cc_test( # Utilities feature flags tests cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_feature_flags_test", size = "small", srcs = ["utilities_feature_flags_test.cpp"], @@ -82,7 +75,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_feature_flags_test_with_log", size = "small", srcs = ["utilities_feature_flags_test_with_log.cpp"], @@ -94,7 +86,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_feature_flags_test_with_stats", size = "small", srcs = ["utilities_feature_flags_test_with_stats.cpp"], @@ -107,7 +98,6 @@ cc_test( # Utilities logging tests cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_log_contains_test", size = "small", srcs = ["utilities_log_contains_test.cpp"], @@ -119,7 +109,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_log_ctx_ops_test", size = "small", srcs = ["utilities_log_ctx_ops_test.cpp"], @@ -131,7 +120,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_log_ctx_ops_test_with_define", size = "small", srcs = ["utilities_log_ctx_ops_test_with_define.cpp"], @@ -143,7 +131,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_log_test", size = "small", srcs = ["utilities_log_test.cpp"], @@ -156,7 +143,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_log_test_with_define", size = "small", srcs = ["utilities_log_test_with_define.cpp"], @@ -170,7 +156,6 @@ cc_test( # Utilities snapshot tests # DISABLED: Tests for unimplemented log_snapshot() feature cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_log_snapshot_test", srcs = ["utilities_log_snapshot_test.cpp"], tags = ["manual"], @@ -183,7 +168,6 @@ cc_test( # Utilities stats tests cc_test( - target_compatible_with = NATIVE_ONLY, name = "utilities_stats_test", size = "small", srcs = ["utilities_stats_test.cpp"], @@ -197,7 +181,6 @@ cc_test( # Transposition table sharing tests # DISABLED: Tests for SolverContext TT sharing (incomplete API) cc_test( - target_compatible_with = NATIVE_ONLY, name = "tt_sharing_test", srcs = ["tt_sharing_test.cpp"], tags = ["manual"], diff --git a/library/tests/trans_table/BUILD.bazel b/library/tests/trans_table/BUILD.bazel index 0cc4b5af..b7374c98 100644 --- a/library/tests/trans_table/BUILD.bazel +++ b/library/tests/trans_table/BUILD.bazel @@ -1,5 +1,4 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") -load("//:wasm_compat.bzl", "NATIVE_ONLY") cc_library( @@ -21,7 +20,6 @@ cc_library( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "trans_table", size = "small", srcs = [ diff --git a/library/tests/utility/BUILD.bazel b/library/tests/utility/BUILD.bazel index b5080fe6..16101a17 100644 --- a/library/tests/utility/BUILD.bazel +++ b/library/tests/utility/BUILD.bazel @@ -1,11 +1,9 @@ load("@rules_cc//cc:defs.bzl", "cc_test") -load("//:wasm_compat.bzl", "NATIVE_ONLY") # Utility tests: constants, lookup tables, and RNG determinism validation cc_test( - target_compatible_with = NATIVE_ONLY, name = "constants_test", size = "small", srcs = ["constants_test.cpp"], @@ -16,7 +14,6 @@ cc_test( ) cc_test( - target_compatible_with = NATIVE_ONLY, name = "lookup_tables_test", size = "small", srcs = ["lookup_tables_test.cpp"], @@ -28,7 +25,6 @@ cc_test( # Aggregate test suite combining constants and lookup tables tests cc_test( - target_compatible_with = NATIVE_ONLY, name = "utility_test_suite", size = "small", srcs = [ diff --git a/wasm_compat.bzl b/wasm_compat.bzl index 1640ea55..dcec1543 100644 --- a/wasm_compat.bzl +++ b/wasm_compat.bzl @@ -1,10 +1,4 @@ -"""Shared attributes for native vs WebAssembly builds.""" - -# Mark targets incompatible when building with --config=wasm. -NATIVE_ONLY = select({ - "//:build_wasm": ["@platforms//:incompatible"], - "//conditions:default": [], -}) +"""Shared attributes for WebAssembly (Emscripten) builds.""" # Emscripten link flags for cc_binary targets wrapped by wasm_cc_binary. WASM_LINKOPTS = [ From 7348cd60631da99cb2d3c00535898a74423663cb Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Mon, 1 Jun 2026 14:15:09 +0200 Subject: [PATCH 3/3] Restore or update some comments that Cursor had decided were unnecessary. --- .github/workflows/ci_wasm.yml | 1 + docs/wasm_build.md | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/.github/workflows/ci_wasm.yml b/.github/workflows/ci_wasm.yml index 114c5eab..9e0e4616 100644 --- a/.github/workflows/ci_wasm.yml +++ b/.github/workflows/ci_wasm.yml @@ -27,3 +27,4 @@ jobs: # 4️⃣ Smoke test: run solve_board under Node.js — pass if it does not crash - name: Smoke test solve_board_wasm run: node bazel-bin/examples/wasm/solve_board.js +git push -u origin wasm-refactor \ No newline at end of file diff --git a/docs/wasm_build.md b/docs/wasm_build.md index 15c5e780..411785ec 100644 --- a/docs/wasm_build.md +++ b/docs/wasm_build.md @@ -59,6 +59,10 @@ Native builds (`bazel build //...`, `bazel test //library/tests/...`, Python bin node bazel-bin/examples/wasm/solve_board.js ``` +### Web browser (not yet supported) + +There is no checked-in HTML runner yet. To experiment manually, copy the built `.js` and `.wasm` files from `bazel-bin/examples/wasm/` to a static file server and load the `.js` from a page that provides the Emscripten `Module` hooks. + ## Compilation flags | Flag | Purpose | @@ -71,6 +75,33 @@ node bazel-bin/examples/wasm/solve_board.js | `-sALLOW_MEMORY_GROWTH=1` | Allow heap growth at runtime | | `-sINITIAL_MEMORY=268435456` | 256MB initial memory | +## C++ standard + +WASM example binaries are built as C++20. The Emscripten toolchain (via `wasm_cc_binary`) compiles the transitioned `cc_target`; project flags for that configuration come from `CPPVARIABLES.bzl` when `//:build_wasm` matches (`--cpu=wasm` set by the transition). + +Host-side Bazel actions still use the normal platform flags in `.bazelrc`: + +``` +build:macos --cxxopt=-std=c++20 +build:linux --cxxopt=-std=c++20 +``` + +There is no separate `build:wasm` profile in `.bazelrc`; WASM builds are selected by targeting `//examples/wasm:*`. + +## Development notes + +- The `__WASM__` preprocessor constant is defined for WASM builds (`CPPVARIABLES.bzl`). It was added to work around platform-specific code paths; revisit whether it can be narrowed or removed as WASM support matures. +- Some threading and platform-specific features are disabled or stubbed when `__WASM__` is set. +- A reusable `cc_library` WASM artifact (not only example binaries) is not yet provided; today only `wasm_cc_binary` example targets are wired up. +- Browser/HTML packaging (`.html` shell, assets) is not yet documented or automated; Node.js is the supported smoke-test runner for now. + +## Next steps + +To integrate WASM builds into CI/CD: + +1. See `.github/workflows/ci_wasm.yml` +2. Store WASM artifacts (`*.js`, `*.wasm`) for download or release as needed + ## Related documentation - [Emscripten Documentation](https://emscripten.org/docs/)