diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bccf709..38ebf4a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,3 +30,4 @@ 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/.gitignore b/.gitignore index aefdad5..83ea0d2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ result /target/ *~ /*/tests/*.out +/wasi/target/ \ No newline at end of file diff --git a/flake.lock b/flake.lock index 7f8d2b6..30e4966 100644 --- a/flake.lock +++ b/flake.lock @@ -83,11 +83,11 @@ "nixpkgs-regression": "nixpkgs-regression" }, "locked": { - "lastModified": 1769164980, - "narHash": "sha256-aJ03Ab2QUns5LF07iABVWZhh3vy88xRMMQplR5Cs0u8=", + "lastModified": 1770399320, + "narHash": "sha256-ZeYsgvxLG0peMQsmzPLvFjp0ZNVI9NuxZSG3dUQpZ7w=", "owner": "DeterminateSystems", "repo": "nix-src", - "rev": "370987fbbd83d174cfc70e729424236c29f47564", + "rev": "c9f71f35b00972bec5af4fe6d3cf3980c66a2372", "type": "github" }, "original": { diff --git a/nix-wasm-plugin-fib/Cargo.toml b/nix-wasm-plugin-fib/Cargo.toml index 9a2207e..a79a2a1 100644 --- a/nix-wasm-plugin-fib/Cargo.toml +++ b/nix-wasm-plugin-fib/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [lib] -crate-type = ["cdylib"] +crate-type = ["lib", "cdylib"] [dependencies] nix-wasm-rust = { path = "../nix-wasm-rust" } diff --git a/nix-wasm-rust/src/lib.rs b/nix-wasm-rust/src/lib.rs index 1457c8e..7abf2ef 100644 --- a/nix-wasm-rust/src/lib.rs +++ b/nix-wasm-rust/src/lib.rs @@ -50,6 +50,10 @@ pub enum Type { } impl Value { + pub fn from_id(id: ValueId) -> Value { + Value(id) + } + pub fn get_type(&self) -> Type { extern "C" { fn get_type(value: ValueId) -> Type; @@ -284,4 +288,11 @@ impl Value { } } } + + pub fn return_to_nix(&self) -> ! { + extern "C" { + fn return_to_nix(value: ValueId) -> !; + } + unsafe { return_to_nix(self.0) } + } } diff --git a/wasi/Cargo.lock b/wasi/Cargo.lock new file mode 100644 index 0000000..97acf50 --- /dev/null +++ b/wasi/Cargo.lock @@ -0,0 +1,22 @@ +# 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 new file mode 100644 index 0000000..471306e --- /dev/null +++ b/wasi/Cargo.toml @@ -0,0 +1,9 @@ +[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 new file mode 100644 index 0000000..0e3a605 --- /dev/null +++ b/wasi/flake.lock @@ -0,0 +1,257 @@ +{ + "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": 1771600547, + "narHash": "sha256-3Q/azBE+UgGYL3W5UE0nXCLxLo2MLiAG0NZi2vzG5mQ=", + "owner": "DeterminateSystems", + "repo": "nix-src", + "rev": "13061498efb05dd2895a88b966093b511272bf2d", + "type": "github" + }, + "original": { + "owner": "DeterminateSystems", + "ref": "eelcodolstra/nix-282-allow-wasm-plugins-to-use-wasi", + "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 new file mode 100644 index 0000000..4fce2d9 --- /dev/null +++ b/wasi/flake.nix @@ -0,0 +1,100 @@ +{ + 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"; + ref = "eelcodolstra/nix-282-allow-wasm-plugins-to-use-wasi"; + }; + 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.wasi 33') = 5702887 ]] + mkdir -p $out + ''; + }); + }; +} diff --git a/wasi/nix-wasi-plugin-fib/Cargo.toml b/wasi/nix-wasi-plugin-fib/Cargo.toml new file mode 100644 index 0000000..2b15028 --- /dev/null +++ b/wasi/nix-wasi-plugin-fib/Cargo.toml @@ -0,0 +1,12 @@ +[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" } diff --git a/wasi/nix-wasi-plugin-fib/src/main.rs b/wasi/nix-wasi-plugin-fib/src/main.rs new file mode 100644 index 0000000..a45443a --- /dev/null +++ b/wasi/nix-wasi-plugin-fib/src/main.rs @@ -0,0 +1,37 @@ +use nix_wasm_plugin_fib::fib; +use nix_wasm_rust::Value; +use std::env; + +fn main() { + eprintln!("Greetings from WASI!"); + eprintln!("Environment size: {}", env::vars().count()); + eprintln!( + "System time: {}", + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() + ); + eprintln!( + "Current directory: {}", + std::env::current_dir().unwrap().display() + ); + eprintln!( + "Number of files in /: {}", + std::fs::read_dir("/").map(|x| x.count()).unwrap_or(0) + ); + + /* The argument value ID is passed via argv[1]. */ + let args: Vec = env::args().collect(); + let arg = Value::from_id( + args[1] + .parse::() + .expect("argv[1] should be a valid ValueId"), + ); + + /* Do the computation. */ + let result = fib(arg); + + /* Return the value to the host. This also ends execution. */ + result.return_to_nix(); +}