commit 68fbcfb32e5a94f870c3535a276dce254faadbcd Author: Michael Franzl Date: Thu May 2 17:38:17 2024 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2be92b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +result diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7f276b --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# wasm-sdk + +A SDK for LLVM C and C++ WebAssembly development based on Nix. + +It builds all required dependencies (*clang, clang++, wasm-ld, libcxx, compiler-rt*, and *wasi-libc*) +and exposes the following environment variables needed to compile to WebAssembly, for example: + +``` +WASM_LLVM=/nix/store/akpcpb9ycb98jjbp6dyg1j65vkwqp1lm-wasm-llvm +WASM_LIBCXX_LIB=/nix/store/ll4hi2jkhv8399dhbz6q0qgw97c6hyja-wasm-libcxx/lib +WASM_LIBCXX_INC=/nix/store/ll4hi2jkhv8399dhbz6q0qgw97c6hyja-wasm-libcxx/include/c++/v1 +WASM_COMPILER_RT_LIB=/nix/store/59lmk928vly8126zq7mabzc9123hknj2-wasm-compiler-rt/lib/wasi +WASI_LIBC_LIB=/nix/store/qislis4ivwv3l721dbhghax6j4kp3ccb-wasi-libc/lib +WASI_LIBC_INC=/nix/store/71k5vk20275571n0bsij42qdasbxc82b-wasi-libc-dev/include +``` + +## Goals + +* Lean toolchain leveraging as much as possible from upstream sources. +* Basic levels of WASI (no threading, no exceptions). + + +## Versions + +* LLVM: 17 +* wasi-libc: 21 + + +## Usage + +The included derivation produces a single file with exportable environment variables. + +Example: + +```sh +env $(cat $(nix-build -E 'with import {}; callPackage ./default.nix {}')) printenv +``` + +A *flake* is also included that exposes the needed variables in the following ways (three ways to choose from, for convenience): + +1. as the `paths` (*attrset* type) *passthru* of the *derivation* of the *default package* (to use in other *flakes*). +2. as exported environment variables in the *default development shell* (`nix develop`). +3. as text in a file (`nix build` produces the file `./result`). diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..e96e3cf --- /dev/null +++ b/default.nix @@ -0,0 +1,34 @@ +{ pkgs, lib, ... }: +let + wasm-llvm = import ./wasm-llvm.nix { inherit pkgs; }; + wasm-libcxx = import ./wasm-libcxx.nix { inherit pkgs; }; + wasi-libc = import ./wasi-libc.nix { inherit pkgs; }; + wasm-compiler-rt = import ./wasm-compiler-rt.nix { inherit pkgs; }; + + paths = { + WASM_LLVM = wasm-llvm; + WASM_LIBCXX_LIB = "${wasm-libcxx}/lib"; + WASM_LIBCXX_INC = "${wasm-libcxx}/include/c++/v1"; + WASM_COMPILER_RT_LIB = "${wasm-compiler-rt}/lib/wasi"; + WASI_LIBC_LIB = "${wasi-libc}/lib"; + WASI_LIBC_INC = "${wasi-libc.dev}/include"; + }; + + pathsFileContents = lib.strings.concatLines ( + lib.attrsets.mapAttrsToList (name: value: name + "=" + value) paths + ); +in +pkgs.stdenv.mkDerivation rec { + name = "wasm-sdk"; + version = "1.0.0"; + + dontUnpack = true; + + installPhase = '' + echo "${pathsFileContents}" > $out + ''; + + passthru = { + inherit paths; + }; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..1cb431a --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1714253743, + "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d4bf635 --- /dev/null +++ b/flake.nix @@ -0,0 +1,17 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + }; + + outputs = + { self, nixpkgs }: + let + pkgs = nixpkgs.legacyPackages.x86_64-linux; + package = import ./default.nix pkgs; + in + { + packages.x86_64-linux.default = package; + formatter.x86_64-linux = pkgs.nixfmt-rfc-style; + devShells.x86_64-linux.default = pkgs.mkShell package.paths; + }; +} diff --git a/wasi-libc.nix b/wasi-libc.nix new file mode 100644 index 0000000..7bb75ce --- /dev/null +++ b/wasi-libc.nix @@ -0,0 +1,32 @@ +{ pkgs }: +with pkgs; +stdenv.mkDerivation rec { + name = "wasi-libc"; + version = "21"; + src = fetchFromGitHub { + owner = "WebAssembly"; + repo = "wasi-libc"; + rev = "refs/tags/wasi-sdk-21"; + hash = "sha256-mQp54JYb3bsmyQy5SByPFu9uxhKDy/XXF7lF9bEUfOo="; + }; + + wasm-llvm = import ./wasm-llvm.nix { inherit pkgs; }; + + outputs = [ + "out" + "dev" + "share" + ]; + + dontInstall = true; + dontFixup = true; + + makeFlags = [ + "CC=${wasm-llvm}/bin/clang" + "NM=${wasm-llvm}/bin/nm" + "AR=${wasm-llvm}/bin/ar" + "SYSROOT_LIB=${builtins.placeholder "out"}/lib" + "SYSROOT_INC=${builtins.placeholder "dev"}/include" + "SYSROOT_SHARE=${builtins.placeholder "share"}/share" + ]; +} diff --git a/wasm-compiler-rt.nix b/wasm-compiler-rt.nix new file mode 100644 index 0000000..aef3eb0 --- /dev/null +++ b/wasm-compiler-rt.nix @@ -0,0 +1,40 @@ +{ pkgs }: +with pkgs; +stdenv.mkDerivation rec { + name = "wasm-compiler-rt"; + version = "17.0.6"; + src = fetchzip { + url = "https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-17.0.6.tar.gz"; + hash = "sha256-8MEDLLhocshmxoEBRSKlJ/GzJ8nfuzQ8qn0X/vLA+ag="; + }; + + wasm-llvm = import ./wasm-llvm.nix { inherit pkgs; }; + + nativeBuildInputs = [ + cmake + ninja + ]; + + dontFixup = true; + + configurePhase = '' + cmake -G Ninja \ + -DCMAKE_MODULE_PATH=${wasm-llvm.dev}/cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_TOOLCHAIN_FILE=${wasm-llvm.dev}/cmake/toolchain.cmake \ + -DCOMPILER_RT_BAREMETAL_BUILD=ON \ + -DCOMPILER_RT_INCLUDE_TESTS=OFF \ + -DCOMPILER_RT_HAS_FPIC_FLAG=OFF \ + -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \ + -DCMAKE_INSTALL_PREFIX=$out \ + $src/compiler-rt/lib/builtins + ''; + + buildPhase = '' + ninja -v + ''; + + installPhase = '' + ninja -v install + ''; +} diff --git a/wasm-libcxx.nix b/wasm-libcxx.nix new file mode 100644 index 0000000..3d010dc --- /dev/null +++ b/wasm-libcxx.nix @@ -0,0 +1,69 @@ +{ pkgs }: +with pkgs; +stdenv.mkDerivation rec { + name = "wasm-libcxx"; + version = "17.0.6"; + src = fetchzip { + url = "https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-17.0.6.tar.gz"; + hash = "sha256-8MEDLLhocshmxoEBRSKlJ/GzJ8nfuzQ8qn0X/vLA+ag="; + }; + + wasm-llvm = import ./wasm-llvm.nix { inherit pkgs; }; + + wasi-libc = import ./wasi-libc.nix { inherit pkgs; }; + + dontFixup = true; + + nativeBuildInputs = [ + cmake + ninja + python3 + ]; + + configurePhase = '' + cmake -G Ninja \ + -DCMAKE_C_COMPILER_WORKS=ON \ + -DCMAKE_CXX_COMPILER_WORKS=ON \ + -DCMAKE_AR=${wasm-llvm}/bin/ar \ + -DCMAKE_MODULE_PATH=${wasm-llvm.dev}/cmake \ + -DCMAKE_TOOLCHAIN_FILE=/${wasm-llvm.dev}/cmake/toolchain.cmake \ + -DCMAKE_STAGING_PREFIX=$out \ + -DCMAKE_POSITION_INDEPENDENT_CODE=OFF \ + -DLIBCXX_ENABLE_THREADS:BOOL=OFF \ + -DLIBCXX_HAS_PTHREAD_API:BOOL=OFF \ + -DLIBCXX_HAS_EXTERNAL_THREAD_API:BOOL=OFF \ + -DLIBCXX_HAS_WIN32_THREAD_API:BOOL=OFF \ + -DLLVM_COMPILER_CHECKED=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DLIBCXX_ENABLE_SHARED:BOOL=OFF \ + -DLIBCXX_ENABLE_EXCEPTIONS:BOOL=OFF \ + -DLIBCXX_ENABLE_FILESYSTEM:BOOL=OFF \ + -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT:BOOL=OFF \ + -DLIBCXX_CXX_ABI=libcxxabi \ + -DLIBCXX_HAS_MUSL_LIBC:BOOL=ON \ + -DLIBCXX_ABI_VERSION=2 \ + -DLIBCXXABI_ENABLE_EXCEPTIONS:BOOL=OFF \ + -DLIBCXXABI_ENABLE_SHARED:BOOL=OFF \ + -DLIBCXXABI_SILENT_TERMINATE:BOOL=ON \ + -DLIBCXXABI_ENABLE_THREADS:BOOL=OFF \ + -DLIBCXXABI_HAS_PTHREAD_API:BOOL=OFF \ + -DLIBCXXABI_HAS_EXTERNAL_THREAD_API:BOOL=OFF \ + -DLIBCXXABI_HAS_WIN32_THREAD_API:BOOL=OFF \ + -DLIBCXXABI_USE_LLVM_UNWINDER:BOOL=OFF \ + -DUNIX:BOOL=ON \ + --debug-trycompile \ + -DCMAKE_SYSROOT_COMPILE=${wasi-libc.dev} \ + -DCMAKE_SYSROOT_LINK=${wasi-libc} \ + -DCMAKE_CXX_FLAGS="-fno-exceptions" \ + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \ + ${src}/runtimes + ''; + + buildPhase = '' + ninja -v + ''; + + installPhase = '' + ninja -v install + ''; +} diff --git a/wasm-llvm.nix b/wasm-llvm.nix new file mode 100644 index 0000000..ade6cbb --- /dev/null +++ b/wasm-llvm.nix @@ -0,0 +1,98 @@ +{ pkgs }: +with pkgs; +stdenv.mkDerivation { + name = "wasm-llvm"; + version = "17.0.6"; + src = fetchzip { + url = "https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-17.0.6.tar.gz"; + hash = "sha256-8MEDLLhocshmxoEBRSKlJ/GzJ8nfuzQ8qn0X/vLA+ag="; + }; + + nativeBuildInputs = [ + cmake + ninja + python3 + ]; + + phases = [ + "configurePhase" + "installPhase" + ]; + + outputs = [ + "out" + "dev" + ]; + + configurePhase = '' + cmake -G Ninja \ + -DCMAKE_INSTALL_PREFIX=$out \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_ENABLE_ZLIB=OFF \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DLLVM_ENABLE_ZSTD=OFF \ + -DLLVM_STATIC_LINK_CXX_STDLIB=ON \ + -DLLVM_HAVE_LIBXAR=OFF \ + -DLLVM_INCLUDE_TESTS=OFF \ + -DLLVM_INCLUDE_UTILS=OFF \ + -DLLVM_INCLUDE_BENCHMARKS=OFF \ + -DLLVM_INCLUDE_EXAMPLES=OFF \ + -DLLVM_TARGETS_TO_BUILD=WebAssembly \ + -DLLVM_DEFAULT_TARGET_TRIPLE=wasm32-wasi \ + -DLLVM_ENABLE_PROJECTS="lld;clang;clang-tools-extra" \ + -DLLVM_INSTALL_BINUTILS_SYMLINKS=TRUE \ + -DLLVM_ENABLE_LIBXML2=OFF \ + $src/llvm + ''; + + installPhase = '' + mkdir -p $dev/cmake + + cat > $dev/cmake/toolchain.cmake <<-CMAKE + set(CMAKE_SYSTEM_NAME WASI) + set(CMAKE_SYSTEM_VERSION 1) + set(CMAKE_SYSTEM_PROCESSOR wasm32) + set(triple wasm32-wasi) + + set(CMAKE_C_COMPILER $out/bin/clang) + set(CMAKE_CXX_COMPILER $out/bin/clang++) + set(CMAKE_ASM_COMPILER $out/bin/clang) + set(CMAKE_AR $out/bin/llvm-ar) + set(CMAKE_RANLIB $out/bin/llvm-ranlib) + + set(CMAKE_C_COMPILER_TARGET wasm32-wasi) + set(CMAKE_CXX_COMPILER_TARGET wasm32-wasi) + set(CMAKE_ASM_COMPILER_TARGET wasm32-wasi) + + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + CMAKE + + mkdir -p $dev/cmake/Platform + echo "set(WASI 1)" > $dev/cmake/Platform/WASI.cmake + + ninja -v \ + install-clang \ + install-clang-format \ + install-clang-tidy \ + install-clang-apply-replacements \ + install-lld \ + install-llvm-mc \ + install-llvm-ranlib \ + install-llvm-strip \ + install-llvm-dwarfdump \ + install-clang-resource-headers \ + install-ar \ + install-ranlib \ + install-strip \ + install-nm \ + install-size \ + install-strings \ + install-objdump \ + install-objcopy \ + install-c++filt \ + install-llvm-config + ''; +}