diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38ebf4a..bccf709 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,4 +30,3 @@ jobs: - name: Build and test run: | nix flake check --all-systems --eval-cores 0 -L - nix flake check ./wasi --all-systems --eval-cores 0 -L diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e193c71..72eeae3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,7 +5,12 @@ "type": "cargo", "command": "build", "args": [ - "--release" + "--release", + "--workspace", + "--exclude", + "nix-wasm-plugin-quickjs", + "--exclude", + "nix-wasm-plugin-fib-wasi" ], "options": { "env": { diff --git a/Cargo.lock b/Cargo.lock index ab8ba74..6fbc873 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "arraydeque" version = "0.5.1" @@ -14,11 +29,67 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] [[package]] name = "const-random" @@ -40,6 +111,15 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "crunchy" version = "0.2.4" @@ -55,6 +135,12 @@ dependencies = [ "const-random", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -64,23 +150,53 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "hashbrown" version = "0.14.5" @@ -93,7 +209,18 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] @@ -105,11 +232,64 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "libc" -version = "0.2.176" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libloading" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nix-wasm-plugin-fib" @@ -118,6 +298,14 @@ dependencies = [ "nix-wasm-rust", ] +[[package]] +name = "nix-wasm-plugin-fib-wasi" +version = "0.1.0" +dependencies = [ + "nix-wasm-plugin-fib", + "nix-wasm-rust", +] + [[package]] name = "nix-wasm-plugin-grep" version = "0.1.0" @@ -141,6 +329,14 @@ dependencies = [ "num", ] +[[package]] +name = "nix-wasm-plugin-quickjs" +version = "0.1.0" +dependencies = [ + "nix-wasm-rust", + "rquickjs", +] + [[package]] name = "nix-wasm-plugin-test" version = "0.1.0" @@ -160,6 +356,16 @@ dependencies = [ name = "nix-wasm-rust" version = "0.1.0" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num" version = "0.4.3" @@ -249,6 +455,129 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "relative-path" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0" +dependencies = [ + "serde", +] + +[[package]] +name = "rquickjs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50dc6d6c587c339edb4769cf705867497a2baf0eca8b4645fa6ecd22f02c77a" +dependencies = [ + "rquickjs-core", + "rquickjs-macro", +] + +[[package]] +name = "rquickjs-core" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bf7840285c321c3ab20e752a9afb95548c75cd7f4632a0627cea3507e310c1" +dependencies = [ + "hashbrown 0.16.1", + "relative-path", + "rquickjs-sys", +] + +[[package]] +name = "rquickjs-macro" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7106215ff41a5677b104906a13e1a440b880f4b6362b5dc4f3978c267fad2b80" +dependencies = [ + "convert_case", + "fnv", + "ident_case", + "indexmap", + "proc-macro-crate", + "proc-macro2", + "quote", + "rquickjs-core", + "syn", +] + +[[package]] +name = "rquickjs-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27344601ef27460e82d6a4e1ecb9e7e99f518122095f3c51296da8e9be2b9d83" +dependencies = [ + "bindgen", + "cc", +] + [[package]] name = "rust-ini" version = "0.21.3" @@ -259,6 +588,58 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -268,12 +649,69 @@ dependencies = [ "crunchy", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + [[package]] name = "yaml-rust2" version = "0.10.4" diff --git a/Cargo.toml b/Cargo.toml index 13cd6b1..bfb6449 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,12 @@ members = [ "nix-wasm-rust", "nix-wasm-plugin-fib", + "nix-wasm-plugin-fib-wasi", "nix-wasm-plugin-ini", "nix-wasm-plugin-yaml", "nix-wasm-plugin-mandelbrot", "nix-wasm-plugin-test", + "nix-wasm-plugin-quickjs", "nix-wasm-plugin-grep", ] resolver = "2" diff --git a/flake.nix b/flake.nix index f52dcac..a44cb83 100644 --- a/flake.nix +++ b/flake.nix @@ -20,6 +20,105 @@ packages = forAllSystems ({ pkgs, system }: rec { default = nix-wasm-plugins; + nix-wasi-plugins = with pkgs; + let + rustPackages = pkgs.rustPackages_1_89; + rustPlatform = rustPackages.rustPlatform; + rustSysroot = runCommand "rust-sysroot" { } '' + mkdir -p $out/lib/rustlib + cp -r ${rustPackages."rustc-unwrapped"}/lib/rustlib/* $out/lib/rustlib/ + mkdir -p $out/lib/rustlib/src + ln -s ${rustPlatform.rustcSrc} $out/lib/rustlib/src/rust + ''; + rustcWithSysroot = runCommand "rustc-with-sysroot" { } '' + mkdir -p $out/bin + cat > $out/bin/rustc <<'EOF' + #!/bin/sh + exec ${rustPackages.rustc}/bin/rustc --sysroot ${rustSysroot} "$@" + EOF + chmod +x $out/bin/rustc + ''; + wasiCc = pkgs.pkgsCross.wasi32.stdenv.cc; + wasiLibc = pkgs.pkgsCross.wasi32.wasilibc; + wasiLibcDev = wasiLibc.dev; + wasiSysroot = runCommand "wasi-sysroot" { } '' + mkdir -p $out/include $out/lib/wasm32-wasip1 + cp -R ${wasiLibcDev}/include/* $out/include/ + cp -R ${wasiLibc}/lib/* $out/lib/ + cp -R ${wasiLibc}/lib/* $out/lib/wasm32-wasip1/ + ''; + wasiSdk = runCommand "wasi-sdk-compat" { } '' + mkdir -p $out/bin $out/lib/clang/19 $out/share + + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-clang $out/bin/clang + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-clang++ $out/bin/clang++ + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-ar $out/bin/ar + ln -s ${wasiCc}/bin/wasm32-unknown-wasi-ld.lld $out/bin/ld.lld + + ln -s ${wasiCc}/resource-root/include $out/lib/clang/19/include + ln -s ${wasiSysroot} $out/share/wasi-sysroot + ''; + workspaceVendor = rustPlatform.fetchCargoVendor { + src = self; + hash = "sha256-vkTdv3StxslmBOKy8mFfz5afOiMjBujFd4IU6pkgqGc="; + }; + stdlibVendor = rustPlatform.fetchCargoVendor { + src = rustPlatform.rustcSrc; + cargoRoot = "library"; + hash = "sha256-XD+1wJ7GfnJG4qyulIdZum7VV4rtIoQRM+L0xXUHjXA="; + }; + cargoVendor = runCommand "cargo-vendor-merged" { } '' + mkdir -p $out + cp -R ${workspaceVendor}/* $out/ + mkdir -p $out/.cargo + cp -R ${workspaceVendor}/.cargo/* $out/.cargo/ + chmod -R u+w $out + cp -R ${stdlibVendor}/* $out/ + cp ${workspaceVendor}/Cargo.lock $out/Cargo.lock + cp ${workspaceVendor}/.cargo/config.toml $out/.cargo/config.toml + ''; + in rustPlatform.buildRustPackage { + pname = "nix-wasi-plugins"; + version = cargoToml.package.version; + + cargoLock.lockFile = ./Cargo.lock; + cargoDeps = cargoVendor; + + # FIXME: filter out the non-wasi plugins from the workspace. + src = self; + + buildPhase = '' + RUSTFLAGS="-L ${wasiSdk}/share/wasi-sysroot/lib/wasm32-wasip1" \ + cargo build --release -p nix-wasm-plugin-quickjs -p nix-wasm-plugin-fib-wasi \ + --target wasm32-wasip1 -Z build-std=std,panic_abort + ''; + + installPhase = '' + mkdir -p $out + for i in target/wasm32-wasip1/release/*.wasm; do + wasm-opt -O3 --enable-bulk-memory --enable-nontrapping-float-to-int --enable-simd -o "$out/$(basename "$i")" "$i" + done + ''; + + nativeBuildInputs = [ + rustPackages.rustc.llvmPackages.lld + binaryen + llvmPackages.clang + llvmPackages.libclang + ]; + + WASI_SDK = "${wasiSdk}"; + LIBCLANG_PATH = "${llvmPackages.libclang.lib}/lib"; + RUSTC = "${rustcWithSysroot}/bin/rustc"; + CC_wasm32_wasip1 = "${wasiSdk}/bin/clang"; + AR_wasm32_wasip1 = "${wasiSdk}/bin/ar"; + CFLAGS_wasm32_wasip1 = "--sysroot=${wasiSdk}/share/wasi-sysroot -isystem ${wasiSdk}/lib/clang/19/include"; + BINDGEN_EXTRA_CLANG_ARGS_wasm32_wasip1 = "-fvisibility=default --sysroot=${wasiSdk}/share/wasi-sysroot -isystem ${wasiSdk}/lib/clang/19/include -resource-dir ${wasiSdk}/lib/clang/19"; + CARGO_TARGET_WASM32_WASIP1_LINKER = "${wasiSdk}/bin/ld.lld"; + RUSTC_BOOTSTRAP = "1"; + doCheck = false; + }; + nix-wasm-plugins = with pkgs; rustPlatform.buildRustPackage { pname = cargoToml.package.name; version = cargoToml.package.version; @@ -28,14 +127,22 @@ src = self; + nix_wasi_plugins = nix-wasi-plugins; + CARGO_BUILD_TARGET = "wasm32-unknown-unknown"; - buildPhase = "cargo build --release"; + buildPhase = "cargo build --release --workspace --exclude nix-wasm-plugin-quickjs --exclude nix-wasm-plugin-fib-wasi"; checkPhase = '' + mkdir -p plugins + cp target/wasm32-unknown-unknown/release/*.wasm plugins/ + if [[ -n $nix_wasi_plugins ]]; then + cp $nix_wasi_plugins/*.wasm plugins/ + fi + for i in nix-wasm-plugin-*/tests/*.nix; do echo "running test $i..." base="$(dirname $i)/$(basename $i .nix)" - nix eval --store dummy:// --offline --json --show-trace -I plugins=target/wasm32-unknown-unknown/release --impure --eval-cores 0 --file "$i" > "$base.out" + nix eval --store dummy:// --offline --json --show-trace -I plugins=plugins --impure --eval-cores 0 --file "$i" > "$base.out" cmp "$base.exp" "$base.out" done ''; @@ -45,6 +152,9 @@ for i in target/wasm32-unknown-unknown/release/*.wasm; do wasm-opt -O3 -o "$out/$(basename "$i")" "$i" done + if [[ -n $nix_wasi_plugins ]]; then + cp $nix_wasi_plugins/*.wasm $out/ + fi ''; nativeBuildInputs = [ @@ -63,6 +173,7 @@ devShells = forAllSystems ({ pkgs, system }: rec { default = with pkgs; self.packages.${system}.default.overrideAttrs (attrs: { + nix_wasi_plugins = null; nativeBuildInputs = attrs.nativeBuildInputs ++ [ wabt rust-analyzer diff --git a/nix-wasm-plugin-fib-wasi/Cargo.toml b/nix-wasm-plugin-fib-wasi/Cargo.toml new file mode 100644 index 0000000..339e9d4 --- /dev/null +++ b/nix-wasm-plugin-fib-wasi/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "nix-wasm-plugin-fib-wasi" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "nix_wasm_plugin_fib_wasi" +path = "src/main.rs" + +[dependencies] +nix-wasm-rust = { path = "../nix-wasm-rust" } +nix-wasm-plugin-fib = { path = "../nix-wasm-plugin-fib" } diff --git a/wasi/nix-wasi-plugin-fib/src/main.rs b/nix-wasm-plugin-fib-wasi/src/main.rs similarity index 96% rename from wasi/nix-wasi-plugin-fib/src/main.rs rename to nix-wasm-plugin-fib-wasi/src/main.rs index a45443a..942021a 100644 --- a/wasi/nix-wasi-plugin-fib/src/main.rs +++ b/nix-wasm-plugin-fib-wasi/src/main.rs @@ -23,7 +23,7 @@ fn main() { /* The argument value ID is passed via argv[1]. */ let args: Vec = env::args().collect(); - let arg = Value::from_id( + let arg = Value::from_raw( args[1] .parse::() .expect("argv[1] should be a valid ValueId"), diff --git a/nix-wasm-plugin-fib-wasi/tests/fib.exp b/nix-wasm-plugin-fib-wasi/tests/fib.exp new file mode 100644 index 0000000..ae22902 --- /dev/null +++ b/nix-wasm-plugin-fib-wasi/tests/fib.exp @@ -0,0 +1 @@ +5702887 diff --git a/nix-wasm-plugin-fib-wasi/tests/fib.nix b/nix-wasm-plugin-fib-wasi/tests/fib.nix new file mode 100644 index 0000000..dbb5a5a --- /dev/null +++ b/nix-wasm-plugin-fib-wasi/tests/fib.nix @@ -0,0 +1 @@ +builtins.wasm { path = ; } 33 diff --git a/nix-wasm-plugin-quickjs/Cargo.toml b/nix-wasm-plugin-quickjs/Cargo.toml new file mode 100644 index 0000000..9c59c88 --- /dev/null +++ b/nix-wasm-plugin-quickjs/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "nix-wasm-plugin-quickjs" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +nix-wasm-rust = { path = "../nix-wasm-rust" } +rquickjs = { version = "0.11.0", features = ["bindgen"] } diff --git a/nix-wasm-plugin-quickjs/src/lib.rs b/nix-wasm-plugin-quickjs/src/lib.rs new file mode 100644 index 0000000..60bacc5 --- /dev/null +++ b/nix-wasm-plugin-quickjs/src/lib.rs @@ -0,0 +1,84 @@ +use nix_wasm_rust::{nix_wasm_init_v1, warn, wasi_arg, Value}; +use rquickjs::{Array, Context, Object, Runtime, Value as JsValue}; +use std::string::String as StdString; + +fn fail(context: &str, err: impl std::fmt::Display) -> ! { + warn!("quickjs {context} failed: {err}"); + panic!("quickjs {context} failed: {err}"); +} + +fn js_value_to_nix(value: JsValue) -> Value { + if value.is_null() || value.is_undefined() { + return Value::make_null(); + } + if let Some(b) = value.as_bool() { + return Value::make_bool(b); + } + if let Some(i) = value.as_int() { + return Value::make_int(i as i64); + } + if let Some(f) = value.as_float() { + return Value::make_float(f); + } + if let Some(js_str) = value.as_string() { + let s = js_str + .to_string() + .unwrap_or_else(|err| fail("string conversion", err)); + return Value::make_string(&s); + } + if value.is_array() { + let array: Array = value + .clone() + .into_array() + .unwrap_or_else(|| fail("array conversion", "value is not an array")); + let mut items = Vec::new(); + for entry in array.into_iter() { + let entry = entry.unwrap_or_else(|err| fail("array iteration", err)); + items.push(js_value_to_nix(entry)); + } + return Value::make_list(&items); + } + if value.is_object() { + let object: Object = value + .into_object() + .unwrap_or_else(|| fail("object conversion", "value is not an object")); + let mut entries: Vec<(StdString, Value)> = Vec::new(); + for entry in object.props::() { + let (key, value) = entry.unwrap_or_else(|err| fail("object iteration", err)); + entries.push((key, js_value_to_nix(value))); + } + let attrs: Vec<(&str, Value)> = entries + .iter() + .map(|(key, value)| (key.as_str(), *value)) + .collect(); + return Value::make_attrset(&attrs); + } + + warn!("quickjs value type not supported: {:?}", value.type_of()); + panic!("quickjs value type not supported: {:?}", value.type_of()); +} + +fn eval_impl(arg: Value) -> Value { + let code = arg.get_string(); + + let runtime = Runtime::new().unwrap_or_else(|err| fail("runtime init", err)); + let context = Context::full(&runtime).unwrap_or_else(|err| fail("context init", err)); + + context.with(|ctx| { + let value: JsValue = ctx.eval(code).unwrap_or_else(|err| fail("eval", err)); + js_value_to_nix(value) + }) +} + +#[no_mangle] +pub extern "C" fn eval(arg: Value) -> Value { + nix_wasm_init_v1(); + eval_impl(arg) +} + +#[no_mangle] +pub extern "C" fn _start() { + nix_wasm_init_v1(); + let result = eval_impl(wasi_arg()); + result.return_to_nix(); +} diff --git a/nix-wasm-plugin-quickjs/tests/eval.exp b/nix-wasm-plugin-quickjs/tests/eval.exp new file mode 100644 index 0000000..2193dfa --- /dev/null +++ b/nix-wasm-plugin-quickjs/tests/eval.exp @@ -0,0 +1 @@ +{"arr":[1,"two",false],"bool":true,"float":1.5,"nil":null,"num":1,"obj":{"nested":3},"str":"hello","undef":null} diff --git a/nix-wasm-plugin-quickjs/tests/eval.nix b/nix-wasm-plugin-quickjs/tests/eval.nix new file mode 100644 index 0000000..83a5eac --- /dev/null +++ b/nix-wasm-plugin-quickjs/tests/eval.nix @@ -0,0 +1,12 @@ +builtins.wasm { path = ; } '' + ({ + num: 1, + float: 1.5, + str: "hello", + bool: true, + nil: null, + undef: undefined, + arr: [1, "two", false], + obj: { nested: 3 } + }) +'' diff --git a/nix-wasm-rust/src/lib.rs b/nix-wasm-rust/src/lib.rs index 7abf2ef..9d39be6 100644 --- a/nix-wasm-rust/src/lib.rs +++ b/nix-wasm-rust/src/lib.rs @@ -36,6 +36,16 @@ pub struct Value(ValueId); type ValueId = u32; +pub fn wasi_arg() -> Value { + let arg = std::env::args() + .nth(1) + .unwrap_or_else(|| panic("missing WASI argument")); + let value_id = arg + .parse::() + .unwrap_or_else(|err| panic(&format!("invalid WASI argument '{arg}': {err}"))); + Value::from_raw(value_id) +} + #[repr(C)] pub enum Type { Int = 1, @@ -50,8 +60,8 @@ pub enum Type { } impl Value { - pub fn from_id(id: ValueId) -> Value { - Value(id) + pub fn from_raw(value: ValueId) -> Value { + Value(value) } pub fn get_type(&self) -> Type { diff --git a/wasi/Cargo.lock b/wasi/Cargo.lock deleted file mode 100644 index 97acf50..0000000 --- a/wasi/Cargo.lock +++ /dev/null @@ -1,22 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "nix-wasi-plugin-fib" -version = "0.1.0" -dependencies = [ - "nix-wasm-plugin-fib", - "nix-wasm-rust", -] - -[[package]] -name = "nix-wasm-plugin-fib" -version = "0.1.0" -dependencies = [ - "nix-wasm-rust", -] - -[[package]] -name = "nix-wasm-rust" -version = "0.1.0" diff --git a/wasi/Cargo.toml b/wasi/Cargo.toml deleted file mode 100644 index 471306e..0000000 --- a/wasi/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[workspace] -members = [ - "nix-wasi-plugin-fib", -] -resolver = "2" - -[profile.release] -lto = true -opt-level = 'z' diff --git a/wasi/flake.lock b/wasi/flake.lock deleted file mode 100644 index 8ea60bf..0000000 --- a/wasi/flake.lock +++ /dev/null @@ -1,256 +0,0 @@ -{ - "nodes": { - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1769929675, - "narHash": "sha256-EBpe7sXCPLs+qVePXbA7kc+Kmpmp0pWysEpjjEWTK+E=", - "rev": "78d518f5ca32a86dc767de481160dbae640c70cf", - "revCount": 2542, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/nix-community/fenix/0.1.2542%2Brev-78d518f5ca32a86dc767de481160dbae640c70cf/019c1851-0ed1-7f81-b175-8e8bbad651e6/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/nix-community/fenix/0.1.%2A.tar.gz" - } - }, - "fenix_2": { - "inputs": { - "nixpkgs": [ - "naersk", - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src_2" - }, - "locked": { - "lastModified": 1752475459, - "narHash": "sha256-z6QEu4ZFuHiqdOPbYss4/Q8B0BFhacR8ts6jO/F/aOU=", - "owner": "nix-community", - "repo": "fenix", - "rev": "bf0d6f70f4c9a9cf8845f992105652173f4b617f", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": [ - "nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1748821116, - "narHash": "sha256-F82+gS044J1APL0n4hH50GYdPRv/5JWm34oCJYmVKdE=", - "rev": "49f0870db23e8c1ca0b5259734a02cd9e1e371a1", - "revCount": 377, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/hercules-ci/flake-parts/0.1.377%2Brev-49f0870db23e8c1ca0b5259734a02cd9e1e371a1/01972f28-554a-73f8-91f4-d488cc502f08/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/hercules-ci/flake-parts/0.1" - } - }, - "flake-schemas": { - "locked": { - "lastModified": 1761577921, - "narHash": "sha256-eK3/xbUOrxp9fFlei09XNjqcdiHXxndzrTXp7jFpOk8=", - "rev": "47849c7625e223d36766968cc6dc23ba0e135922", - "revCount": 107, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/DeterminateSystems/flake-schemas/0.2.0/019a4a84-544d-7c59-b26d-e334e320c932/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/DeterminateSystems/flake-schemas/%2A.tar.gz" - } - }, - "git-hooks-nix": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": [ - "nix" - ], - "nixpkgs": [ - "nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1747372754, - "narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=", - "rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46", - "revCount": 1026, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/cachix/git-hooks.nix/0.1.1026%2Brev-80479b6ec16fefd9c1db3ea13aeb038c60530f46/0196d79a-1b35-7b8e-a021-c894fb62163d/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/cachix/git-hooks.nix/0.1.941" - } - }, - "naersk": { - "inputs": { - "fenix": "fenix_2", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1769799857, - "narHash": "sha256-88IFXZ7Sa1vxbz5pty0Io5qEaMQMMUPMonLa3Ls/ss4=", - "rev": "9d4ed44d8b8cecdceb1d6fd76e74123d90ae6339", - "revCount": 385, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/nix-community/naersk/0.1.385%2Brev-9d4ed44d8b8cecdceb1d6fd76e74123d90ae6339/019c104b-c472-7eef-ba5e-d14761c1e374/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/nix-community/naersk/0.1.%2A.tar.gz" - } - }, - "nix": { - "inputs": { - "flake-parts": "flake-parts", - "git-hooks-nix": "git-hooks-nix", - "nixpkgs": "nixpkgs", - "nixpkgs-23-11": "nixpkgs-23-11", - "nixpkgs-regression": "nixpkgs-regression" - }, - "locked": { - "lastModified": 1772218272, - "narHash": "sha256-58OxqvVmSo7y5GuLrt1ogU8tmGvGgtijmaurHPZMSBs=", - "owner": "DeterminateSystems", - "repo": "nix-src", - "rev": "fe3515c2e42b95fb250c22549367285191fb9f5d", - "type": "github" - }, - "original": { - "owner": "DeterminateSystems", - "repo": "nix-src", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1761597516, - "narHash": "sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8+ON/0Yy8+a5vsDU=", - "rev": "daf6dc47aa4b44791372d6139ab7b25269184d55", - "revCount": 811874, - "type": "tarball", - "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2505.811874%2Brev-daf6dc47aa4b44791372d6139ab7b25269184d55/019a3494-3498-707e-9086-1fb81badc7fe/source.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://flakehub.com/f/NixOS/nixpkgs/0.2505" - } - }, - "nixpkgs-23-11": { - "locked": { - "lastModified": 1717159533, - "narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", - "type": "github" - } - }, - "nixpkgs-regression": { - "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - } - }, - "root": { - "inputs": { - "fenix": "fenix", - "flake-schemas": "flake-schemas", - "naersk": "naersk", - "nix": "nix", - "nixpkgs": [ - "nix", - "nixpkgs" - ] - } - }, - "rust-analyzer-src": { - "flake": false, - "locked": { - "lastModified": 1769857242, - "narHash": "sha256-3eKpRRzKz0KzY7CJzRXFm4POwEqbuTohyQ2ajI/zKvg=", - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "17304e9c7e11d26139672d3d77aa498b1cae0d69", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - }, - "rust-analyzer-src_2": { - "flake": false, - "locked": { - "lastModified": 1752428706, - "narHash": "sha256-EJcdxw3aXfP8Ex1Nm3s0awyH9egQvB2Gu+QEnJn2Sfg=", - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "591e3b7624be97e4443ea7b5542c191311aa141d", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/wasi/flake.nix b/wasi/flake.nix deleted file mode 100644 index 28ec373..0000000 --- a/wasi/flake.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ - description = "Nix WebAssembly plugin example"; - - inputs = { - nixpkgs.follows = "nix/nixpkgs"; - flake-schemas.url = "https://flakehub.com/f/DeterminateSystems/flake-schemas/*.tar.gz"; - nix = { - type = "github"; - owner = "DeterminateSystems"; - repo = "nix-src"; - }; - fenix = { - url = "https://flakehub.com/f/nix-community/fenix/0.1.*.tar.gz"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - naersk = { - url = "https://flakehub.com/f/nix-community/naersk/0.1.*.tar.gz"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - }; - - outputs = { self, ... }@inputs: - let - cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); - supportedSystems = [ "aarch64-darwin" "x86_64-linux" ]; - forAllSystems = f: inputs.nixpkgs.lib.genAttrs supportedSystems (system: f { - pkgs = import inputs.nixpkgs { - inherit system; - overlays = [ - (final: prev: { - rustToolchain = with inputs.fenix.packages.${system}; - combine [ - latest.rustc - latest.cargo - targets.wasm32-wasip1.latest.rust-std - ]; - }) - ]; - }; - inherit system; - }); - in - { - packages = forAllSystems ({ pkgs, system }: rec { - default = nix-wasi-plugins; - - nix-wasi-plugins = with pkgs; - (pkgs.callPackage inputs.naersk { - cargo = pkgs.rustToolchain; - rustc = pkgs.rustToolchain; - }).buildPackage { - pname = "nix-wasi-plugins"; - version = "0.0.1"; - - src = ./..; - - preConfigure = "cd wasi"; - - CARGO_BUILD_TARGET = "wasm32-wasip1"; - - postInstall = - '' - for i in $out/bin/*.wasm; do - wasm-opt -O3 -o "$i" "$i" - done - ''; - - buildInputs = [ - binaryen - ]; - }; - }); - - devShells = forAllSystems ({ pkgs, system }: rec { - default = with pkgs; self.packages.${system}.default.overrideAttrs (attrs: { - nativeBuildInputs = attrs.nativeBuildInputs ++ [ - rust-analyzer - rustfmt - clippy - ]; - }); - }); - - checks = forAllSystems ({ pkgs, system }: rec { - build = self.packages.${system}.default; - run = - pkgs.runCommand "nix-wasi-plugins-test-${system}" - { - buildInputs = [ inputs.nix.packages.${system}.nix ]; - NIX_CONFIG = "extra-experimental-features = wasm-builtin"; - } - '' - [[ $(nix eval --store dummy:// --offline --json --show-trace -I plugins=${self.packages.${system}.nix-wasi-plugins}/bin --impure --eval-cores 0 \ - --expr 'builtins.wasm { path = ; } 33') = 5702887 ]] - mkdir -p $out - ''; - }); - }; -} diff --git a/wasi/nix-wasi-plugin-fib/Cargo.toml b/wasi/nix-wasi-plugin-fib/Cargo.toml deleted file mode 100644 index 2b15028..0000000 --- a/wasi/nix-wasi-plugin-fib/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "nix-wasi-plugin-fib" -version = "0.1.0" -edition = "2021" - -[[bin]] -name = "nix-wasi-plugin-fib" -path = "src/main.rs" - -[dependencies] -nix-wasm-rust = { path = "../../nix-wasm-rust" } -nix-wasm-plugin-fib = { path = "../../nix-wasm-plugin-fib" }