diff options
| author | Sander Vocke <sandervocke@gmail.com> | 2023-09-07 07:52:44 +0000 |
|---|---|---|
| committer | Sander Vocke <sandervocke@gmail.com> | 2023-09-07 09:09:01 +0000 |
| commit | 5863c50ee766a9d61f220b554f514c238abdf40c (patch) | |
| tree | 4dd186b5479bb5dc2f83bc1be2b2cb3548731b70 | |
| parent | 97851f00182c540c4f61b5fb09a69e241d31dbaf (diff) | |
Workflow for building a C/C++ sysroot.
| -rw-r--r-- | .github/workflows/build_cxx_sysroot.yml | 117 | ||||
| -rw-r--r-- | .github/workflows/files/clang-wasix.cmake_toolchain | 31 | ||||
| -rw-r--r-- | .github/workflows/main.yml | 2 | ||||
| -rw-r--r-- | README.md | 20 | ||||
| -rw-r--r-- | test/wasix/c_pthreads/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | test/wasix/c_pthreads/main.c | 26 | ||||
| -rw-r--r-- | test/wasix/c_pthreads/test.sh | 11 | ||||
| -rw-r--r-- | test/wasix/cpp_atomic/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | test/wasix/cpp_atomic/main.cpp | 12 | ||||
| -rw-r--r-- | test/wasix/cpp_atomic/test.sh | 9 | ||||
| -rw-r--r-- | test/wasix/cpp_executable/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | test/wasix/cpp_executable/main.cpp | 3 | ||||
| -rw-r--r-- | test/wasix/cpp_executable/test.sh | 9 | ||||
| -rw-r--r-- | test/wasix/cpp_iostream/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | test/wasix/cpp_iostream/main.cpp | 6 | ||||
| -rw-r--r-- | test/wasix/cpp_iostream/test.sh | 9 | ||||
| -rw-r--r-- | test/wasix/cpp_threads/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | test/wasix/cpp_threads/main.cpp | 14 | ||||
| -rw-r--r-- | test/wasix/cpp_threads/test.sh | 11 | ||||
| -rwxr-xr-x | test/wasix/run_tests.sh | 32 |
20 files changed, 331 insertions, 1 deletions
diff --git a/.github/workflows/build_cxx_sysroot.yml b/.github/workflows/build_cxx_sysroot.yml new file mode 100644 index 0000000..b4e92f6 --- /dev/null +++ b/.github/workflows/build_cxx_sysroot.yml @@ -0,0 +1,117 @@ +name: Build C/C++ Sysroot + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + checks: write + +jobs: + build_cxx_sysroot: + runs-on: ubuntu-latest + container: + image: archlinux:base-devel + options: --user root --workdir / + steps: + - name: Update and install dependencies + run: | + pacman -Syu --noconfirm + pacman -Sy --noconfirm coreutils nodejs npm wget git cmake ninja llvm clang rsync make lld wasmer + + - name: Checkout + uses: actions/checkout@v3 + + - name: Build + run: | + TARGET_ARCH=wasm32 TARGET_OS=wasix make CC=clang AR=llvm-ar NM=llvm-nm THREAD_MODEL=posix || true + rm -rf /opt/wasix-sysroot + cp -r sysroot /opt/wasix-sysroot + cp .github/workflows/files/clang-wasix.cmake_toolchain /opt/wasix-sysroot/clang-wasix.cmake_toolchain + + - name: Determine LLVM revision + run: | + export LLVM_TAG=$(echo "llvmorg-$(llvm-ar --version | grep -i "LLVM version" | sed -r 's/.*version ([0-9\.]+).*/\1/')") + echo "LLVM tag: $LLVM_TAG" + echo "LLVM_REV=$(git ls-remote --tags https://github.com/llvm/llvm-project.git $LLVM_TAG | sed -r 's/([^ \t]*).*/\1/')" | tee -a $GITHUB_ENV + echo "LLVM_TAG=$LLVM_TAG" | tee -a $GITHUB_ENV + + - name: Cache LLVM + uses: actions/cache@v3 + if: ${{ !env.ACT }} + with: + path: llvm-project + key: llvm-${{ env.LLVM_REV }} + + - name: Checkout LLVM + run: | + if [ ! -d "llvm-project" ]; then git clone https://github.com/llvm/llvm-project.git; fi + cd llvm-project + git fetch origin refs/tags/${{ env.LLVM_TAG }} + if [ "$(git rev-parse ${{ env.LLVM_TAG }})" != "$(git rev-parse HEAD)" ]; then echo "Checkout ($(git rev-parse ${{ env.LLVM_TAG }}) != $(git rev-parse HEAD))" && git reset --hard ${{ env.LLVM_TAG }} && echo "checked out $(git rev-parse HEAD)"; fi + + - name: Build and install compiler_rt builtins + run: | + mkdir -p build-compiler-rt-builtins + cd build-compiler-rt-builtins + cmake --fresh -DCOMPILER_RT_BAREMETAL_BUILD=On -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCOMPILER_RT_OS_DIR=wasm32-wasi -DCOMPILER_RT_DEFAULT_TARGET_ONLY:BOOL=ON -DCMAKE_TOOLCHAIN_FILE=/opt/wasix-sysroot/clang-wasix.cmake_toolchain -DCMAKE_SYSROOT=/opt/wasix-sysroot -DCMAKE_INSTALL_PREFIX=/opt/wasix-sysroot ../llvm-project/compiler-rt/lib/builtins + cmake --build . --target install --parallel 4 + export CLANG_MAJOR_VERSION=$(clang --version | grep -i "clang version" | sed -r 's/.*version ([0-9]+).*/\1/') + mkdir -p /usr/lib/clang/$CLANG_MAJOR_VERSION/lib/wasi + cp /opt/wasix-sysroot/lib/wasm32-wasi/libclang_rt.builtins-wasm32.a /usr/lib/clang/$CLANG_MAJOR_VERSION/lib/wasi/libclang_rt.builtins-wasm32.a + + - name: Build and install LLVM libc++ + run: > + mkdir -p build-libcxx && + cd build-libcxx && + cmake + --fresh + -DCMAKE_TOOLCHAIN_FILE=/opt/wasix-sysroot/clang-wasix.cmake_toolchain + -DCMAKE_SYSROOT=/opt/wasix-sysroot + -DCMAKE_INSTALL_PREFIX=/opt/wasix-sysroot + -DCXX_SUPPORTS_CXX11=ON + -DLIBCXX_ENABLE_THREADS:BOOL=ON + -DLIBCXX_HAS_PTHREAD_API:BOOL=ON + -DLIBCXX_HAS_EXTERNAL_THREAD_API:BOOL=OFF + -DLIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY:BOOL=OFF + -DLIBCXX_HAS_WIN32_THREAD_API:BOOL=OFF + -DCMAKE_BUILD_TYPE=RelWithDebugInfo + -DLIBCXX_ENABLE_SHARED:BOOL=OFF + -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY:BOOL=OFF + -DLIBCXX_ENABLE_EXCEPTIONS:BOOL=OFF + -DLIBCXX_ENABLE_FILESYSTEM: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=ON + -DLIBCXXABI_HAS_PTHREAD_API:BOOL=ON + -DLIBCXXABI_HAS_EXTERNAL_THREAD_API:BOOL=OFF + -DLIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY:BOOL=OFF + -DLIBCXXABI_HAS_WIN32_THREAD_API:BOOL=OFF + -DLIBCXXABI_ENABLE_PIC:BOOL=OFF + -DCMAKE_C_COMPILER_WORKS=ON + -DCMAKE_CXX_COMPILER_WORKS=ON + -DLLVM_COMPILER_CHECKED=ON + -DUNIX:BOOL=ON + -DLIBCXX_LIBDIR_SUFFIX=/wasm32-wasi + -DLIBCXXABI_LIBDIR_SUFFIX=/wasm32-wasi + -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" + ../llvm-project/runtimes + && cmake --build . --target install --parallel 4 + + - name: Upload sysroot + if: ${{ !env.ACT }} + uses: actions/upload-artifact@v2 + with: + name: wasix-sysroot + path: /opt/wasix-sysroot + + - name: Run WASIX tests + run: | + TOOLCHAIN=/opt/wasix-sysroot/clang-wasix.cmake_toolchain ./test/wasix/run_tests.sh diff --git a/.github/workflows/files/clang-wasix.cmake_toolchain b/.github/workflows/files/clang-wasix.cmake_toolchain new file mode 100644 index 0000000..826b94a --- /dev/null +++ b/.github/workflows/files/clang-wasix.cmake_toolchain @@ -0,0 +1,31 @@ +# Cmake toolchain description file for the Makefile for WASI +cmake_minimum_required(VERSION 3.5.0) + +set(COMPILE_FLAGS "-O2 -matomics -mbulk-memory -mmutable-globals -pthread -mthread-model posix -ftls-model=local-exec -fno-trapping-math -D_WASI_EMULATED_MMAN -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_PROCESS_CLOCKS -fno-exceptions") +set(LINK_FLAGS "-lwasi-emulated-mman -fno-exceptions -Wl,--shared-memory -Wl,--max-memory=4294967296 -Wl,--import-memory -Wl,--export-dynamic -Wl,--export=__heap_base -Wl,--export=__stack_pointer -Wl,--export=__data_end -Wl,--export=__wasm_init_tls -Wl,--export=__wasm_signal -Wl,--export=__tls_size -Wl,--export=__tls_align -Wl,--export=__tls_base") + +set(CMAKE_SYSTEM_NAME WASI) # Generic for now, to not trigger a Warning +set(CMAKE_SYSTEM_VERSION 1) +set(CMAKE_SYSTEM_PROCESSOR wasm32) +set(CMAKE_C_COMPILER_ID Clang) +set(triple wasm32-wasmer-wasi) +set(CMAKE_C_COMPILER_TARGET ${triple}) +set(CMAKE_CXX_COMPILER_TARGET ${triple}) +set(CMAKE_ASM_COMPILER_TARGET ${triple}) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMPILE_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS}") +set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} ${LINK_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_FLAGS}") +set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "--sysroot=") + +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_LINKER wasm-ld) +set(CMAKE_AR llvm-ar) + +# Don't look in the sysroot for executables to run during the build +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# Only look in the sysroot (not in the host paths) for the rest +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
\ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2af8a5b..f73a3e7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ name: CI -on: [push, pull_request] +on: workflow_dispatch # This is the wasi-libc CI build, not for wasix-libc jobs: buildlibc: @@ -47,6 +47,26 @@ Major bug fixes and/or zero day vulnerabilities will be addressed promptly here with careful consideration for resolving issues without compromising the long-term support goal. +# Installation + +A pre-built sysroot suitable for C/C++ is released in this repository. + +To build from source, have a look at the `build_cxx_sysroot.yml` script and +replicate its build steps. + +# Usage + +For building CMake projects, a toolchain file is included in the released sysroot +at `wasix-sysroot/clang-wasm.cmake_toolchain`. In addition to specifying the +toolchain: + +* `wasm-ld` is needed for linking. It is usually available in your system's `LLVM` + linker package. It should be in the `PATH`. +* `CMAKE_TOOLCHAIN_FILE` and `CMAKE_SYSROOT` should both be set by you. Example: + +The WASIX-specific tests and script in `test/wasix` can serve as examples for how +to set this up. + # WASI Libc WASI Libc is a libc for WebAssembly programs built on top of WASI system calls. diff --git a/test/wasix/c_pthreads/CMakeLists.txt b/test/wasix/c_pthreads/CMakeLists.txt new file mode 100644 index 0000000..de21e61 --- /dev/null +++ b/test/wasix/c_pthreads/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required (VERSION 3.5.0) +project (basic_executable) + +add_executable(main main.c)
\ No newline at end of file diff --git a/test/wasix/c_pthreads/main.c b/test/wasix/c_pthreads/main.c new file mode 100644 index 0000000..ba5d49a --- /dev/null +++ b/test/wasix/c_pthreads/main.c @@ -0,0 +1,26 @@ + +#include <pthread.h> +#include <stdio.h> + +void *thread(void *ptr) +{ + long type = (long)ptr; + fprintf(stdout,"thread %ld\n", type); + return ptr; +} + +int main(int argc, char **argv) +{ + pthread_t thread1, thread2; + int thr = 1; + int thr2 = 2; + pthread_create(&thread1, NULL, *thread, (void*)thr); + pthread_create(&thread2, NULL, *thread, (void*)thr2); + + pthread_join(thread1,NULL); + pthread_join(thread2,NULL); + + fprintf(stdout, "threads joined\n"); + + return 0; +}
\ No newline at end of file diff --git a/test/wasix/c_pthreads/test.sh b/test/wasix/c_pthreads/test.sh new file mode 100644 index 0000000..caf5767 --- /dev/null +++ b/test/wasix/c_pthreads/test.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +tmpfile=$(mktemp) +wasmer run --verbose --enable-all ./main > $tmpfile +RESULT=$? +if [ "$RESULT" != "0" ]; then + echo "Test failed: different exit code ($RESULT vs. 0)" > /dev/stderr + exit 1 +fi + +echo "c_pthreads test passed"
\ No newline at end of file diff --git a/test/wasix/cpp_atomic/CMakeLists.txt b/test/wasix/cpp_atomic/CMakeLists.txt new file mode 100644 index 0000000..94ec92f --- /dev/null +++ b/test/wasix/cpp_atomic/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required (VERSION 3.5.0) +project (basic_executable) + +add_executable(main main.cpp)
\ No newline at end of file diff --git a/test/wasix/cpp_atomic/main.cpp b/test/wasix/cpp_atomic/main.cpp new file mode 100644 index 0000000..a3c3fd0 --- /dev/null +++ b/test/wasix/cpp_atomic/main.cpp @@ -0,0 +1,12 @@ +#include <atomic> +#include <stdio.h> + +std::atomic<int> a; +std::atomic<int> b; + +int main(int argc, char** argv) { + a = 10; + b = a.load(); + fprintf(stdout, "%d\n", b.load()); + return 0; +}
\ No newline at end of file diff --git a/test/wasix/cpp_atomic/test.sh b/test/wasix/cpp_atomic/test.sh new file mode 100644 index 0000000..f14bd18 --- /dev/null +++ b/test/wasix/cpp_atomic/test.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +wasmer run --verbose --enable-all ./main +RESULT=$? +if [ "$RESULT" != "0" ]; then + echo "Test failed: different exit code ($RESULT vs. 0)" > /dev/stderr + exit 1 +fi +echo "cpp_atomic test passed"
\ No newline at end of file diff --git a/test/wasix/cpp_executable/CMakeLists.txt b/test/wasix/cpp_executable/CMakeLists.txt new file mode 100644 index 0000000..94ec92f --- /dev/null +++ b/test/wasix/cpp_executable/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required (VERSION 3.5.0) +project (basic_executable) + +add_executable(main main.cpp)
\ No newline at end of file diff --git a/test/wasix/cpp_executable/main.cpp b/test/wasix/cpp_executable/main.cpp new file mode 100644 index 0000000..96aef32 --- /dev/null +++ b/test/wasix/cpp_executable/main.cpp @@ -0,0 +1,3 @@ +int main(int argc, char** argv) { + return 123; +}
\ No newline at end of file diff --git a/test/wasix/cpp_executable/test.sh b/test/wasix/cpp_executable/test.sh new file mode 100644 index 0000000..e67e4c6 --- /dev/null +++ b/test/wasix/cpp_executable/test.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +wasmer run --verbose --enable-all ./main +RESULT=$? +if [ "$RESULT" != "123" ]; then + echo "Test failed: different exit code ($RESULT vs. 123)" > /dev/stderr + exit 1 +fi +echo "cpp_executable test passed"
\ No newline at end of file diff --git a/test/wasix/cpp_iostream/CMakeLists.txt b/test/wasix/cpp_iostream/CMakeLists.txt new file mode 100644 index 0000000..94ec92f --- /dev/null +++ b/test/wasix/cpp_iostream/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required (VERSION 3.5.0) +project (basic_executable) + +add_executable(main main.cpp)
\ No newline at end of file diff --git a/test/wasix/cpp_iostream/main.cpp b/test/wasix/cpp_iostream/main.cpp new file mode 100644 index 0000000..f19bd5e --- /dev/null +++ b/test/wasix/cpp_iostream/main.cpp @@ -0,0 +1,6 @@ +#include <iostream> + +int main(int argc, char** argv) { + std::cout << "Hello, world!\n"; + return 0; +}
\ No newline at end of file diff --git a/test/wasix/cpp_iostream/test.sh b/test/wasix/cpp_iostream/test.sh new file mode 100644 index 0000000..0fcb58b --- /dev/null +++ b/test/wasix/cpp_iostream/test.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +wasmer run --verbose --enable-all ./main +RESULT=$? +if [ "$RESULT" != "0" ]; then + echo "Test failed: different exit code ($RESULT vs. 0)" > /dev/stderr + exit 1 +fi +echo "cpp_iostream test passed"
\ No newline at end of file diff --git a/test/wasix/cpp_threads/CMakeLists.txt b/test/wasix/cpp_threads/CMakeLists.txt new file mode 100644 index 0000000..94ec92f --- /dev/null +++ b/test/wasix/cpp_threads/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required (VERSION 3.5.0) +project (basic_executable) + +add_executable(main main.cpp)
\ No newline at end of file diff --git a/test/wasix/cpp_threads/main.cpp b/test/wasix/cpp_threads/main.cpp new file mode 100644 index 0000000..8f750ba --- /dev/null +++ b/test/wasix/cpp_threads/main.cpp @@ -0,0 +1,14 @@ +#include <string> +#include <thread> +#include <stdio.h> + +using namespace std; + +void task1(string msg) { + printf("task1 says: %s\n", msg.c_str()); +} + +int main() { + thread t1(task1, "Hello World!"); + t1.join(); +}
\ No newline at end of file diff --git a/test/wasix/cpp_threads/test.sh b/test/wasix/cpp_threads/test.sh new file mode 100644 index 0000000..a5bfdea --- /dev/null +++ b/test/wasix/cpp_threads/test.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +tmpfile=$(mktemp) +wasmer run --verbose --enable-all ./main > $tmpfile +RESULT=$? +if [ "$RESULT" != "0" ]; then + echo "Test failed: different exit code ($RESULT vs. 0)" > /dev/stderr + exit 1 +fi + +echo "cpp_threads test passed"
\ No newline at end of file diff --git a/test/wasix/run_tests.sh b/test/wasix/run_tests.sh new file mode 100755 index 0000000..3337a95 --- /dev/null +++ b/test/wasix/run_tests.sh @@ -0,0 +1,32 @@ +#!/bin/bash +SCRIPT_DIR=$(dirname "$(readlink -f "$0")") +BUILD_DIR=$SCRIPT_DIR/../../test-builds +TESTS= +STATUS=0 +FAILED_TESTS="" +PASSED_TESTS="" + +if [ ! -z "${@:1}" ]; then + TESTS=${@:1} +else + TESTS=$(cd $SCRIPT_DIR && ls -d */) +fi + +for test in $TESTS; do + mkdir -p ${BUILD_DIR}/${test} + cd ${BUILD_DIR}/${test} + cmake --fresh -DCMAKE_MAKE_PROGRAM=make -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN -DCMAKE_SYSROOT=/opt/wasix-sysroot $SCRIPT_DIR/${test} + cmake --build . --target all + bash $SCRIPT_DIR/${test}/test.sh + RESULT=$? + if [ $RESULT -eq 0 ]; then + PASSED_TESTS="$PASSED_TESTS $test" + else + FAILED_TESTS="$FAILED_TESTS $test" + STATUS=1 + fi +done + +echo "Passed tests: $PASSED_TESTS" +echo "Failed tests: $FAILED_TESTS" +exit $STATUS |
