diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 938fa0aa181..09e343c57fd 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -2,7 +2,6 @@ name: Wasm on: [push, pull_request] -# This will cancel previous runs when a branch or PR is updated concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }} cancel-in-progress: true @@ -16,14 +15,66 @@ jobs: - name: Checkout sources uses: actions/checkout@v3 - - name: Setup rust toolchain - uses: dtolnay/rust-toolchain@master + - name: Setup Nix + uses: cachix/install-nix-action@v20 with: - toolchain: 1.66.0 + nix_path: nixpkgs=channel:nixos-22.11 + github_access_token: ${{ secrets.GITHUB_TOKEN }} - - name: Install wasm-pack - run: cargo install wasm-pack + - name: Build wasm package + run: | + nix build -L .#wasm + ls -la - - name: Build wasm crate - working-directory: ./crates/wasm - run: ./build-wasm + - name: Copy wasm build result + run: | + mkdir -p ./pkg + ls -la + cp -r -L ./result/* ./pkg + + - name: Output results + run: ls -la ./result + + # Todo: Enable wasm testing by injecting wasm into noir-wasm-testing + + # - name: Checkout noir-wasm-testing + # uses: actions/checkout@v3 + # with: + # repository: noir-lang/noir-wasm-testing + # path: noir-wasm-testing + + # - name: Inject built wasm into noir-wasm-testing + # run: | + # cp -r ./crates/wasm/result ./noir-wasm-testing/@noir-lang_noir_wasm + # jq '.dependencies["@noir-lang/noir_wasm"] = "file:./node_modules/@noir-lang/noir_wasm"' ./noir-wasm-testing/package.json > ./noir-wasm-testing/package.json.tmp + # mv ./noir-wasm-testing/package.json.tmp ./noir-wasm-testing/package.json + + # - name: Log package information + # working-directory: ./noir-wasm-testing + # run: | + # echo "Wasm contents:" + # ls -la ./@noir-lang_noir_wasm + # echo "Directory contents:" + # ls -la + # echo "package.json contents:" + # cat package.json + # echo "Checking if noir-script.json exists:" + # if [ -f "./src/noir-script/target/noir-script.json" ]; then + # echo "File exists." + # else + # echo "File does not exist." + # fi + + # - name: Run build.sh in noir-wasm-testing + # working-directory: ./noir-wasm-testing + # run: | + # chmod +x build.sh + # ./build.sh + + # - name: Install dependencies + # working-directory: ./noir-wasm-testing + # run: npm install + + # - name: Run tests + # working-directory: ./noir-wasm-testing + # run: npm test diff --git a/.gitignore b/.gitignore index 351f5e16a7f..9684106d30c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ node_modules pkg/ # Nix stuff +**/outputs result .envrc.local .direnv/ diff --git a/crates/wasm/Cargo.toml b/crates/wasm/Cargo.toml index 7660f67bd57..5c139d96164 100644 --- a/crates/wasm/Cargo.toml +++ b/crates/wasm/Cargo.toml @@ -27,4 +27,4 @@ gloo-utils = { version = "0.1", features = ["serde"] } getrandom = { version = "*", features = ["js"] } [build-dependencies] -build-data = "0.1.3" +build-data = "0.1.3" \ No newline at end of file diff --git a/crates/wasm/README.md b/crates/wasm/README.md index 55c5cc4fb19..3714acd329f 100644 --- a/crates/wasm/README.md +++ b/crates/wasm/README.md @@ -4,7 +4,6 @@ In order to build the wasm package, the following must be installed: -- [wasm-pack](https://github.com/rustwasm/wasm-pack) - [jq](https://github.com/stedolan/jq) ## Build @@ -14,5 +13,3 @@ The wasm package can be built using the command below: ```bash ./build-wasm ``` - -Using `wasm-pack` directly isn't recommended as it doesn't generate a complete `package.json` file, resulting in files being omitted from the published package. diff --git a/crates/wasm/build-wasm b/crates/wasm/build-wasm deleted file mode 100755 index 6b574b71d03..00000000000 --- a/crates/wasm/build-wasm +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# Clear out the existing build artifacts as these aren't automatically removed by wasm-pack. -if [ -d ./pkg/ ]; then - rm -rf ./pkg/ -fi - -# Build the new wasm package -wasm-pack build --scope noir-lang --target nodejs --out-dir pkg/nodejs - -wasm-pack build --scope noir-lang --target web --out-dir pkg/web - -COMMIT_SHORT=$(git rev-parse --short HEAD) -VERSION_APPENDIX="" -if [ -n "$COMMIT_SHORT" ]; then - VERSION_APPENDIX="-$COMMIT_SHORT" -else - VERSION_APPENDIX="-NOGIT" -fi - -jq -s '.[0] * .[1]' pkg/nodejs/package.json pkg/web/package.json | jq '.files = ["nodejs", "web", "package.json"]' | jq ".version += \"$VERSION_APPENDIX\"" | jq '.main = "./nodejs/" + .main | .module = "./web/" + .module | .types = "./web/" + .types | .peerDependencies = { "@noir-lang/noir-source-resolver": "1.1.2" }' | tee ./pkg/package.json - -rm pkg/nodejs/package.json pkg/nodejs/README.md pkg/nodejs/.gitignore - -rm pkg/web/package.json pkg/web/README.md pkg/web/.gitignore \ No newline at end of file diff --git a/crates/wasm/build.sh b/crates/wasm/build.sh new file mode 100755 index 00000000000..2aa0a339aa4 --- /dev/null +++ b/crates/wasm/build.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +function require_command { + if ! command -v "$1" >/dev/null 2>&1; then + echo "Error: $1 is required but not installed." >&2 + exit 1 + fi +} + +require_command toml2json +require_command jq +require_command cargo +require_command wasm-bindgen +require_command wasm-opt + +export pname=$(toml2json < Cargo.toml | jq -r .package.name) + +./buildPhaseCargoCommand.sh +./installPhase.sh + diff --git a/crates/wasm/buildPhaseCargoCommand.sh b/crates/wasm/buildPhaseCargoCommand.sh new file mode 100755 index 00000000000..a9eac8c2000 --- /dev/null +++ b/crates/wasm/buildPhaseCargoCommand.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# Clear out the existing build artifacts as these aren't automatically removed by wasm-pack. +if [ -d ./pkg/ ]; then + rm -rf ./pkg/ +fi + +WASM_BINARY=./target/wasm32-unknown-unknown/release/${pname}.wasm +NODE_WASM=./pkg/nodejs/${pname}_bg.wasm +BROWSER_WASM=./pkg/nodejs/${pname}_bg.wasm + +# Build the new wasm package +cargo build --lib --release --package noir_wasm --target wasm32-unknown-unknown +wasm-bindgen $WASM_BINARY --out-dir ./pkg/nodejs --typescript --target nodejs +wasm-bindgen $WASM_BINARY --out-dir ./pkg/web --typescript --target web +wasm-opt $NODE_WASM -o $NODE_WASM -O +wasm-opt $BROWSER_WASM -o $BROWSER_WASM -O diff --git a/crates/wasm/installPhase.sh b/crates/wasm/installPhase.sh new file mode 100755 index 00000000000..c653111c1f3 --- /dev/null +++ b/crates/wasm/installPhase.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Extract version from Cargo.toml using toml2json +PACKAGE_VERSION=$(toml2json < Cargo.toml | jq -r .workspace.package.version) +if [ -z "$PACKAGE_VERSION" ]; then + echo "Could not extract version from Cargo.toml" + exit 1 +fi +PACKAGE_VERSION+=$VERSION_APPENDIX + +echo PACKAGE_VERSION=$PACKAGE_VERSION + +mkdir -p $out +cp README.md $out/ +cp -r ./pkg/* $out/ +jq -n --arg ver "$PACKAGE_VERSION" \ + '{ + "version": $ver, + "repository": {"type": "git","url": "https://github.com/noir-lang/noir_wasm.git"}, + "sideEffects": false, + "files": ["nodejs","web","package.json"], + "main": "./nodejs/noir_wasm.js", + "types": "./web/noir_wasm.d.ts", + "module": "./web/noir_wasm.js" + }' > $out/package.json diff --git a/crates/wasm/wasm.nix b/crates/wasm/wasm.nix deleted file mode 100644 index 332db3de0cc..00000000000 --- a/crates/wasm/wasm.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ nixpkgs ? import {} }: - -let - rustOverlay = builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"; - llvm11stdenv = pkgs.llvmPackages_10.stdenv; - - # NixOS 22.05 - pinnedPkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/0938d73bb143f4ae037143572f11f4338c7b2d1c.tar.gz"; - - - pkgs = import pinnedPkgs { - overlays = [ (import rustOverlay) ]; - }; - - rustbin = pkgs.rust-bin.stable.latest.default.override { - extensions = [ "rust-src" ]; - targets = [ "wasm32-unknown-unknown" ]; - }; -in -pkgs.mkShell.override { stdenv = llvm11stdenv;} { - - nativeBuildInputs = with pkgs; [ - binaryen - jq - ]; - - buildInputs = with pkgs; [ - pkg-config - rustbin - wasm-pack - ]; - -} \ No newline at end of file diff --git a/flake.nix b/flake.nix index c02dbe14542..de14809a885 100644 --- a/flake.nix +++ b/flake.nix @@ -64,6 +64,9 @@ # We include rust-src to ensure rust-analyzer works. # See https://discourse.nixos.org/t/rust-src-not-found-and-other-misadventures-of-developing-rust-on-nixos/11570/4 extensions = [ "rust-src" ]; + # possible fix for "section too large" + # targets = [ "aarch64-apple-darwin" "wasm32-unknown-unknown" ]; + targets = [ "wasm32-unknown-unknown" ]; }; craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; @@ -164,6 +167,19 @@ buildInputs = [ ] ++ extraBuildInputs; }; + # Combine the environmnet with cargo args needed to build wasm package + noirWasmArgs = wasmEnvironment // { + pname = "noir_wasm"; + + src = ./.; + + cargoExtraArgs = "--lib --package noir_wasm --target wasm32-unknown-unknown"; + + buildInputs = [ ] ++ extraBuildInputs; + + doCheck = false; + }; + # The `port` is parameterized to support parallel test runs without colliding static servers testArgs = port: testEnvironment // { # We provide `barretenberg-transcript00` from the overlay to the tests as a URL hosted via a static server @@ -192,6 +208,7 @@ # Build *just* the cargo dependencies, so we can reuse all of that work between runs native-cargo-artifacts = craneLib.buildDepsOnly nativeArgs; wasm-cargo-artifacts = craneLib.buildDepsOnly wasmArgs; + noir-wasm-cargo-artifacts = craneLib.buildDepsOnly noirWasmArgs; noir-native = craneLib.buildPackage (nativeArgs // { inherit GIT_COMMIT GIT_DIRTY; @@ -210,6 +227,37 @@ # We don't want to run checks or tests when just building the project doCheck = false; }); + + rustPlatform = pkgs.makeRustPlatform { + rustc = rustToolchain; + cargo = rustToolchain; + }; + + wasm-bindgen-cli = rustPlatform.buildRustPackage rec { + pname = "wasm-bindgen-cli"; + version = "0.2.86"; + + src = pkgs.fetchCrate { + inherit pname version; + sha256 = "sha256-56EOiLbdgAcoTrkyvB3t9TjtLaRvGxFUXx4haLwE2QY="; + }; + + cargoSha256 = "sha256-4CPBmz92PuPN6KeGDTdYPAf5+vTFk9EN5Cmx4QJy6yI="; + + nativeBuildInputs = [ pkgs.pkg-config ]; + + buildInputs = [ pkgs.openssl ] ++ pkgs.lib.optionals stdenv.isDarwin [ pkgs.curl pkgs.darwin.apple_sdk.frameworks.Security ]; + + doCheck = false; + + meta = with pkgs.lib; { + homepage = "https://rustwasm.github.io/docs/wasm-bindgen/"; + license = with licenses; [ asl20 /* or */ mit ]; + description = "Facilitating high-level interactions between wasm modules and JavaScript"; + maintainers = with maintainers; [ nitsky rizary ]; + mainProgram = "wasm-bindgen"; + }; + }; in rec { checks = { @@ -252,12 +300,48 @@ git nil nixpkgs-fmt + toml2json llvmPackages.lldb # This ensures the right lldb is in the environment for running rust-lldb + wasm-bindgen-cli ]; shellHook = '' + echo which wasm-bindgen $(which wasm-bindgen) eval "$(starship init bash)" ''; }); + + packages.wasm = craneLib.mkCargoDerivation (noirWasmArgs // { + + inherit GIT_COMMIT; + inherit GIT_DIRTY; + doCheck = false; + + cargoArtifacts = noir-wasm-cargo-artifacts; + + COMMIT_SHORT = builtins.substring 0 7 GIT_COMMIT; + VERSION_APPENDIX = if GIT_DIRTY == "true" then "-dirty" else ""; + PKG_PATH = "./pkg"; + + nativeBuildInputs = with pkgs; [ + which + git + jq + rustToolchain + wasm-bindgen-cli + binaryen + toml2json + ]; + + buildPhaseCargoCommand = '' + bash crates/wasm/buildPhaseCargoCommand.sh + ''; + + installPhase = '' + bash crates/wasm/installPhase.sh + ''; + + }); }); } +