mirror of https://github.com/WebAssembly/wasi-sdk
Add riscv64gc-unknown-linux-musl to the build matrix using a native ubuntu-24.04-riscv runner (RISE Project), mirroring the arm64-linux pattern which uses ubuntu-22.04-arm. Changes: - Use ubuntu-24.04-riscv runner instead of cross-compilation on x86_64 - Dockerfile.riscv64-linux: Ubuntu 24.04 base (AlmaLinux 8 has no riscv64 image); native build-essential, no cross-compiler env vars - docker-build.sh: skip wasmtime volume mount when WASI_SDK_CI_SKIP_SYSROOT is set (wasmtime is not available on riscv64 runners yet) - WASI_SDK_CI_SKIP_SYSROOT: 1 and WASI_SDK_LLDB=OFF kept as before; sysroot tests require running wasm binaries which needs wasmtime RISE runners are GitHub Actions runners for riscv64, free for open source projects: https://github.com/apps/rise-risc-v-runners Closes #607 Signed-off-by: Bruno Verachten <gounthar@gmail.com>pull/619/head
commit
d4e56f2ffc
@ -0,0 +1,4 @@
|
||||
# Our docker builds do not require the submodule sources so exclude them as
|
||||
# they can be very big.
|
||||
/src
|
||||
.git
|
||||
@ -0,0 +1,2 @@
|
||||
# Bourne-style shell scripts: These are Unix-style scripts. Don't add CR's.
|
||||
*.sh text eol=lf
|
||||
@ -0,0 +1,16 @@
|
||||
name: 'Prepare wasi-sdk git directory'
|
||||
description: 'Prepare wasi-sdk git directory'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- run: git fetch --tags --force
|
||||
name: Force-fetch tags to work around actions/checkout#290
|
||||
shell: bash
|
||||
# We can't use `--depth 1` here sadly because the GNU config
|
||||
# submodule is not pinned to a particular tag/branch. Please
|
||||
# bump depth (or even better, the submodule), in case of "error:
|
||||
# Server does not allow request for unadvertised object" in the
|
||||
# future.
|
||||
- run: git submodule update --init --depth 64 --jobs 3
|
||||
shell: bash
|
||||
@ -0,0 +1,28 @@
|
||||
name: 'Install wasi-sdk dependencies'
|
||||
description: 'Install wasi-sdk dependencies'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup `wasmtime` for tests
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
with:
|
||||
version: "41.0.3"
|
||||
- name: Install ccache, ninja (macOS)
|
||||
run: brew install ccache ninja
|
||||
if: runner.os == 'macOS'
|
||||
shell: bash
|
||||
- name: Install ccache, ninja (Windows)
|
||||
run: choco install ccache ninja
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
shell: bash
|
||||
# Windows arm runners don't come with rust by default (see https://github.com/actions/partner-runner-images/blob/main/images/arm-windows-11-image.md)
|
||||
# but the x86 ones do (see https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-Readme.md)
|
||||
- name: Install cargo (Windows-arm)
|
||||
run: choco install rust
|
||||
if: matrix.os == 'windows-11-arm'
|
||||
shell: bash
|
||||
- name: Install ccache, ninja (Linux)
|
||||
run: sudo apt-get install -y ccache ninja-build
|
||||
if: runner.os == 'Linux'
|
||||
shell: bash
|
||||
@ -0,0 +1,281 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'wasi-sdk-*'
|
||||
branches:
|
||||
- main
|
||||
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ matrix.artifact }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- artifact: x86_64-linux
|
||||
os: ubuntu-24.04
|
||||
|
||||
- artifact: arm64-linux
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
- artifact: riscv64-linux
|
||||
os: ubuntu-24.04-riscv
|
||||
rust_target: riscv64gc-unknown-linux-gnu
|
||||
cross_cmake_args: -DWASI_SDK_LLDB=OFF
|
||||
env:
|
||||
WASI_SDK_CI_SKIP_SYSROOT: 1
|
||||
|
||||
- artifact: arm64-macos
|
||||
os: macos-14
|
||||
rust_target: aarch64-apple-darwin
|
||||
env:
|
||||
WASI_SDK_CI_TOOLCHAIN_LLVM_CMAKE_ARGS: >-
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64
|
||||
|
||||
- artifact: x86_64-macos
|
||||
os: macos-14
|
||||
rust_target: x86_64-apple-darwin
|
||||
env:
|
||||
WASI_SDK_CI_SKIP_SYSROOT: 1
|
||||
WASI_SDK_CI_TOOLCHAIN_LLVM_CMAKE_ARGS: >-
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64
|
||||
|
||||
- artifact: x86_64-windows
|
||||
os: windows-2022
|
||||
|
||||
- artifact: arm64-windows
|
||||
os: windows-11-arm
|
||||
|
||||
env: ${{ matrix.env || fromJSON('{}') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/checkout
|
||||
- uses: ./.github/actions/install-deps
|
||||
|
||||
# Persist ccache-based caches across builds. This directory is configured
|
||||
# via the CCACHE_DIR env var below for ccache to use.
|
||||
#
|
||||
# Bump the prefix number to evict all previous caches and enforce a clean
|
||||
# build, in the unlikely case that some weird build error occur and ccache
|
||||
# becomes a potential suspect.
|
||||
- uses: actions/cache@v5
|
||||
id: cache-restore
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/ccache
|
||||
key: 0-cache-${{ matrix.artifact }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
0-cache-${{ matrix.artifact }}-
|
||||
- run: |
|
||||
mkdir -p '${{ runner.tool_cache }}/ccache'
|
||||
echo 'CCACHE_DIR=${{ runner.tool_cache }}/ccache' >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
# Configure CMake flags for `ci/build.sh` as necessary for each
|
||||
# matrix entry.
|
||||
- run: |
|
||||
cmake_args=-DWASI_SDK_ARTIFACT=${{ matrix.artifact }}
|
||||
if [ "${{ matrix.rust_target }}" != "" ]; then
|
||||
rustup target add ${{ matrix.rust_target }}
|
||||
cmake_args="$cmake_args -DRUST_TARGET=${{ matrix.rust_target }}"
|
||||
fi
|
||||
if [ "${{ matrix.cross_cmake_args }}" != "" ]; then
|
||||
cmake_args="$cmake_args ${{ matrix.cross_cmake_args }}"
|
||||
fi
|
||||
echo WASI_SDK_CI_TOOLCHAIN_CMAKE_ARGS="$cmake_args" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Clear ccache statistics
|
||||
run: ccache --zero-stats
|
||||
|
||||
- name: Build and test (macOS)
|
||||
run: ./ci/build.sh
|
||||
if: runner.os == 'macOS'
|
||||
|
||||
- name: Build and test (Linux)
|
||||
run: ./ci/docker-build.sh ${{ matrix.artifact }}
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
# Setup the VS Developoer Prompt environment variables to explicitly use
|
||||
# MSVC to compile LLVM as that avoids extra runtime dependencies
|
||||
# msys/mingw might bring.
|
||||
#
|
||||
# As of 2024-07-22 this sha is the "v1.13.0" tag.
|
||||
- uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
- name: Build and test (Windows)
|
||||
run: |
|
||||
# Delete a troublesome binary as recommended here
|
||||
# https://github.com/ilammy/msvc-dev-cmd?tab=readme-ov-file#name-conflicts-with-shell-bash
|
||||
rm /usr/bin/link
|
||||
# Use a shorter build directory than the default on Windows to avoid
|
||||
# hitting path length and command line length limits. See
|
||||
# WebAssembly/wasi-libc#514. Despite using a different build directory
|
||||
# though still move the `dist` folder to `build/dist` so the upload
|
||||
# step below doesn't need a windows-specific hook.
|
||||
./ci/build.sh C:/wasi-sdk
|
||||
mkdir build
|
||||
cp -r C:/wasi-sdk/dist build
|
||||
shell: bash
|
||||
if: startsWith(matrix.os, 'windows')
|
||||
|
||||
# Upload the `dist` folder from the build as the artifacts for this
|
||||
# runner.
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ format( 'dist-{0}', matrix.artifact) }}
|
||||
path: build/dist
|
||||
|
||||
# Caches are persisted across runs by restoring the latest cache which
|
||||
# means that quite a lot of cruft can accumulate. Prune older entries that
|
||||
# haven't been used by this run to avoid the cache continuously getting
|
||||
# larger. In theory this should use `--evict-older-than $dur` where `$dur`
|
||||
# is the time since the start of the run, but I'm not sure how to easily
|
||||
# calculate that so pick something loose like one day instead.
|
||||
- name: Prune ccache objects
|
||||
run: ccache --evict-older-than 1d
|
||||
|
||||
# Help debug ccache issues by showing what happened.
|
||||
- if: always()
|
||||
name: Show ccache statistics
|
||||
run: ccache --show-stats
|
||||
|
||||
# Always save a cache, even if the build failed. This ensures that if
|
||||
# live-debugging via CI the build gets to pick up where it left off last
|
||||
# time instead of having to recreate everything each time a failure
|
||||
# happens.
|
||||
- if: always() && steps.cache-restore.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/ccache
|
||||
key: 0-cache-${{ matrix.artifact }}-${{ github.run_id }}
|
||||
|
||||
build-only-sysroot:
|
||||
name: Build only sysroot - ${{ matrix.name }}
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: default
|
||||
- name: exceptions
|
||||
defines: -DWASI_SDK_EXCEPTIONS=ON
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/checkout
|
||||
- uses: ./.github/actions/install-deps
|
||||
- run: cargo install wasm-component-ld@0.5.21
|
||||
- run: sudo apt-get update -y && sudo apt-get install -y clang-20 lld-20
|
||||
- run: |
|
||||
cmake -G Ninja -B build -S . \
|
||||
-DCMAKE_C_COMPILER=/usr/lib/llvm-20/bin/clang \
|
||||
-DCMAKE_SYSTEM_NAME=WASI \
|
||||
-DWASI_SDK_INCLUDE_TESTS=ON \
|
||||
-DWASI_SDK_CPU_CFLAGS="" \
|
||||
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=OFF \
|
||||
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=OFF \
|
||||
${{ matrix.defines }}
|
||||
- run: ninja -C build
|
||||
- run: ctest --output-on-failure --parallel 10 --test-dir build/tests
|
||||
|
||||
# Once all of the above matrix entries have completed this job will run and
|
||||
# assemble the final `wasi-sdk-*` artifacts by fusing the toolchain/sysroot
|
||||
# artifacts.
|
||||
finalize:
|
||||
name: Finalize wasi-sdk artifacts
|
||||
needs: build
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/checkout
|
||||
|
||||
# Download all artifacts from all platforms in `build`, merge them into
|
||||
# final wasi-sdk-* artifacts, and then upload them.
|
||||
- uses: actions/download-artifact@v8
|
||||
- run: ./ci/merge-artifacts.sh
|
||||
- uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: release-artifacts
|
||||
path: dist
|
||||
|
||||
# Use the `wasi-sdk-*` artifacts just created to create a docker image
|
||||
# with a toolchain pre-installed.
|
||||
- uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: docker/setup-qemu-action@v2
|
||||
- uses: docker/setup-buildx-action@v2
|
||||
- uses: docker/metadata-action@v4
|
||||
id: meta
|
||||
with:
|
||||
images: ghcr.io/${{ github.repository }}
|
||||
tags: |
|
||||
type=schedule
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
type=ref,event=pr
|
||||
type=sha
|
||||
- name: Build and push wasi-sdk docker image
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' && github.event_name != 'workflow_dispatch' }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Publish a draft release
|
||||
if: startsWith(github.ref, 'refs/tags')
|
||||
run: gh release create --draft --prerelease --generate-notes ${{ github.ref_name }} ./dist/*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Test the final artifacts as-is without passing `--sysroot` or
|
||||
# `-resource-dir` or any extra flags. This exercises running the compiler
|
||||
# as-is from the distribution tarballs and ensuring that it can build and pass
|
||||
# all tests.
|
||||
test-standalone:
|
||||
name: Test standalone toolchain
|
||||
needs: build
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/actions/checkout
|
||||
- uses: ./.github/actions/install-deps
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: dist-x86_64-linux
|
||||
path: dist-x86_64-linux
|
||||
- run: ./ci/merge-artifacts.sh
|
||||
- run: tar xf dist/wasi-sdk-*.tar.gz
|
||||
- run: |
|
||||
cmake -G Ninja -B build -S . \
|
||||
-DWASI_SDK_INCLUDE_TESTS=ON \
|
||||
-DWASI_SDK_TEST_HOST_TOOLCHAIN=ON \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$(ls ./wasi-sdk-*/share/cmake/wasi-sdk.cmake)
|
||||
- run: ninja -C build build-tests
|
||||
- run: ctest --output-on-failure --parallel 10 --test-dir build/tests
|
||||
@ -0,0 +1,2 @@
|
||||
build
|
||||
dist
|
||||
@ -0,0 +1,9 @@
|
||||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/llvm/llvm-project
|
||||
[submodule "src/wasi-libc"]
|
||||
path = src/wasi-libc
|
||||
url = https://github.com/WebAssembly/wasi-libc
|
||||
[submodule "src/config"]
|
||||
path = src/config
|
||||
url = https://git.savannah.gnu.org/git/config.git
|
||||
@ -0,0 +1,40 @@
|
||||
# Build logic for building both a toolchain and a sysroot for WASI.
|
||||
#
|
||||
# This top level `CMakeLists.txt` file can be used either to build a clang
|
||||
# toolchain or a WASI sysroot. Note that this can't be done at the same time.
|
||||
# A toolchain build requires a compiler for the target architecture. A
|
||||
# WASI sysroot build requires this previous compiler and must be runnable on
|
||||
# the host.
|
||||
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
project(wasi-sdk)
|
||||
include(ExternalProject)
|
||||
|
||||
set(WASI_SDK_TARGETS "wasm32-wasi;wasm32-wasip1;wasm32-wasip2;wasm32-wasip1-threads;wasm32-wasi-threads"
|
||||
CACHE STRING "List of WASI targets to build")
|
||||
option(WASI_SDK_BUILD_TOOLCHAIN "Build a toolchain instead of the sysroot" OFF)
|
||||
|
||||
set(llvm_proj_dir ${CMAKE_CURRENT_SOURCE_DIR}/src/llvm-project)
|
||||
set(wasi_libc ${CMAKE_CURRENT_SOURCE_DIR}/src/wasi-libc)
|
||||
|
||||
include(wasi-sdk-enable-ccache)
|
||||
|
||||
find_program(PYTHON python3 python REQUIRED)
|
||||
|
||||
# Set some variables based on the `version.py` script
|
||||
set(version_script ${CMAKE_CURRENT_SOURCE_DIR}/version.py)
|
||||
execute_process(
|
||||
COMMAND ${PYTHON} ${version_script}
|
||||
OUTPUT_VARIABLE wasi_sdk_version
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
message(STATUS "wasi-sdk version is ${wasi_sdk_version}")
|
||||
|
||||
# Only include one version of the build logic as pulling in both isn't
|
||||
# supported at this time.
|
||||
if(WASI_SDK_BUILD_TOOLCHAIN)
|
||||
include(wasi-sdk-toolchain)
|
||||
else()
|
||||
include(wasi-sdk-sysroot)
|
||||
endif()
|
||||
@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at either sunfish@mozilla.com or tyler@fastly.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
@ -0,0 +1,60 @@
|
||||
# Support for C++ Exceptions
|
||||
|
||||
The released artifacts for wasi-sdk at this time do not support C++ exceptions.
|
||||
LLVM and Clang, however, have support for C++ exceptions in WebAssembly and this
|
||||
is intended to serve as documentation of the current state of affairs of using
|
||||
C++ exceptions. It should be noted though that the current status of C++
|
||||
exceptions support is not intended to be the final state of support, and this is
|
||||
all continuing to be iterated on over time.
|
||||
|
||||
## Building wasi-sdk with exceptions
|
||||
|
||||
When building the sysroot with wasi-sdk you can pass `-DWASI_SDK_EXCEPTIONS=ON`
|
||||
to enable support for C++ exceptions. For example:
|
||||
|
||||
```shell script
|
||||
$ cmake -G Ninja -B build/sysroot -S . \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$path/to/wasi-sdk-p1.cmake \
|
||||
-DWASI_SDK_EXCEPTIONS=ON
|
||||
```
|
||||
|
||||
The C++ standard library will be compiled with support for exceptions for the
|
||||
desired targets and the resulting sysroot supports using exceptions.
|
||||
|
||||
## Compiling code with C++ exceptions
|
||||
|
||||
Currently extra compilation flags are required to fully support C++ exceptions.
|
||||
Without these flags programs using C++ exceptions will not work correctly:
|
||||
|
||||
* `-fwasm-exceptions` - needed to enable the WebAssembly exception-handling
|
||||
proposal.
|
||||
* `-mllvm -wasm-use-legacy-eh=false` - indicates that the standard WebAssembly
|
||||
exception-handling instructions should be used.
|
||||
* `-lunwind` - links in support for unwinding which C++ exceptions requires.
|
||||
|
||||
This can be specified for example with:
|
||||
|
||||
```shell script
|
||||
$ export CFLAGS="-fwasm-exceptions -mllvm -wasm-use-legacy-eh=false"
|
||||
$ export LDFLAGS="-lunwind"
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
Currently C++ exceptions support in wasi-sdk does not support shared libraries.
|
||||
Fixing this will require resolving some miscellaneous build issues in this
|
||||
repository itself.
|
||||
|
||||
## Future Plans
|
||||
|
||||
There are a few tracking issues with historical discussion about C++ exceptions
|
||||
support in wasi-sdk such as [#334](https://github.com/WebAssembly/wasi-sdk/issues/334)
|
||||
and [#565](https://github.com/WebAssembly/wasi-sdk/issues/565). The major
|
||||
remaining items are:
|
||||
|
||||
* Figure out support for shared libraries.
|
||||
* Determine how to ship a sysroot that supports both with-and-without
|
||||
exceptions.
|
||||
* Figure out how to avoid the need for extra compiler flags when using
|
||||
exceptions.
|
||||
* Figure out if a new wasm target is warranted.
|
||||
@ -0,0 +1,220 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
--- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
@ -0,0 +1,238 @@
|
||||
# WASI SDK
|
||||
|
||||
## Quick Start
|
||||
|
||||
[Download SDK packages here.][releases]
|
||||
|
||||
[releases]: https://github.com/WebAssembly/wasi-sdk/releases
|
||||
|
||||
## About this repository
|
||||
|
||||
This repository contains no compiler or library code itself; it uses
|
||||
git submodules to pull in the upstream Clang and LLVM tree, as well as the
|
||||
wasi-libc tree.
|
||||
|
||||
The libc portion of this SDK is maintained in [wasi-libc].
|
||||
|
||||
[wasi-libc]: https://github.com/WebAssembly/wasi-libc
|
||||
|
||||
Upstream Clang and LLVM (from 9.0 onwards) can compile for WASI out of the box,
|
||||
and WebAssembly support is included in them by default. So, all that's done here
|
||||
is to provide builds configured to set the default target and sysroot for
|
||||
convenience.
|
||||
|
||||
One could also use a standard Clang installation, build a sysroot from the
|
||||
sources mentioned above, and compile with `--target=wasm32-wasi
|
||||
--sysroot=/path/to/sysroot`. In this scenario, one would also need the
|
||||
`libclang_rt.*.a` objects available separately in the [release
|
||||
downloads][releases] which must be extracted into
|
||||
`$CLANG_INSTALL_DIR/$CLANG_VERSION/lib/`.
|
||||
|
||||
## Clone
|
||||
|
||||
This repository uses git submodule, to clone it you need use the command below :
|
||||
|
||||
```shell script
|
||||
git clone --recursive https://github.com/WebAssembly/wasi-sdk.git
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
The Wasm-sdk's build process needs some packages :
|
||||
|
||||
* `cmake`
|
||||
* `clang`
|
||||
* `ninja`
|
||||
* `python3`
|
||||
* `cargo`
|
||||
|
||||
Please refer to your OS documentation to install those packages.
|
||||
|
||||
## Build
|
||||
|
||||
Building `wasi-sdk` uses CMake and is split into two halves. First you can build
|
||||
the toolchain itself:
|
||||
|
||||
```shell script
|
||||
cmake -G Ninja -B build/toolchain -S . -DWASI_SDK_BUILD_TOOLCHAIN=ON -DCMAKE_INSTALL_PREFIX=build/install
|
||||
cmake --build build/toolchain --target install
|
||||
```
|
||||
|
||||
When you're developing locally you may also wish to pass
|
||||
`-DCMAKE_CXX_COMPILER_LAUNCHER=ccache` to assist with rebuilds. Other supported
|
||||
CMake flags are:
|
||||
|
||||
* `-DLLVM_CMAKE_FLAGS` - extra flags to pass to `cmake` when building
|
||||
LLVM/Clang.
|
||||
* `-DRUST_TARGET` - the specific Rust target triple to build `wasm-component-ld`
|
||||
for, useful for cross-compiles.
|
||||
|
||||
The `clang` compiler should now be located at `build/install/bin/clang` but it's
|
||||
just a compiler, the sysroot isn't built yet. Next the second step of the build
|
||||
is to build the sysroot:
|
||||
|
||||
```shell script
|
||||
cmake -G Ninja -B build/sysroot -S . \
|
||||
-DCMAKE_INSTALL_PREFIX=build/install \
|
||||
-DCMAKE_TOOLCHAIN_FILE=build/install/share/cmake/wasi-sdk.cmake \
|
||||
-DCMAKE_C_COMPILER_WORKS=ON \
|
||||
-DCMAKE_CXX_COMPILER_WORKS=ON
|
||||
cmake --build build/sysroot --target install
|
||||
```
|
||||
|
||||
A full toolchain should now be present at `build/install` and is ready for use
|
||||
in compiling WebAssembly code. Supported CMake flags are:
|
||||
|
||||
* `-DWASI_SDK_DEBUG_PREFIX_MAKE=OFF` - disable `-fdebug-prefix-map` when
|
||||
building C/C++ code to use full host paths instead.
|
||||
* `-DWASI_SDK_INCLUDE_TESTS=ON` - used for building tests.
|
||||
* `-DWASI_SDK_CPU_CFLAGS=..` - used to specify CFLAGS to tweak wasm features
|
||||
to enable/disable. The default is `-mcpu=lime1`.
|
||||
* `-DWASI_SDK_LTO=ON` - whether to enable/disable builds of LTO-capable
|
||||
libraries as part of the build.
|
||||
* `-DWASI_SDK_EXCEPTIONS=ON` - whether to enable/disable support for C++
|
||||
exceptions, see [CppExceptions.md](./CppExceptions.md) for more information.
|
||||
* `-DWASI_SDK_TEST_HOST_TOOLCHAIN=ON` - test the host toolchain's wasi-libc and
|
||||
sysroot libraries, don't build or use fresh libraries for tests.
|
||||
* `-DWASI_SDK_TARGETS=..` - a list of targets to build, by default all WASI
|
||||
targets are compiled.
|
||||
* `-DWASI_SDK_INSTALL_TO_CLANG_RESOURCE_DIR=ON` - install compiler-rt
|
||||
to the compiler's resource directory. might be convenient if you want to
|
||||
use the toolchain (eg. `./build/install/bin/clang`) in-place.
|
||||
|
||||
If you'd like to build distribution artifacts you can use the `dist` target like
|
||||
so:
|
||||
|
||||
```shell script
|
||||
cmake --build build/toolchain --target dist
|
||||
cmake --build build/sysroot --target dist
|
||||
```
|
||||
|
||||
Tarballs will be created under `build/toolchain/dist` and `build/sysroot/dist`.
|
||||
Note that these are separate tarballs for the toolchain and sysroot. To create a
|
||||
single tarball for the entire SDK you'll first want to copy all tarballs into a
|
||||
new folder and then run the `./ci/merge-artifacts.sh` script:
|
||||
|
||||
```shell script
|
||||
mkdir dist-my-platform
|
||||
cp build/toolchain/dist/* build/sysroot/dist/* dist-my-platform
|
||||
./ci/merge-artifacts.sh
|
||||
```
|
||||
|
||||
This will produce `dist/wasi-sdk-*.tar.gz` which is the same as the release
|
||||
artifacts for this repository.
|
||||
|
||||
Finally you can additionally bundle many of the above steps, minus
|
||||
`merge-artifact.sh` by using the CI script to perform both the toolchain and
|
||||
sysroot build:
|
||||
|
||||
```shell script
|
||||
./ci/build.sh
|
||||
```
|
||||
|
||||
The built package can be found into `build/dist` directory.
|
||||
For releasing a new version of the package on GitHub,
|
||||
see [RELEASING.md](RELEASING.md).
|
||||
|
||||
## Install
|
||||
|
||||
A typical installation from the release binaries might look like the following:
|
||||
|
||||
```shell script
|
||||
WASI_OS=linux
|
||||
WASI_ARCH=x86_64 # or 'arm64' if running on arm64 host
|
||||
WASI_VERSION=27
|
||||
WASI_VERSION_FULL=${WASI_VERSION}.0
|
||||
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}.tar.gz
|
||||
tar xvf wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}.tar.gz
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
Use the clang installed in the `wasi-sdk` directory:
|
||||
|
||||
```shell script
|
||||
WASI_SDK_PATH=`pwd`/wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}
|
||||
CC="${WASI_SDK_PATH}/bin/clang --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot"
|
||||
$CC foo.c -o foo.wasm
|
||||
```
|
||||
|
||||
Note: `${WASI_SDK_PATH}/share/wasi-sysroot` contains the WASI-specific
|
||||
includes/libraries/etc. The `--sysroot=...` option is not necessary if
|
||||
`WASI_SDK_PATH` is `/opt/wasi-sdk`. For troubleshooting, one can replace the
|
||||
`--sysroot` path with a manual build of [wasi-libc].
|
||||
|
||||
### Integrating with a CMake build system
|
||||
|
||||
Use a toolchain file to setup the *wasi-sdk* platform.
|
||||
|
||||
```
|
||||
$ cmake -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_PATH}/share/cmake/wasi-sdk.cmake ...
|
||||
```
|
||||
|
||||
or the *wasi-sdk-thread* platform
|
||||
|
||||
```
|
||||
$ cmake -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_PATH}/share/cmake/wasi-sdk-pthread.cmake ...
|
||||
```
|
||||
|
||||
## Notes for Autoconf
|
||||
|
||||
[Autoconf] 2.70 now [recognizes WASI].
|
||||
|
||||
[Autoconf]: https://www.gnu.org/software/autoconf/autoconf.html
|
||||
[recognizes WASI]: https://git.savannah.gnu.org/gitweb/?p=autoconf.git;a=blob;f=build-aux/config.sub;h=19c9553b1825cafb182115513bc628e0ee801bd0;hb=97fbc5c184acc6fa591ad094eae86917f03459fa#l1723
|
||||
|
||||
For convenience when building packages that aren't yet updated, updated
|
||||
config.sub and config.guess files are installed at `share/misc/config.*`
|
||||
in the install directory.
|
||||
|
||||
## Docker Image
|
||||
|
||||
We provide a [docker image] including WASI SDK that can be used for building
|
||||
projects without a separate installation of the SDK. Autotools, CMake, and Ninja
|
||||
are included in this image, and standard environment variables are set to use
|
||||
WASI SDK for building.
|
||||
|
||||
[docker image]: https://github.com/WebAssembly/wasi-sdk/pkgs/container/wasi-sdk
|
||||
|
||||
For example, this command can build a make-based project with the Docker
|
||||
image.
|
||||
|
||||
```
|
||||
docker run -v `pwd`:/src -w /src ghcr.io/webassembly/wasi-sdk make
|
||||
```
|
||||
|
||||
Take note of the [notable limitations](#notable-limitations) below when
|
||||
building projects, for example many projects will need threads support
|
||||
disabled in a configure step before building with WASI SDK.
|
||||
|
||||
## Notable Limitations
|
||||
|
||||
* C++ exceptions are disabled by default. For more information see
|
||||
[CppExceptions.md].
|
||||
* C `setjmp`/`longjmp` require some extra configuration to get working, see
|
||||
[SetjmpLongjmp.md].
|
||||
* Most targets do not support spawning a thread. Experimental support for
|
||||
spawning threads is available with the `wasm32-wasip1-threads` target which
|
||||
uses [wasi-threads]. Note that the `pthread_*` family of functions, as well as
|
||||
C++ threading primitives such as `<atomic>`, `<mutex>`, and `<thread>` are
|
||||
available on all targets. Defining a macro `_WASI_STRICT_PTHREAD` will make
|
||||
`pthread_create`, `pthread_detach`, `pthread_join`, `pthread_tryjoin_np`, and
|
||||
`pthread_timedjoin_np` fail with a compile time error when building for
|
||||
single-threaded targets.
|
||||
* Dynamic linking [is supported][dylink] but not as fully baked as static
|
||||
linking. There might be obscure bugs in some situations related to dynamic
|
||||
linking.
|
||||
* The WASIp1 targets do not support networking, but WASIp2/WASIp3 support
|
||||
networking.
|
||||
* 64-bit linear memories (a "wasm64" target) are not supported at this time.
|
||||
Supporting this will require resolving [WebAssembly/component-model#22] first
|
||||
at which point it will be possible to add a `wasm64-wasip2` target. There are
|
||||
no plans to add support for `wasm64-wasi{,-threads,p1,p1-threads}` at this
|
||||
time.
|
||||
|
||||
[threads]: https://github.com/WebAssembly/threads
|
||||
[wasi-threads]: https://github.com/WebAssembly/wasi-threads
|
||||
[dylink]: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
|
||||
[WebAssembly/component-model#22]: https://github.com/WebAssembly/component-model/issues/22
|
||||
@ -0,0 +1,43 @@
|
||||
# Release Process
|
||||
|
||||
We (maintainers) plan to release a new version of wasi-sdk every three months,
|
||||
coinciding with our monthly meeting to discuss latest issues and pull requests.
|
||||
This provides regularity to the release cadence, though we also reserve the
|
||||
right to publish at any intervening time if there is a pressing need (i.e., open
|
||||
an issue to discuss).
|
||||
|
||||
To publish a new version of `wasi-sdk` as a GitHub release:
|
||||
|
||||
1. Tag a commit with an annotated tag. Note that this must be an annotated tag,
|
||||
not a lightweight tag, so that `version.py` can use it for calculating the
|
||||
package version (use `git show wasi-sdk-...` to show other tag messages).
|
||||
Note that you may need to clear the repository cache to avoid problems with
|
||||
cached artifacts [^cache].
|
||||
|
||||
```shell script
|
||||
TAG=wasi-sdk-1
|
||||
git tag -a $TAG
|
||||
git push origin $TAG
|
||||
```
|
||||
|
||||
2. Wait for the CI build of the tag to finish. This will automatically publish
|
||||
a draft pre-release to [GitHub Releases](https://github.com/WebAssembly/wasi-sdk/releases).
|
||||
Release notes are auto-generated and should be reviewed for accuracy. Once
|
||||
everything looks good manually publish the release through the GitHub UI.
|
||||
|
||||
3. Remember to tag the wasi-libc repository with the new `$TAG` version.
|
||||
|
||||
```shell script
|
||||
git submodule status -- src/wasi-libc # grab $WASI_LIBC_COMMIT from the output
|
||||
cd $WASI_LIBC_REPO_DIR
|
||||
git tag $TAG $WASI_LIBC_COMMIT
|
||||
git push origin $TAG
|
||||
```
|
||||
|
||||
[^cache]: Here is an example of how to clear a cache with the GitHub CLI:
|
||||
|
||||
```shell script
|
||||
URL=/repos/WebAssembly/wasi-sdk/actions/caches
|
||||
gh api $URL -q '.actions_caches[].id' \
|
||||
| xargs -I {} gh api --method DELETE $URL/{}
|
||||
```
|
||||
@ -0,0 +1,117 @@
|
||||
# C setjmp/longjmp support
|
||||
|
||||
WASI-SDK provides basic setjmp/longjmp support.
|
||||
|
||||
Note that it's still under active development and may change in
|
||||
future versions. The tl;dr; version of this document is to pass these flags to
|
||||
the C compiler:
|
||||
|
||||
```
|
||||
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false
|
||||
```
|
||||
|
||||
## Implementation Primitives
|
||||
|
||||
Support for `setjmp` and `longjmp` is built on top of the
|
||||
[exception-handling](https://github.com/WebAssembly/exception-handling)
|
||||
WebAssembly proposal. This proposal is now [phase
|
||||
5](https://github.com/WebAssembly/proposals) and becoming part of the official
|
||||
specification. Note, however, that the exception-handling proposal has a long
|
||||
history and has a "legacy" version which shipped in browsers as well. This means
|
||||
that there are two different, but similar, sets of instructions that can be
|
||||
emitted to support `setjmp` and `longjmp`. Clang 20 and later (wasi-sdk-26 and
|
||||
later) is capable of emitting both at this time via `-mllvm
|
||||
-wasm-use-legacy-eh={false,true}` compiler flags.
|
||||
|
||||
Another important point is that exception-handling only provides structured
|
||||
control flow primitives for exceptions. This means it is not possible to purely
|
||||
define `setjmp` in C as otherwise it must be a function that returns twice. This
|
||||
means that support for `setjmp` and `longjmp` in WebAssembly relies on a
|
||||
compiler pass to transform invocations of `setjmp` at a compiler IR level. This
|
||||
means that the `setjmp` symbol is not defined in wasi-libc, for example, but
|
||||
instead primitives used to implement `setjmp`, in conjunction with LLVM, are
|
||||
found in wasi-libc.
|
||||
|
||||
## Build an application
|
||||
|
||||
To build an application using setjmp/longjmp, you need three sets of compiler
|
||||
flags:
|
||||
|
||||
1. `-mllvm -wasm-enable-sjlj`: Enable LLVM compiler pass which replaces calls to
|
||||
`setjmp` and `longjmp` with a different implementation that wasi-libc
|
||||
implements and hooks into.
|
||||
2. `-lsetjmp`: Link the setjmp library that wasi-libc provides which contains
|
||||
these hooks that LLVM uses.
|
||||
2. `-mllvm -wasm-use-legacy-eh=false`: Specify which version of the
|
||||
exception-handling instructions will be emitted. Note that if this is omitted
|
||||
it currently defaults to `true` meaning that the legacy instructions are
|
||||
emitted, not the standard instructions.
|
||||
|
||||
In short, these flags are required to use `setjmp`/`longjmp`
|
||||
|
||||
```
|
||||
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
This source code:
|
||||
|
||||
```c
|
||||
#include <assert.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static jmp_buf env;
|
||||
|
||||
static bool test_if_longjmp(void(*f)(void)) {
|
||||
if (setjmp(env))
|
||||
return true;
|
||||
f();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void do_not_longjmp() {
|
||||
}
|
||||
|
||||
static void do_longjmp() {
|
||||
longjmp(env, 1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
bool longjmped = test_if_longjmp(do_not_longjmp);
|
||||
assert(!longjmped);
|
||||
longjmped = test_if_longjmp(do_longjmp);
|
||||
assert(longjmped);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
can be compiled using the standard set of instructions as:
|
||||
|
||||
```shell
|
||||
clang -Os -o test.wasm test.c \
|
||||
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false
|
||||
```
|
||||
|
||||
and then `test.wasm` can be executed in a WebAssembly runtime supporting WASI.
|
||||
|
||||
You can also compile for the legacy exceptions proposal with:
|
||||
|
||||
```shell
|
||||
clang -Os -o test.wasm test.c \
|
||||
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=true
|
||||
```
|
||||
|
||||
and then `test.wasm` can be executed in a WebAssembly runtime supporting the
|
||||
legacy WebAssembly instructions.
|
||||
|
||||
Note that when compiling with LTO you'll need to pass `-mllvm` flags to the
|
||||
linker in addition to Clang itself, such as:
|
||||
|
||||
```shell
|
||||
clang -Os -flto=full -o test.wasm test.c \
|
||||
-mllvm -wasm-enable-sjlj -lsetjmp -mllvm -wasm-use-legacy-eh=false \
|
||||
-Wl,-mllvm,-wasm-enable-sjlj,-mllvm,-wasm-use-legacy-eh=false
|
||||
```
|
||||
@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build logic executed in CI. This is intentionally kept relatively minimal to
|
||||
# one day not live in bash to have a bash-less build on Windows. For now though
|
||||
# this will unconditionally build a toolchain and then optionally build a
|
||||
# sysroot. Builders which can't actually execute the toolchain they produce
|
||||
# skip the sysroot step below.
|
||||
|
||||
set -ex
|
||||
|
||||
# Optionally allow the first argument to this script to be the install
|
||||
# location.
|
||||
if [ "$1" = "" ]; then
|
||||
build_dir=`pwd`/build
|
||||
else
|
||||
build_dir="$1"
|
||||
fi
|
||||
|
||||
cmake -G Ninja -B $build_dir/toolchain -S . \
|
||||
-DWASI_SDK_BUILD_TOOLCHAIN=ON \
|
||||
-DCMAKE_BUILD_TYPE=MinSizeRel \
|
||||
"-DCMAKE_INSTALL_PREFIX=$build_dir/install" \
|
||||
$WASI_SDK_CI_TOOLCHAIN_CMAKE_ARGS \
|
||||
"-DLLVM_CMAKE_FLAGS=$WASI_SDK_CI_TOOLCHAIN_LLVM_CMAKE_ARGS"
|
||||
ninja -C $build_dir/toolchain install dist -v
|
||||
|
||||
mv $build_dir/toolchain/dist $build_dir/dist
|
||||
|
||||
if [ "$WASI_SDK_CI_SKIP_SYSROOT" = "1" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Use the just-built toolchain and its `CMAKE_TOOLCHAIN_FILE` to build a
|
||||
# sysroot.
|
||||
cmake -G Ninja -B $build_dir/sysroot -S . \
|
||||
"-DCMAKE_TOOLCHAIN_FILE=$build_dir/install/share/cmake/wasi-sdk.cmake" \
|
||||
-DCMAKE_C_COMPILER_WORKS=ON \
|
||||
-DCMAKE_CXX_COMPILER_WORKS=ON \
|
||||
-DWASI_SDK_INCLUDE_TESTS=ON \
|
||||
"-DCMAKE_INSTALL_PREFIX=$build_dir/install"
|
||||
ninja -C $build_dir/sysroot install dist -v
|
||||
|
||||
mv $build_dir/sysroot/dist/* $build_dir/dist
|
||||
|
||||
if [ "$WASI_SDK_CI_SKIP_TESTS" = "1" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run tests to ensure that the sysroot works.
|
||||
ctest --output-on-failure --parallel 10 --test-dir $build_dir/sysroot/tests \
|
||||
--timeout 60
|
||||
@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This is a helper script invoked from CI which will execute the `ci/build.sh`
|
||||
# script within a docker container. This contain is built using the Dockerfile located at `ci/docker/Dockerfile`
|
||||
# This container is then used to execute `ci/build.sh`.
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" = "" ]; then
|
||||
echo "Usage: $0 <image>"
|
||||
echo ""
|
||||
echo "example: $0 x86_64-linux"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
# Build the Docker image. Use an artifact-specific Dockerfile if one exists
|
||||
# (e.g. ci/docker/Dockerfile.riscv64-linux), otherwise use the default.
|
||||
dockerfile=ci/docker/Dockerfile
|
||||
if [ -f "ci/docker/Dockerfile.$1" ]; then
|
||||
dockerfile="ci/docker/Dockerfile.$1"
|
||||
fi
|
||||
docker build --tag wasi-sdk-builder --file $dockerfile ci/docker
|
||||
|
||||
# Perform the build in `/src`. The current directory is mounted read-write at
|
||||
# this location as well. To ensure that container-created files are reasonable
|
||||
# on the host as well the `--user` is passed to configure various permissions.
|
||||
args="--workdir /src --volume `pwd`:/src:Z"
|
||||
args="$args --user $(id -u):$(id -g)"
|
||||
|
||||
# Persist the ccache directory on the host to ensure repeated runs/debugging
|
||||
# of this container don't take forever. Also enables caching in CI.
|
||||
ccache_dir=$CCACHE_DIR
|
||||
if [ "$ccache_dir" = "" ]; then
|
||||
ccache_dir=$HOME/.ccache
|
||||
fi
|
||||
args="$args --volume $ccache_dir:/ccache:Z --env CCACHE_DIR=/ccache"
|
||||
|
||||
# Inherit some tools from the host into this container. This ensures that the
|
||||
# decision made on CI of what versions to use is the canonical source of truth
|
||||
# for these tools.
|
||||
args="$args --volume `rustc --print sysroot`:/rustc:ro"
|
||||
# Only mount wasmtime when the sysroot build (and its tests) will run.
|
||||
# When WASI_SDK_CI_SKIP_SYSROOT is set wasmtime is not needed.
|
||||
if [ -z "$WASI_SDK_CI_SKIP_SYSROOT" ]; then
|
||||
args="$args --volume $(dirname $(which wasmtime)):/wasmtime:ro"
|
||||
fi
|
||||
|
||||
# Pass through some env vars that `build.sh` reads
|
||||
args="$args --env WASI_SDK_CI_TOOLCHAIN_CMAKE_ARGS"
|
||||
args="$args --env WASI_SDK_CI_TOOLCHAIN_LLVM_CMAKE_ARGS"
|
||||
args="$args --env WASI_SDK_CI_SKIP_SYSROOT"
|
||||
args="$args --env WASI_SDK_CI_SKIP_TESTS"
|
||||
|
||||
# Before running `ci/build.sh` set up some rust/PATH related info to use what
|
||||
# was just mounted above, and then execute the build.
|
||||
docker run \
|
||||
$args \
|
||||
--tty \
|
||||
--init \
|
||||
wasi-sdk-builder \
|
||||
bash -c 'CARGO_HOME=/tmp/cargo-home PATH=$PATH:/rustc/bin:/wasmtime exec ci/build.sh'
|
||||
@ -0,0 +1,33 @@
|
||||
# Use a relatively old/stable distro here to maximize the supported platforms
|
||||
# and avoid depending on more recent version of, say, libc.
|
||||
# Here we choose AlmaLinux 8
|
||||
|
||||
FROM almalinux:8
|
||||
|
||||
# Various build tooling and such necessary to build LLVM and a wasi-sysroot
|
||||
RUN dnf install -y \
|
||||
curl \
|
||||
ca-certificates \
|
||||
clang \
|
||||
python3 \
|
||||
git \
|
||||
unzip \
|
||||
cmake \
|
||||
ncurses-devel
|
||||
|
||||
COPY ./install-ccache.sh .
|
||||
RUN ./install-ccache.sh
|
||||
|
||||
ENV PATH /opt/ccache/bin:$PATH
|
||||
|
||||
# AlmaLinux 8 doesn't seem to have ninja, so install it manually.
|
||||
RUN ARCH=$(uname -m) \
|
||||
&& if [ "$ARCH" = "aarch64" ]; then SUFFIX=-aarch64; fi \
|
||||
&& curl -sSL -o ninja.zip https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-linux${SUFFIX}.zip \
|
||||
&& unzip ninja.zip \
|
||||
&& rm *.zip \
|
||||
&& mv ninja /opt/ccache/bin
|
||||
|
||||
# Tell programs to cache in a location that both isn't a `--volume` mounted root
|
||||
# and isn't `/root` in the container as that won't be writable during the build.
|
||||
ENV XDG_CACHE_HOME /tmp/cache
|
||||
@ -0,0 +1,20 @@
|
||||
# Ubuntu 24.04 is used here (rather than AlmaLinux 8) because AlmaLinux 8
|
||||
# does not publish riscv64 images. This runs natively on a riscv64 runner.
|
||||
FROM ubuntu:24.04
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
ca-certificates \
|
||||
build-essential \
|
||||
clang \
|
||||
lld \
|
||||
python3 \
|
||||
git \
|
||||
unzip \
|
||||
cmake \
|
||||
ninja-build \
|
||||
ccache
|
||||
|
||||
# Tell programs to cache in a location that both isn't a `--volume` mounted root
|
||||
# and isn't `/root` in the container as that won't be writable during the build.
|
||||
ENV XDG_CACHE_HOME /tmp/cache
|
||||
@ -0,0 +1,10 @@
|
||||
# About
|
||||
|
||||
This folder contains the docker images that are used in CI to build the wasi-sdk
|
||||
release toolchains. Docker is used to intentionally use older Linux
|
||||
distributions to build the toolchain to have a more maximal set of glibc
|
||||
compatibility.
|
||||
|
||||
These images are intended to be used on an x86\_64 host. Images start from the
|
||||
`Dockerfile.common` file and then layer on target-specific
|
||||
toolchains/options/etc as necessary.
|
||||
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AlmaLinux 8, the container this script runs in, does not have ccache in its
|
||||
# package repositories. The ccache project publishes both x86_64 and aarch64
|
||||
# binaries, however. The x86_64 binaries for ccache are themselves built in
|
||||
# AlmaLinux 8 so they're compatible, but the aarch64 binaries are built in a
|
||||
# newer container and don't run on AlmaLinux 8.
|
||||
#
|
||||
# Thus this script downloads precompiled binaries for x86_64 but builds from
|
||||
# source on aarch64.
|
||||
|
||||
ARCH=$(uname -m)
|
||||
ver=4.12.1
|
||||
|
||||
if [ "x$ARCH" = "x86_64" ]; then
|
||||
curl -sSLO https://github.com/ccache/ccache/releases/download/v${ver}/ccache-${ver}-linux-${ARCH}.tar.xz
|
||||
tar -xf ccache-${ver}-linux-${ARCH}.tar.xz
|
||||
rm ccache-${ver}-linux-${ARCH}.tar.xz
|
||||
mv ccache-${ver}-linux-${ARCH} /opt/ccache/bin
|
||||
else
|
||||
curl -sSLO https://github.com/ccache/ccache/releases/download/v${ver}/ccache-${ver}.tar.xz
|
||||
tar -xf ccache-${ver}.tar.xz
|
||||
|
||||
cd ccache-${ver}
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. \
|
||||
-DCMAKE_INSTALL_PREFIX=/opt/ccache \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DHTTP_STORAGE_BACKEND=OFF \
|
||||
-DENABLE_TESTING=OFF \
|
||||
-DREDIS_STORAGE_BACKEND=OFF
|
||||
make -j$(nproc)
|
||||
make install
|
||||
fi
|
||||
@ -0,0 +1,83 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Helper script executed on CI once all builds have completed. This takes
|
||||
# `wasi-toolchain-*` artifacts and `wasi-sysroot-*` artifacts and merges
|
||||
# them together into a single `wasi-sdk-*` artifact. Toolchains which don't
|
||||
# have a sysroot that they themselves built use a sysroot from the x86_64-linux
|
||||
# toolchain.
|
||||
|
||||
set -ex
|
||||
|
||||
rm -rf dist
|
||||
mkdir dist
|
||||
version=$(./version.py)
|
||||
|
||||
make_deb() {
|
||||
build=$1
|
||||
dir=$2
|
||||
|
||||
if ! command -v dpkg-deb >/dev/null; then
|
||||
return
|
||||
fi
|
||||
|
||||
case $build in
|
||||
dist-x86_64-linux) deb_arch=amd64 ;;
|
||||
dist-arm64-linux) deb_arch=arm64 ;;
|
||||
*)
|
||||
echo "unknown build $build"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
mkdir dist/pkg
|
||||
mkdir dist/pkg/opt
|
||||
mkdir dist/pkg/DEBIAN
|
||||
sed s/VERSION/$version/ wasi-sdk.control | \
|
||||
sed s/ARCH/$deb_arch/ > dist/pkg/DEBIAN/control
|
||||
cp -R $dir dist/pkg/opt/wasi-sdk
|
||||
deb_name=$(echo $(basename $dir) | sed 's/.tar.gz//')
|
||||
(cd dist && dpkg-deb -b pkg $deb_name.deb)
|
||||
rm -rf dist/pkg
|
||||
}
|
||||
|
||||
for build in dist-*; do
|
||||
toolchain=`ls $build/wasi-toolchain-*`
|
||||
if [ -f $build/wasi-sysroot-* ]; then
|
||||
sysroot=`ls $build/wasi-sysroot-*`
|
||||
else
|
||||
sysroot=`ls dist-x86_64-linux/wasi-sysroot-*`
|
||||
fi
|
||||
if [ -f $build/libclang_rt* ]; then
|
||||
compiler_rt=`ls $build/libclang_rt*`
|
||||
else
|
||||
compiler_rt=`ls dist-x86_64-linux/libclang_rt*`
|
||||
fi
|
||||
|
||||
sdk_dir=`basename $toolchain | sed 's/.tar.gz//' | sed s/toolchain/sdk/`
|
||||
mkdir dist/$sdk_dir
|
||||
|
||||
# Start with the toolchain and then overlay the sysroot into
|
||||
# `share/wasi-sysroot`, the default sysroot.
|
||||
tar xf $toolchain -C dist/$sdk_dir --strip-components 1
|
||||
mkdir -p dist/$sdk_dir/share/wasi-sysroot
|
||||
tar xf $sysroot -C dist/$sdk_dir/share/wasi-sysroot --strip-components 1
|
||||
mv dist/$sdk_dir/share/wasi-sysroot/VERSION dist/$sdk_dir
|
||||
|
||||
# Setup the compiler-rt library for all targets.
|
||||
rtlibdir=$(dirname $(find dist/$sdk_dir/lib -name include))/lib
|
||||
mkdir -p $rtlibdir
|
||||
tar xf $compiler_rt -C $rtlibdir --strip-components 1
|
||||
|
||||
tar czf dist/$sdk_dir.tar.gz -C dist $sdk_dir
|
||||
|
||||
if echo $build | grep -q linux; then
|
||||
make_deb $build dist/$sdk_dir
|
||||
fi
|
||||
rm -rf dist/$sdk_dir
|
||||
done
|
||||
|
||||
# In addition to `wasi-sdk-*` also preserve artifacts for just the sysroot
|
||||
# and just compiler-rt.
|
||||
if [ -d dist-x86_64-linux ]; then
|
||||
cp dist-x86_64-linux/wasi-sysroot-* dist
|
||||
cp dist-x86_64-linux/libclang_rt* dist
|
||||
fi
|
||||
@ -0,0 +1 @@
|
||||
set(WASI 1)
|
||||
@ -0,0 +1,37 @@
|
||||
# Helper function to create tarballs for wasi-sdk.
|
||||
#
|
||||
# The `target` is the name of the CMake target to create for the creation of
|
||||
# this tarball. The `tarball` argument is where the final tarball will be
|
||||
# located. The name of the tarball is also used for the name of the root folder
|
||||
# in the tarball. The `dir` argument is is the directory that will get packaged
|
||||
# up within the tarball.
|
||||
function(wasi_sdk_add_tarball target tarball dir)
|
||||
cmake_path(GET tarball PARENT_PATH tarball_dir)
|
||||
|
||||
# Run STEM twice to chop of both `.gz` and `.tar` in `.tar.gz`
|
||||
cmake_path(GET tarball STEM LAST_ONLY tarball_stem)
|
||||
cmake_path(GET tarball_stem STEM LAST_ONLY tarball_stem)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES Windows)
|
||||
# Copy the contents of symlinks on Windows to avoid dealing with symlink
|
||||
set(copy_dir ${CMAKE_COMMAND} -E copy_directory ${dir} ${tarball_stem})
|
||||
else()
|
||||
# ... but on non-Windows copy symlinks themselves to cut down on
|
||||
# distribution size.
|
||||
set(copy_dir cp -R ${dir} ${tarball_stem})
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${tarball}
|
||||
# First copy the directory under a different name, the filestem of the
|
||||
# tarball.
|
||||
COMMAND ${copy_dir}
|
||||
# Next use CMake to create the tarball itself
|
||||
COMMAND ${CMAKE_COMMAND} -E tar cfz ${tarball} ${tarball_stem}
|
||||
# Finally delete the temporary directory created above.
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf ${tarball_stem}
|
||||
WORKING_DIRECTORY ${tarball_dir}
|
||||
COMMENT "Creating ${tarball}..."
|
||||
)
|
||||
add_custom_target(${target} DEPENDS ${tarball})
|
||||
endfunction()
|
||||
@ -0,0 +1,17 @@
|
||||
# Helper module to auto-enable ccache if detected.
|
||||
|
||||
find_program(CCACHE ccache)
|
||||
|
||||
option(WASI_SDK_DISABLE_CCACHE "Force disable ccache even if it's found" OFF)
|
||||
|
||||
if(NOT CMAKE_C_COMPILER_LAUNCHER)
|
||||
if(NOT WASI_SDK_DISABLE_CCACHE)
|
||||
if(CCACHE)
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ccache)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
|
||||
message(STATUS "Auto-enabling ccache")
|
||||
else()
|
||||
message(STATUS "Failed to auto-enable ccache, not found on system")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@ -0,0 +1,416 @@
|
||||
# Build logic for building a sysroot for wasi-sdk which includes compiler-rt,
|
||||
# wasi-libc, libcxx, and libcxxabi.
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_C_COMPILER_ID MATCHES Clang)
|
||||
message(FATAL_ERROR "C compiler ${CMAKE_C_COMPILER} is not `Clang`, it is ${CMAKE_C_COMPILER_ID}")
|
||||
endif()
|
||||
|
||||
set(minimum_clang_required 18.0.0)
|
||||
|
||||
if(CMAKE_C_COMPILER_VERSION VERSION_LESS ${minimum_clang_required})
|
||||
message(FATAL_ERROR "compiler version ${CMAKE_C_COMPILER_VERSION} is less than the required version ${minimum_clang_required}")
|
||||
endif()
|
||||
|
||||
message(STATUS "Found executable for `nm`: ${CMAKE_NM}")
|
||||
message(STATUS "Found executable for `ar`: ${CMAKE_AR}")
|
||||
|
||||
find_program(MAKE make REQUIRED)
|
||||
|
||||
option(WASI_SDK_DEBUG_PREFIX_MAP "Pass `-fdebug-prefix-map` for built artifacts" ON)
|
||||
option(WASI_SDK_INCLUDE_TESTS "Whether or not to build tests by default" OFF)
|
||||
option(WASI_SDK_INSTALL_TO_CLANG_RESOURCE_DIR "Whether or not to modify the compiler's resource directory" OFF)
|
||||
option(WASI_SDK_LTO "Whether or not to build LTO assets" ON)
|
||||
option(WASI_SDK_EXCEPTIONS "Whether or not C++ exceptions are enabled" OFF)
|
||||
set(WASI_SDK_CPU_CFLAGS "-mcpu=lime1" CACHE STRING "CFLAGS to specify wasm features to enable")
|
||||
|
||||
set(wasi_tmp_install ${CMAKE_CURRENT_BINARY_DIR}/install)
|
||||
set(wasi_sysroot ${wasi_tmp_install}/share/wasi-sysroot)
|
||||
set(wasi_resource_dir ${wasi_tmp_install}/wasi-resource-dir)
|
||||
|
||||
if(WASI_SDK_DEBUG_PREFIX_MAP)
|
||||
add_compile_options(
|
||||
-fdebug-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=wasisdk://v${wasi_sdk_version})
|
||||
endif()
|
||||
|
||||
# Default arguments for builds of cmake projects (mostly LLVM-based) to forward
|
||||
# along much of our own configuration into these projects.
|
||||
set(default_cmake_args
|
||||
-DCMAKE_SYSTEM_NAME=WASI
|
||||
-DCMAKE_SYSTEM_VERSION=1
|
||||
-DCMAKE_SYSTEM_PROCESSOR=wasm32
|
||||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
-DCMAKE_AR=${CMAKE_AR}
|
||||
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_C_COMPILER_WORKS=ON
|
||||
-DCMAKE_CXX_COMPILER_WORKS=ON
|
||||
-DCMAKE_SYSROOT=${wasi_sysroot}
|
||||
-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/cmake
|
||||
# CMake detects this based on `CMAKE_C_COMPILER` alone and when that compiler
|
||||
# is just a bare "clang" installation then it can mistakenly deduce that this
|
||||
# feature is supported when it's not actually supported for WASI targets.
|
||||
# Currently `wasm-ld` does not support the linker flag for this.
|
||||
-DCMAKE_C_LINKER_DEPFILE_SUPPORTED=OFF
|
||||
-DCMAKE_CXX_LINKER_DEPFILE_SUPPORTED=OFF)
|
||||
|
||||
if(CMAKE_C_COMPILER_LAUNCHER)
|
||||
list(APPEND default_cmake_args -DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER})
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_LAUNCHER)
|
||||
list(APPEND default_cmake_args -DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER})
|
||||
endif()
|
||||
|
||||
# =============================================================================
|
||||
# compiler-rt build logic
|
||||
# =============================================================================
|
||||
|
||||
add_custom_target(compiler-rt-build)
|
||||
function(define_compiler_rt target)
|
||||
ExternalProject_Add(compiler-rt-build-${target}
|
||||
SOURCE_DIR "${llvm_proj_dir}/compiler-rt"
|
||||
CMAKE_ARGS
|
||||
${default_cmake_args}
|
||||
-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON
|
||||
-DCOMPILER_RT_BAREMETAL_BUILD=ON
|
||||
-DCOMPILER_RT_BUILD_XRAY=OFF
|
||||
-DCOMPILER_RT_INCLUDE_TESTS=OFF
|
||||
-DCOMPILER_RT_HAS_FPIC_FLAG=OFF
|
||||
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON
|
||||
-DCOMPILER_RT_BUILD_SANITIZERS=OFF
|
||||
-DCOMPILER_RT_BUILD_XRAY=OFF
|
||||
-DCOMPILER_RT_BUILD_LIBFUZZER=OFF
|
||||
-DCOMPILER_RT_BUILD_PROFILE=OFF
|
||||
-DCOMPILER_RT_BUILD_CTX_PROFILE=OFF
|
||||
-DCOMPILER_RT_BUILD_MEMPROF=OFF
|
||||
-DCOMPILER_RT_BUILD_ORC=OFF
|
||||
-DCOMPILER_RT_BUILD_GWP_ASAN=OFF
|
||||
-DCMAKE_C_COMPILER_TARGET=${target}
|
||||
-DCMAKE_C_FLAGS=${WASI_SDK_CPU_CFLAGS}
|
||||
-DCMAKE_CXX_FLAGS=${WASI_SDK_CPU_CFLAGS}
|
||||
-DCMAKE_ASM_FLAGS=${WASI_SDK_CPU_CFLAGS}
|
||||
-DCMAKE_INSTALL_PREFIX=${wasi_resource_dir}
|
||||
EXCLUDE_FROM_ALL ON
|
||||
USES_TERMINAL_CONFIGURE ON
|
||||
USES_TERMINAL_BUILD ON
|
||||
USES_TERMINAL_INSTALL ON
|
||||
)
|
||||
add_dependencies(compiler-rt-build compiler-rt-build-${target})
|
||||
endfunction()
|
||||
|
||||
# The `compiler-rt` for `wasm32-wasip1` will be reused for `wasm32-wasip2` and
|
||||
# `wasm32-wasi`. The version for `wasm32-wasip1-threads` will be reused for
|
||||
# `wasm32-wasi-threads`. Different builds are needed for different codegen flags
|
||||
# and such across the threaded/not target.
|
||||
define_compiler_rt(wasm32-wasip1)
|
||||
define_compiler_rt(wasm32-wasip1-threads)
|
||||
|
||||
# If a p3 target is requested, also build compiler-rt for that target. WASIp3
|
||||
# will eventually have a different ABI than wasm32-wasip2, so this separate
|
||||
# build is needed.
|
||||
if(WASI_SDK_TARGETS MATCHES p3)
|
||||
define_compiler_rt(wasm32-wasip3)
|
||||
endif()
|
||||
|
||||
# In addition to the default installation of `compiler-rt` itself also copy
|
||||
# around some headers and make copies of the `wasi` directory as `wasip1` and
|
||||
# `wasip2` and `wasip3`
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-resource-dir
|
||||
OUTPUT_VARIABLE clang_resource_dir
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
add_custom_target(compiler-rt-post-build
|
||||
# The `${wasi_resource_dir}` folder is going to get used as `-resource-dir`
|
||||
# for future compiles. Copy the host compiler's own headers into this
|
||||
# directory to ensure that all host-defined headers all work as well.
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${clang_resource_dir}/include ${wasi_resource_dir}/include
|
||||
|
||||
# Copy the `lib/wasm32-unknown-wasip1` folder to `lib/wasm32-unknown-wasi{,p2}` to ensure that those
|
||||
# OS-strings also work for looking up the compiler-rt.a file.
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${wasi_resource_dir}/lib/wasm32-unknown-wasip1 ${wasi_resource_dir}/lib/wasm32-unknown-wasi
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${wasi_resource_dir}/lib/wasm32-unknown-wasip1 ${wasi_resource_dir}/lib/wasm32-unknown-wasip2
|
||||
# Copy the `lib/wasm32-unknown-wasip1-threads` folder to `lib/wasm32-unknown-wasi-threads`
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${wasi_resource_dir}/lib/wasm32-unknown-wasip1-threads ${wasi_resource_dir}/lib/wasm32-unknown-wasi-threads
|
||||
|
||||
COMMENT "finalizing compiler-rt installation"
|
||||
)
|
||||
add_dependencies(compiler-rt-post-build compiler-rt-build)
|
||||
|
||||
add_custom_target(compiler-rt DEPENDS compiler-rt-build compiler-rt-post-build)
|
||||
|
||||
# =============================================================================
|
||||
# wasi-libc build logic
|
||||
# =============================================================================
|
||||
|
||||
function(define_wasi_libc_sub target target_suffix lto)
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPER)
|
||||
get_property(directory_cflags DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_OPTIONS)
|
||||
set(extra_cflags_list "${WASI_SDK_CPU_CFLAGS} ${CMAKE_C_FLAGS} ${directory_cflags}")
|
||||
|
||||
if(${target} MATCHES "p[23]")
|
||||
# Always enable `-fPIC` for the `wasm32-wasip2` and `wasm32-wasip3` targets.
|
||||
# This makes `libc.a` more flexible and usable in dynamic linking situations.
|
||||
list(APPEND extra_cflags_list -fPIC)
|
||||
endif()
|
||||
|
||||
# The `wasm32-wasi` target is deprecated in clang, so ignore the deprecation
|
||||
# warnings for now.
|
||||
if(${target} STREQUAL wasm32-wasi OR ${target} STREQUAL wasm32-wasi-threads)
|
||||
list(APPEND extra_cflags_list -Wno-deprecated)
|
||||
endif()
|
||||
|
||||
list(JOIN extra_cflags_list " " extra_cflags)
|
||||
|
||||
if(${target} MATCHES threads)
|
||||
set(libcompiler_rt_a ${wasi_resource_dir}/lib/wasm32-unknown-wasip1-threads/libclang_rt.builtins.a)
|
||||
else()
|
||||
set(libcompiler_rt_a ${wasi_resource_dir}/lib/wasm32-unknown-wasip1/libclang_rt.builtins.a)
|
||||
endif()
|
||||
|
||||
set(extra_cmake_args)
|
||||
|
||||
# Configure LTO in wasi libc if it's enabled. Be sure to disable shared
|
||||
# libraries as well since that's not currently supported.
|
||||
if (lto)
|
||||
list(APPEND extra_cmake_args -DLTO=full -DBUILD_SHARED=OFF)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(wasi-libc-${target}${target_suffix}-build
|
||||
SOURCE_DIR ${wasi_libc}
|
||||
CMAKE_ARGS
|
||||
${default_cmake_args}
|
||||
${extra_cmake_args}
|
||||
-DTARGET_TRIPLE=${target}
|
||||
-DCMAKE_INSTALL_PREFIX=${wasi_sysroot}
|
||||
-DCMAKE_C_FLAGS=${extra_cflags}
|
||||
-DCMAKE_ASM_FLAGS=${extra_cflags}
|
||||
-DBUILTINS_LIB=${libcompiler_rt_a}
|
||||
-DUSE_WASM_COMPONENT_LD=OFF
|
||||
-DWASI_SDK_VERSION=${wasi_sdk_version}
|
||||
DEPENDS compiler-rt
|
||||
EXCLUDE_FROM_ALL ON
|
||||
USES_TERMINAL_CONFIGURE ON
|
||||
USES_TERMINAL_BUILD ON
|
||||
USES_TERMINAL_INSTALL ON
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(define_wasi_libc target)
|
||||
define_wasi_libc_sub (${target} "" OFF)
|
||||
if(WASI_SDK_LTO)
|
||||
define_wasi_libc_sub (${target} "-lto" ON)
|
||||
endif()
|
||||
|
||||
add_custom_target(wasi-libc-${target}
|
||||
DEPENDS wasi-libc-${target}-build $<$<BOOL:${WASI_SDK_LTO}>:wasi-libc-${target}-lto-build>)
|
||||
endfunction()
|
||||
|
||||
foreach(target IN LISTS WASI_SDK_TARGETS)
|
||||
define_wasi_libc(${target})
|
||||
endforeach()
|
||||
|
||||
# =============================================================================
|
||||
# libcxx build logic
|
||||
# =============================================================================
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE llvm_version
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
function(define_libcxx_sub target target_suffix extra_target_flags extra_libdir_suffix)
|
||||
if(${target} MATCHES threads)
|
||||
set(pic OFF)
|
||||
set(target_flags -pthread)
|
||||
else()
|
||||
set(pic ON)
|
||||
set(target_flags "")
|
||||
endif()
|
||||
if(${target_suffix} MATCHES lto)
|
||||
set(pic OFF)
|
||||
endif()
|
||||
list(APPEND target_flags ${extra_target_flags})
|
||||
|
||||
set(runtimes "libcxx;libcxxabi")
|
||||
|
||||
get_property(dir_compile_opts DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_OPTIONS)
|
||||
get_property(dir_link_opts DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY LINK_OPTIONS)
|
||||
set(extra_flags
|
||||
${WASI_SDK_CPU_CFLAGS}
|
||||
${target_flags}
|
||||
--target=${target}
|
||||
${dir_compile_opts}
|
||||
${dir_link_opts}
|
||||
--sysroot ${wasi_sysroot}
|
||||
-resource-dir ${wasi_resource_dir})
|
||||
|
||||
if (WASI_SDK_EXCEPTIONS)
|
||||
# TODO: lots of builds fail with shared libraries and `-fPIC`. Looks like
|
||||
# things are maybe changing in llvm/llvm-project#159143 but otherwise I'm at
|
||||
# least not really sure what the state of shared libraries and exceptions
|
||||
# are. For now shared libraries are disabled and supporting them is left for
|
||||
# a future endeavor.
|
||||
set(pic OFF)
|
||||
set(runtimes "libunwind;${runtimes}")
|
||||
list(APPEND extra_flags -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false)
|
||||
endif()
|
||||
|
||||
# The `wasm32-wasi` target is deprecated in clang, so ignore the deprecation
|
||||
# warnings for now.
|
||||
if(${target} STREQUAL wasm32-wasi OR ${target} STREQUAL wasm32-wasi-threads)
|
||||
list(APPEND extra_flags -Wno-deprecated)
|
||||
endif()
|
||||
|
||||
set(extra_cflags_list ${CMAKE_C_FLAGS} ${extra_flags})
|
||||
list(JOIN extra_cflags_list " " extra_cflags)
|
||||
set(extra_cxxflags_list ${CMAKE_CXX_FLAGS} ${extra_flags})
|
||||
list(JOIN extra_cxxflags_list " " extra_cxxflags)
|
||||
|
||||
ExternalProject_Add(libcxx-${target}${target_suffix}-build
|
||||
SOURCE_DIR ${llvm_proj_dir}/runtimes
|
||||
CMAKE_ARGS
|
||||
${default_cmake_args}
|
||||
# Ensure headers are installed in a target-specific path instead of a
|
||||
# target-generic path.
|
||||
-DCMAKE_INSTALL_INCLUDEDIR=${wasi_sysroot}/include/${target}
|
||||
-DCMAKE_STAGING_PREFIX=${wasi_sysroot}
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=${pic}
|
||||
-DLIBCXX_ENABLE_THREADS:BOOL=ON
|
||||
-DLIBCXX_HAS_PTHREAD_API:BOOL=ON
|
||||
-DLIBCXX_HAS_EXTERNAL_THREAD_API:BOOL=OFF
|
||||
-DLIBCXX_HAS_WIN32_THREAD_API:BOOL=OFF
|
||||
-DLLVM_COMPILER_CHECKED=ON
|
||||
-DLIBCXX_ENABLE_SHARED:BOOL=${pic}
|
||||
-DLIBCXX_ENABLE_EXCEPTIONS:BOOL=${WASI_SDK_EXCEPTIONS}
|
||||
-DLIBCXX_ENABLE_FILESYSTEM:BOOL=ON
|
||||
-DLIBCXX_ENABLE_ABI_LINKER_SCRIPT:BOOL=OFF
|
||||
-DLIBCXX_CXX_ABI=libcxxabi
|
||||
-DLIBCXX_HAS_MUSL_LIBC:BOOL=OFF
|
||||
-DLIBCXX_ABI_VERSION=2
|
||||
-DLIBCXXABI_ENABLE_EXCEPTIONS:BOOL=${WASI_SDK_EXCEPTIONS}
|
||||
-DLIBCXXABI_ENABLE_SHARED:BOOL=${pic}
|
||||
-DLIBCXXABI_SILENT_TERMINATE:BOOL=ON
|
||||
-DLIBCXXABI_ENABLE_THREADS:BOOL=ON
|
||||
-DLIBCXXABI_HAS_PTHREAD_API:BOOL=ON
|
||||
-DLIBCXXABI_HAS_EXTERNAL_THREAD_API:BOOL=OFF
|
||||
-DLIBCXXABI_HAS_WIN32_THREAD_API:BOOL=OFF
|
||||
-DLIBCXXABI_USE_LLVM_UNWINDER:BOOL=${WASI_SDK_EXCEPTIONS}
|
||||
-DLIBUNWIND_ENABLE_SHARED:BOOL=${pic}
|
||||
-DLIBUNWIND_ENABLE_THREADS:BOOL=ON
|
||||
-DLIBUNWIND_USE_COMPILER_RT:BOOL=ON
|
||||
-DLIBUNWIND_INCLUDE_TESTS:BOOL=OFF
|
||||
-DUNIX:BOOL=ON
|
||||
-DCMAKE_C_FLAGS=${extra_cflags}
|
||||
-DCMAKE_ASM_FLAGS=${extra_cflags}
|
||||
-DCMAKE_CXX_FLAGS=${extra_cxxflags}
|
||||
-DLIBCXX_LIBDIR_SUFFIX=/${target}${extra_libdir_suffix}
|
||||
-DLIBCXXABI_LIBDIR_SUFFIX=/${target}${extra_libdir_suffix}
|
||||
-DLIBUNWIND_LIBDIR_SUFFIX=/${target}${extra_libdir_suffix}
|
||||
-DLIBCXX_INCLUDE_TESTS=OFF
|
||||
-DLIBCXX_INCLUDE_BENCHMARKS=OFF
|
||||
|
||||
# See https://www.scivision.dev/cmake-externalproject-list-arguments/ for
|
||||
# why this is in `CMAKE_CACHE_ARGS` instead of above
|
||||
CMAKE_CACHE_ARGS
|
||||
-DLLVM_ENABLE_RUNTIMES:STRING=${runtimes}
|
||||
DEPENDS
|
||||
wasi-libc-${target}
|
||||
compiler-rt
|
||||
EXCLUDE_FROM_ALL ON
|
||||
USES_TERMINAL_CONFIGURE ON
|
||||
USES_TERMINAL_BUILD ON
|
||||
USES_TERMINAL_INSTALL ON
|
||||
PATCH_COMMAND
|
||||
${CMAKE_COMMAND} -E chdir .. bash -c
|
||||
"git apply ${CMAKE_SOURCE_DIR}/src/llvm-pr-168449.patch || git apply ${CMAKE_SOURCE_DIR}/src/llvm-pr-168449.patch -R --check"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E chdir .. bash -c
|
||||
"git apply ${CMAKE_SOURCE_DIR}/src/llvm-pr-186054.patch || git apply ${CMAKE_SOURCE_DIR}/src/llvm-pr-186054.patch -R --check"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(define_libcxx target)
|
||||
define_libcxx_sub(${target} "" "" "")
|
||||
if(WASI_SDK_LTO)
|
||||
# Note: clang knows this /llvm-lto/${llvm_version} convention.
|
||||
# https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/clang/lib/Driver/ToolChains/WebAssembly.cpp#L204-L210
|
||||
define_libcxx_sub(${target} "-lto" "-flto=full" "/llvm-lto/${llvm_version}")
|
||||
endif()
|
||||
|
||||
# As of this writing, `clang++` will ignore the target-specific include dirs
|
||||
# unless this one also exists:
|
||||
add_custom_target(libcxx-${target}-extra-dir
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${wasi_sysroot}/include/c++/v1
|
||||
COMMENT "creating libcxx-specific header file folder")
|
||||
add_custom_target(libcxx-${target}
|
||||
DEPENDS libcxx-${target}-build $<$<BOOL:${WASI_SDK_LTO}>:libcxx-${target}-lto-build> libcxx-${target}-extra-dir)
|
||||
endfunction()
|
||||
|
||||
foreach(target IN LISTS WASI_SDK_TARGETS)
|
||||
define_libcxx(${target})
|
||||
endforeach()
|
||||
|
||||
# =============================================================================
|
||||
# misc build logic
|
||||
# =============================================================================
|
||||
|
||||
install(DIRECTORY ${wasi_tmp_install}/share
|
||||
USE_SOURCE_PERMISSIONS
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
if(WASI_SDK_INSTALL_TO_CLANG_RESOURCE_DIR)
|
||||
install(DIRECTORY ${wasi_resource_dir}/lib
|
||||
USE_SOURCE_PERMISSIONS
|
||||
DESTINATION ${clang_resource_dir})
|
||||
else()
|
||||
install(DIRECTORY ${wasi_resource_dir}/lib
|
||||
USE_SOURCE_PERMISSIONS
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/clang-resource-dir)
|
||||
endif()
|
||||
|
||||
# Add a top-level `build` target as well as `build-$target` targets.
|
||||
add_custom_target(build ALL)
|
||||
foreach(target IN LISTS WASI_SDK_TARGETS)
|
||||
add_custom_target(build-${target})
|
||||
add_dependencies(build-${target} libcxx-${target} wasi-libc-${target} compiler-rt)
|
||||
add_dependencies(build build-${target})
|
||||
endforeach()
|
||||
|
||||
# Install a `VERSION` file in the output prefix with a dump of version
|
||||
# information.
|
||||
execute_process(
|
||||
COMMAND ${PYTHON} ${version_script} dump
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE version_dump)
|
||||
set(version_file_tmp ${wasi_sysroot}/VERSION)
|
||||
file(GENERATE OUTPUT ${version_file_tmp} CONTENT ${version_dump})
|
||||
add_custom_target(version-file DEPENDS ${version_file_tmp})
|
||||
add_dependencies(build version-file)
|
||||
|
||||
if(WASI_SDK_INCLUDE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
include(wasi-sdk-dist)
|
||||
|
||||
set(dist_dir ${CMAKE_CURRENT_BINARY_DIR}/dist)
|
||||
|
||||
# Tarball with just `compiler-rt` libraries within it
|
||||
wasi_sdk_add_tarball(dist-compiler-rt
|
||||
${dist_dir}/libclang_rt-${wasi_sdk_version}.tar.gz
|
||||
${wasi_resource_dir}/lib)
|
||||
add_dependencies(dist-compiler-rt compiler-rt)
|
||||
|
||||
# Tarball with the whole sysroot
|
||||
wasi_sdk_add_tarball(dist-sysroot
|
||||
${dist_dir}/wasi-sysroot-${wasi_sdk_version}.tar.gz
|
||||
${wasi_sysroot})
|
||||
add_dependencies(dist-sysroot build)
|
||||
|
||||
add_custom_target(dist DEPENDS dist-compiler-rt dist-sysroot)
|
||||
@ -0,0 +1,337 @@
|
||||
# Build logic and support for building a Clang toolchain that can target
|
||||
# WebAssembly and build a WASI sysroot.
|
||||
|
||||
set(LLVM_CMAKE_FLAGS "" CACHE STRING "Extra cmake flags to pass to LLVM's build")
|
||||
set(RUST_TARGET "" CACHE STRING "Target to build Rust code for, if not the host")
|
||||
set(WASI_SDK_ARTIFACT "" CACHE STRING "Name of the wasi-sdk artifact being produced")
|
||||
|
||||
option(WASI_SDK_LLDB "Include a build of LLDB" ON)
|
||||
|
||||
set(LIBEDIT_DEFAULT ON)
|
||||
# I don't want to deal with running a `./configure` script on Windows, disable
|
||||
# it by default.
|
||||
if(WIN32)
|
||||
set(LIBEDIT_DEFAULT OFF)
|
||||
endif()
|
||||
# I don't know how to resolve build failures when building libedit for x86_64
|
||||
# from arm64 on macos, so disable it for now.
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64" AND LLVM_CMAKE_FLAGS MATCHES "x86_64")
|
||||
set(LIBEDIT_DEFAULT OFF)
|
||||
endif()
|
||||
option(WASI_SDK_LIBEDIT "Whether or not to build libedit for LLDB" ${LIBEDIT_DEFAULT})
|
||||
option(WASI_SDK_LIBXML2 "Whether or not to build libxml2 for LLDB" ON)
|
||||
|
||||
string(REGEX REPLACE "[ ]+" ";" llvm_cmake_flags_list "${LLVM_CMAKE_FLAGS}")
|
||||
|
||||
set(wasi_tmp_install ${CMAKE_CURRENT_BINARY_DIR}/install)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE MinSizeRel)
|
||||
endif()
|
||||
|
||||
set(default_cmake_args
|
||||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
-DCMAKE_AR=${CMAKE_AR}
|
||||
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
|
||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
||||
-DCMAKE_INSTALL_PREFIX=${wasi_tmp_install})
|
||||
|
||||
if(CMAKE_C_COMPILER_LAUNCHER)
|
||||
list(APPEND default_cmake_args -DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER})
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_LAUNCHER)
|
||||
list(APPEND default_cmake_args -DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER})
|
||||
endif()
|
||||
|
||||
set(links_to_create clang-cl clang-cpp clang++)
|
||||
foreach(target IN LISTS WASI_SDK_TARGETS)
|
||||
list(APPEND links_to_create ${target}-clang)
|
||||
list(APPEND links_to_create ${target}-clang++)
|
||||
endforeach()
|
||||
|
||||
set(projects "lld;clang;clang-tools-extra")
|
||||
|
||||
set(tools
|
||||
clang
|
||||
clang-format
|
||||
clang-tidy
|
||||
clang-apply-replacements
|
||||
lld
|
||||
llvm-addr2line
|
||||
llvm-mc
|
||||
llvm-ranlib
|
||||
llvm-strip
|
||||
llvm-dwarfdump
|
||||
llvm-dwp
|
||||
clang-resource-headers
|
||||
ar
|
||||
ranlib
|
||||
strip
|
||||
nm
|
||||
size
|
||||
strings
|
||||
objdump
|
||||
objcopy
|
||||
c++filt
|
||||
llvm-config
|
||||
libclang)
|
||||
|
||||
# By default link LLVM dynamically to all the various tools. This greatly
|
||||
# reduces the binary size of all the tools through a shared library rather than
|
||||
# statically linking LLVM to each individual tool. This requires a few other
|
||||
# install targets as well to ensure the appropriate libraries are all installed.
|
||||
#
|
||||
# Also note that the `-wasi-sdk` version suffix is intended to help prevent
|
||||
# these dynamic libraries from clashing with other system libraries in case the
|
||||
# `lib` dir gets put on `LD_LIBRARY_PATH` or similar.
|
||||
if(NOT WIN32)
|
||||
list(APPEND default_cmake_args -DLLVM_LINK_LLVM_DYLIB=ON -DLLVM_VERSION_SUFFIX=-wasi-sdk)
|
||||
list(APPEND tools LLVM clang-cpp)
|
||||
endif()
|
||||
|
||||
# Configure/add LLDB if requested.
|
||||
#
|
||||
# Note that LLDB depends on `libedit` which is more-or-less required to get a
|
||||
# reasonable command-line experience, so this is built custom here to ensure
|
||||
# that it's available for LLDB.
|
||||
if(WASI_SDK_LLDB)
|
||||
list(APPEND projects lldb)
|
||||
list(APPEND tools lldb liblldb)
|
||||
list(APPEND default_cmake_args
|
||||
-DLLDB_INCLUDE_TESTS=OFF
|
||||
-DLLDB_INCLUDE_UNITTESTS=OFF
|
||||
-DLLDB_ENABLE_SWIG=OFF
|
||||
-DLLDB_ENABLE_CURSES=OFF
|
||||
-DLLDB_ENABLE_LZMA=OFF
|
||||
-DLLDB_ENABLE_LUA=OFF
|
||||
-DLLDB_ENABLE_PYTHON=OFF
|
||||
-DLLDB_ENABLE_FBSDVMCORE=OFF
|
||||
-DLLDB_ENABLE_LINUXPTY=OFF
|
||||
)
|
||||
|
||||
set(extra_configure_commands)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
set(extra_configure_commands
|
||||
# By default it looks like `libedit` tries to link to `libncurses.so` and
|
||||
# such on Linux. This is problematic as systems may not have that
|
||||
# installed. Turns out though at least for AlmaLinux [1] they just edit
|
||||
# makefile and pkg-config info and it works out. Who knew! I thought
|
||||
# one of the millions of lines in `./configure` would take care of this
|
||||
# but apparently we're still resorting to editing things raw...
|
||||
#
|
||||
# [1]: https://git.almalinux.org/rpms/libedit/src/commit/3f0893c4cd8e0cbb2f556d2fad48326c9c037a6c/SPECS/libedit.spec#L44-L48
|
||||
COMMAND sed -i "s/lncurses/ltinfo/" src/Makefile
|
||||
COMMAND sed -i "s/ -lncurses//" libedit.pc
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WASI_SDK_LIBEDIT)
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(nproc)
|
||||
find_program(MAKE_EXECUTABLE make REQUIRED)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
|
||||
set(libedit_ldflags -Wl,-install_name,@rpath/libedit.0.dylib)
|
||||
endif()
|
||||
ExternalProject_Add(libedit
|
||||
URL https://thrysoee.dk/editline/libedit-20251016-3.1.tar.gz
|
||||
URL_HASH SHA256=21362b00653bbfc1c71f71a7578da66b5b5203559d43134d2dd7719e313ce041
|
||||
|
||||
# Without this the build system tries to find and use `aclocal-1.18` where
|
||||
# with this it doesn't so turn this on.
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP ON
|
||||
|
||||
CONFIGURE_COMMAND
|
||||
<SOURCE_DIR>/configure
|
||||
--prefix=${wasi_tmp_install}
|
||||
--enable-pic
|
||||
--disable-examples
|
||||
--disable-static
|
||||
--disable-silent-rules
|
||||
CC=${CMAKE_C_COMPILER}
|
||||
LDFLAGS=${libedit_ldflags}
|
||||
${extra_configure_commands}
|
||||
BUILD_COMMAND
|
||||
${MAKE_EXECUTABLE} -j${nproc}
|
||||
|
||||
USES_TERMINAL_CONFIGURE ON
|
||||
USES_TERMINAL_BUILD ON
|
||||
USES_TERMINAL_INSTALL ON
|
||||
)
|
||||
list(APPEND default_cmake_args
|
||||
-DLLDB_ENABLE_LIBEDIT=ON
|
||||
-DLibEdit_ROOT=${wasi_tmp_install}
|
||||
)
|
||||
else()
|
||||
list(APPEND default_cmake_args -DLLDB_ENABLE_LIBEDIT=OFF)
|
||||
add_custom_target(libedit)
|
||||
endif()
|
||||
|
||||
set(libxml_cmake_args)
|
||||
|
||||
# Windows doesn't have iconv by default, so disable it for now.
|
||||
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
list(APPEND libxml_cmake_args -DLIBXML2_WITH_ICONV=OFF)
|
||||
endif()
|
||||
|
||||
# Our AlmaLinux:8 container ends up using `lib64` instead of `lib` by default
|
||||
# which doesn't match LLVM, so specifically use the same dir as LLVM.
|
||||
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
||||
list(APPEND libxml_cmake_args -DCMAKE_INSTALL_LIBDIR=lib)
|
||||
endif()
|
||||
|
||||
if (WASI_SDK_LIBXML2)
|
||||
ExternalProject_Add(libxml2
|
||||
URL https://download.gnome.org/sources/libxml2/2.15/libxml2-2.15.2.tar.xz
|
||||
URL_HASH SHA256=c8b9bc81f8b590c33af8cc6c336dbff2f53409973588a351c95f1c621b13d09d
|
||||
|
||||
CMAKE_ARGS
|
||||
${default_cmake_args}
|
||||
-DLIBXML2_WITH_PROGRAMS=OFF
|
||||
-DLIBXML2_WITH_DEBUG=OFF
|
||||
-DLIBXML2_WITH_DOCS=OFF
|
||||
-DLIBXML2_WITH_TESTS=OFF
|
||||
${libxml_cmake_args}
|
||||
${llvm_cmake_flags_list}
|
||||
|
||||
USES_TERMINAL_CONFIGURE ON
|
||||
USES_TERMINAL_BUILD ON
|
||||
USES_TERMINAL_INSTALL ON
|
||||
)
|
||||
list(APPEND default_cmake_args
|
||||
-DLLDB_ENABLE_LIBXML2=ON
|
||||
-DLibXml2_ROOT=${wasi_tmp_install}
|
||||
)
|
||||
else()
|
||||
list(APPEND default_cmake_args -DLLDB_ENABLE_LIBXML2=OFF)
|
||||
add_custom_target(libxml2)
|
||||
endif()
|
||||
else()
|
||||
add_custom_target(libedit)
|
||||
add_custom_target(libxml2)
|
||||
endif()
|
||||
|
||||
list(TRANSFORM tools PREPEND --target= OUTPUT_VARIABLE build_targets)
|
||||
list(TRANSFORM tools PREPEND --target=install- OUTPUT_VARIABLE install_targets)
|
||||
|
||||
ExternalProject_Add(llvm-build
|
||||
SOURCE_DIR "${llvm_proj_dir}/llvm"
|
||||
CMAKE_ARGS
|
||||
${default_cmake_args}
|
||||
-DLLVM_ENABLE_ZLIB=OFF
|
||||
-DLLVM_ENABLE_ZSTD=OFF
|
||||
-DLLVM_STATIC_LINK_CXX_STDLIB=ON
|
||||
-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-wasip1
|
||||
-DLLVM_INSTALL_BINUTILS_SYMLINKS=TRUE
|
||||
-DLLVM_ENABLE_LIBXML2=OFF
|
||||
# Pass `-s` to strip symbols by default and shrink the size of the
|
||||
# distribution
|
||||
-DCMAKE_EXE_LINKER_FLAGS=-s
|
||||
# Looks to be required on macOS for, at build time, the dynamic linker to
|
||||
# find `libedit.dylib` when that's enabled.
|
||||
-DCMAKE_BUILD_RPATH=${wasi_tmp_install}/lib
|
||||
${llvm_cmake_flags_list}
|
||||
# See https://www.scivision.dev/cmake-externalproject-list-arguments/ for
|
||||
# why this is in `CMAKE_CACHE_ARGS` instead of above
|
||||
CMAKE_CACHE_ARGS
|
||||
-DLLVM_ENABLE_PROJECTS:STRING=${projects}
|
||||
-DCLANG_LINKS_TO_CREATE:STRING=${links_to_create}
|
||||
BUILD_COMMAND
|
||||
cmake --build . ${build_targets}
|
||||
INSTALL_COMMAND
|
||||
cmake --build . ${install_targets}
|
||||
USES_TERMINAL_CONFIGURE ON
|
||||
USES_TERMINAL_BUILD ON
|
||||
USES_TERMINAL_INSTALL ON
|
||||
)
|
||||
|
||||
add_custom_target(build ALL DEPENDS llvm-build)
|
||||
ExternalProject_Add_StepDependencies(llvm-build configure libedit libxml2)
|
||||
|
||||
# Installation target for this outer project for installing the toolchain to the
|
||||
# system.
|
||||
install(DIRECTORY ${wasi_tmp_install}/bin ${wasi_tmp_install}/lib ${wasi_tmp_install}/share
|
||||
USE_SOURCE_PERMISSIONS
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
# Build logic for `wasm-component-ld` installed from Rust code.
|
||||
set(wasm_component_ld_root ${CMAKE_CURRENT_BINARY_DIR}/wasm-component-ld)
|
||||
set(wasm_component_ld ${wasm_component_ld_root}/bin/wasm-component-ld${CMAKE_EXECUTABLE_SUFFIX})
|
||||
set(wasm_component_ld_version 0.5.21)
|
||||
if(RUST_TARGET)
|
||||
set(rust_target_flag --target=${RUST_TARGET})
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT ${wasm_component_ld}
|
||||
COMMAND
|
||||
cargo install --root ${wasm_component_ld_root} ${rust_target_flag}
|
||||
wasm-component-ld@${wasm_component_ld_version}
|
||||
COMMAND
|
||||
cmake -E make_directory ${wasi_tmp_install}/bin
|
||||
COMMAND
|
||||
cmake -E copy ${wasm_component_ld} ${wasi_tmp_install}/bin
|
||||
COMMENT "Building `wasm-component-ld` ...")
|
||||
add_custom_target(wasm-component-ld DEPENDS ${wasm_component_ld})
|
||||
add_dependencies(build wasm-component-ld)
|
||||
|
||||
# Setup installation logic for CMake support files.
|
||||
add_custom_target(misc-files)
|
||||
add_dependencies(build misc-files)
|
||||
|
||||
function(copy_misc_file src dst_folder)
|
||||
cmake_path(GET src FILENAME src_filename)
|
||||
set(dst ${wasi_tmp_install}/share/${dst_folder}/${src_filename})
|
||||
add_custom_command(
|
||||
OUTPUT ${dst}
|
||||
COMMAND cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${dst})
|
||||
add_custom_target(copy-${src_filename} DEPENDS ${dst})
|
||||
add_dependencies(misc-files copy-${src_filename})
|
||||
endfunction()
|
||||
|
||||
copy_misc_file(src/config/config.sub misc)
|
||||
copy_misc_file(src/config/config.guess misc)
|
||||
copy_misc_file(wasi-sdk.cmake cmake)
|
||||
copy_misc_file(wasi-sdk-pthread.cmake cmake)
|
||||
copy_misc_file(wasi-sdk-p1.cmake cmake)
|
||||
copy_misc_file(wasi-sdk-p2.cmake cmake)
|
||||
copy_misc_file(wasi-sdk-p3.cmake cmake)
|
||||
copy_misc_file(cmake/Platform/WASI.cmake cmake/Platform)
|
||||
|
||||
function(copy_cfg_file compiler)
|
||||
set(dst ${wasi_tmp_install}/bin/${compiler}.cfg)
|
||||
add_custom_command(
|
||||
OUTPUT ${dst}
|
||||
COMMAND cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/clang.cfg ${dst})
|
||||
add_custom_target(copy-${compiler} DEPENDS ${dst})
|
||||
add_dependencies(misc-files copy-${compiler})
|
||||
endfunction()
|
||||
|
||||
copy_cfg_file(clang)
|
||||
copy_cfg_file(clang++)
|
||||
|
||||
include(wasi-sdk-dist)
|
||||
|
||||
# Figure out the name of the artifact which is either explicitly specified or
|
||||
# inferred from CMake default variables.
|
||||
if(WASI_SDK_ARTIFACT)
|
||||
set(wasi_sdk_artifact ${WASI_SDK_ARTIFACT})
|
||||
else()
|
||||
if(APPLE)
|
||||
set(wasi_sdk_os macos)
|
||||
else()
|
||||
string(TOLOWER ${CMAKE_SYSTEM_NAME} wasi_sdk_os)
|
||||
endif()
|
||||
set(wasi_sdk_arch ${CMAKE_SYSTEM_PROCESSOR})
|
||||
set(wasi_sdk_artifact ${wasi_sdk_arch}-${wasi_sdk_os})
|
||||
endif()
|
||||
|
||||
set(dist_dir ${CMAKE_CURRENT_BINARY_DIR}/dist)
|
||||
wasi_sdk_add_tarball(dist-toolchain
|
||||
${dist_dir}/wasi-toolchain-${wasi_sdk_version}-${wasi_sdk_artifact}.tar.gz
|
||||
${wasi_tmp_install})
|
||||
add_dependencies(dist-toolchain build)
|
||||
add_custom_target(dist DEPENDS dist-toolchain)
|
||||
@ -0,0 +1,27 @@
|
||||
# A container which has a number of build tools pre-installed plus a build of
|
||||
# `wasi-sdk` installed at `/opt/wasi-sdk`. This also has environment variables
|
||||
# pre-configued to use the installed toolchain.
|
||||
#
|
||||
# This container is built as the last step on CI for this repository and
|
||||
# pre-built versions of this container are pushed as a package to the repository
|
||||
# as well.
|
||||
|
||||
FROM ubuntu:24.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y cmake ninja-build make autoconf autogen automake libtool && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ADD dist/wasi-sdk-*.deb .
|
||||
RUN case `dpkg --print-architecture` in \
|
||||
amd64) dpkg -i wasi-sdk-*-x86_64-linux.deb ;; \
|
||||
arm64) dpkg -i wasi-sdk-*-arm64-linux.deb ;; \
|
||||
*) exit 1 ;; \
|
||||
esac && \
|
||||
rm wasi-sdk-*.deb
|
||||
|
||||
ENV CC="/opt/wasi-sdk/bin/clang"
|
||||
ENV CXX="/opt/wasi-sdk/bin/clang++"
|
||||
ENV LD="/opt/wasi-sdk/bin/wasm-ld"
|
||||
ENV AR="/opt/wasi-sdk/bin/llvm-ar"
|
||||
ENV RANLIB="/opt/wasi-sdk/bin/llvm-ranlib"
|
||||
@ -0,0 +1 @@
|
||||
Subproject commit f992bcc08219edb283d2ab31dd3871a4a0e8220e
|
||||
@ -0,0 +1,28 @@
|
||||
diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h
|
||||
index f8e83e138eff..c5097d25b0c6 100644
|
||||
--- a/libunwind/src/assembly.h
|
||||
+++ b/libunwind/src/assembly.h
|
||||
@@ -249,6 +249,9 @@ aliasname: \
|
||||
#define WEAK_ALIAS(name, aliasname)
|
||||
#define NO_EXEC_STACK_DIRECTIVE
|
||||
|
||||
+#elif defined(__wasm__)
|
||||
+#define NO_EXEC_STACK_DIRECTIVE
|
||||
+
|
||||
// clang-format on
|
||||
#else
|
||||
|
||||
diff --git a/libunwind/src/config.h b/libunwind/src/config.h
|
||||
index deb5a4d4d73d..23c9f012cbcf 100644
|
||||
--- a/libunwind/src/config.h
|
||||
+++ b/libunwind/src/config.h
|
||||
@@ -66,7 +66,8 @@
|
||||
#define _LIBUNWIND_EXPORT
|
||||
#define _LIBUNWIND_HIDDEN
|
||||
#else
|
||||
- #if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX)
|
||||
+ #if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX) && \
|
||||
+ !defined(__wasm__)
|
||||
#define _LIBUNWIND_EXPORT __declspec(dllexport)
|
||||
#define _LIBUNWIND_HIDDEN
|
||||
#else
|
||||
@ -0,0 +1,48 @@
|
||||
From f71fdfcbd6fcc7b521c74b5856ebeacdd6cf55d9 Mon Sep 17 00:00:00 2001
|
||||
From: Catherine <whitequark@whitequark.org>
|
||||
Date: Thu, 12 Mar 2026 08:19:49 +0000
|
||||
Subject: [PATCH] [libc++abi] Revert gating of `__cxa_thread_atexit` on
|
||||
Linux||Fuchsia
|
||||
|
||||
This was done in the commit 3c100d5d548d with the description
|
||||
"Enable -Wmissing-prototypes" which seems incongruent to me.
|
||||
|
||||
Since then it's made its way into a release and broke the use of
|
||||
`thread_local` variables with destructors on Wasm/WASI:
|
||||
|
||||
```cc
|
||||
// repro.cc
|
||||
struct c { ~c() {} };
|
||||
thread_local c v;
|
||||
int main() { (void)v; }
|
||||
```
|
||||
|
||||
```console
|
||||
$ ./wasi-sdk-31.0-x86_64-linux/bin/clang++ repro.cc
|
||||
wasm-ld: error: /tmp/repro-dd1ad7.o: undefined symbol: __cxa_thread_atexit
|
||||
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
|
||||
```
|
||||
---
|
||||
libcxxabi/src/cxa_thread_atexit.cpp | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libcxxabi/src/cxa_thread_atexit.cpp b/libcxxabi/src/cxa_thread_atexit.cpp
|
||||
index 402a52c741012..1bdcb4ef192b4 100644
|
||||
--- a/libcxxabi/src/cxa_thread_atexit.cpp
|
||||
+++ b/libcxxabi/src/cxa_thread_atexit.cpp
|
||||
@@ -106,7 +106,6 @@ namespace {
|
||||
|
||||
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
|
||||
|
||||
-#if defined(__linux__) || defined(__Fuchsia__)
|
||||
extern "C" {
|
||||
|
||||
_LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() {
|
||||
@@ -141,6 +140,5 @@ extern "C" {
|
||||
}
|
||||
#endif // HAVE___CXA_THREAD_ATEXIT_IMPL
|
||||
}
|
||||
-} // extern "C"
|
||||
-#endif // defined(__linux__) || defined(__Fuchsia__)
|
||||
+ } // extern "C"
|
||||
} // namespace __cxxabiv1
|
||||
@ -0,0 +1 @@
|
||||
Subproject commit 4434dabb69916856b824f68a64b029c67175e532
|
||||
@ -0,0 +1 @@
|
||||
Subproject commit 2fc32bc81b9f07f8d9525edea59bfbaf760c06d6
|
||||
@ -0,0 +1,3 @@
|
||||
*.observed
|
||||
*.observed.filtered
|
||||
*.wasm
|
||||
@ -0,0 +1,123 @@
|
||||
# Support for running tests in the `tests/{compile-only,general}` folders
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
project(wasi-sdk-test)
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".wasm")
|
||||
|
||||
option(WASI_SDK_TEST_HOST_TOOLCHAIN "Test against the host toolchain, not a fresh sysroot" OFF)
|
||||
|
||||
if(NOT WASI_SDK_TEST_HOST_TOOLCHAIN)
|
||||
add_compile_options(--sysroot=${wasi_sysroot} -resource-dir ${wasi_resource_dir})
|
||||
add_link_options(--sysroot=${wasi_sysroot} -resource-dir ${wasi_resource_dir})
|
||||
endif()
|
||||
|
||||
# Sanity check setup
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL WASI)
|
||||
message(FATAL_ERROR "Wrong system name (${CMAKE_SYSTEM_NAME}), wrong toolchain file in use?")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED WASI)
|
||||
message(FATAL_ERROR "WASI is not set, platform file likely not loaded")
|
||||
endif()
|
||||
|
||||
set(WASI_SDK_RUNWASI "wasmtime" CACHE STRING "Runner for tests")
|
||||
|
||||
# Test everything at O0, O2, and O2+LTO
|
||||
set(opt_flags -O0 -O2 "-O2 -flto")
|
||||
|
||||
add_custom_target(build-tests)
|
||||
|
||||
# Executes a single `test` specified.
|
||||
#
|
||||
# This will compile `test` for all the various targets and with various
|
||||
# compiler options. If `runwasi` is non-empty then the test will be executed
|
||||
# in that runner as well.
|
||||
function(add_testcase runwasi test)
|
||||
foreach(target IN LISTS WASI_SDK_TARGETS)
|
||||
foreach(compile_flags IN LISTS opt_flags)
|
||||
# Mangle the options into something appropriate for a CMake rule name
|
||||
string(REGEX REPLACE " " "." target_name "${target}.${compile_flags}.${test}")
|
||||
|
||||
# Add a new test executable based on `test`
|
||||
add_executable(${target_name} ${test})
|
||||
add_dependencies(build-tests ${target_name})
|
||||
|
||||
# Configure all the compile options necessary. For example `--target` here
|
||||
# if the target doesn't look like it's already in the name of the compiler
|
||||
# as well.
|
||||
if(NOT(CMAKE_C_COMPILER MATCHES ${target}))
|
||||
target_compile_options(${target_name} PRIVATE --target=${target})
|
||||
target_link_options(${target_name} PRIVATE --target=${target})
|
||||
endif()
|
||||
|
||||
# Apply test-specific compile options and link flags.
|
||||
if(test MATCHES "clocks.c$")
|
||||
target_compile_options(${target_name} PRIVATE -D_WASI_EMULATED_PROCESS_CLOCKS)
|
||||
target_link_options(${target_name} PRIVATE -lwasi-emulated-process-clocks)
|
||||
elseif(test MATCHES "mmap.c$")
|
||||
target_compile_options(${target_name} PRIVATE -D_WASI_EMULATED_MMAN)
|
||||
target_link_options(${target_name} PRIVATE -lwasi-emulated-mman)
|
||||
elseif(test MATCHES "(sigabrt|signals).c$")
|
||||
target_compile_options(${target_name} PRIVATE -D_WASI_EMULATED_SIGNAL)
|
||||
target_link_options(${target_name} PRIVATE -lwasi-emulated-signal)
|
||||
elseif(test MATCHES "printf-long-double-enabled.c$")
|
||||
target_link_options(${target_name} PRIVATE -lc-printscan-long-double)
|
||||
endif()
|
||||
|
||||
# Apply language-specific options and dependencies.
|
||||
if(test MATCHES "cc$")
|
||||
if(WASI_SDK_EXCEPTIONS)
|
||||
target_compile_options(${target_name} PRIVATE -fwasm-exceptions -mllvm -wasm-use-legacy-eh=false)
|
||||
target_link_options(${target_name} PRIVATE -lunwind)
|
||||
else()
|
||||
target_compile_options(${target_name} PRIVATE -fno-exceptions)
|
||||
endif()
|
||||
if(NOT WASI_SDK_TEST_HOST_TOOLCHAIN)
|
||||
add_dependencies(${target_name} libcxx-${target})
|
||||
endif()
|
||||
else()
|
||||
if(NOT WASI_SDK_TEST_HOST_TOOLCHAIN)
|
||||
add_dependencies(${target_name} wasi-libc-${target})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Apply target-specific options.
|
||||
if(target MATCHES threads)
|
||||
target_compile_options(${target_name} PRIVATE -pthread)
|
||||
target_link_options(${target_name} PRIVATE -pthread)
|
||||
endif()
|
||||
|
||||
if(target STREQUAL wasm32-wasi OR target STREQUAL wasm32-wasi-threads)
|
||||
target_compile_options(${target_name} PRIVATE -Wno-deprecated)
|
||||
target_link_options(${target_name} PRIVATE -Wno-deprecated)
|
||||
endif()
|
||||
|
||||
if(runwasi)
|
||||
set(runner ${runwasi})
|
||||
if(${runner} MATCHES wasmtime)
|
||||
if(target MATCHES threads)
|
||||
set(runner "${runner} -Wshared-memory")
|
||||
endif()
|
||||
if(WASI_SDK_EXCEPTIONS)
|
||||
set(runner "${runner} -Wexceptions")
|
||||
endif()
|
||||
if(target MATCHES "wasip3")
|
||||
set(runner "${runner} -Wcomponent-model-async -Sp3")
|
||||
endif()
|
||||
endif()
|
||||
add_test(
|
||||
NAME test-${target_name}
|
||||
COMMAND
|
||||
bash ../testcase.sh
|
||||
${runner}
|
||||
${test}
|
||||
$<TARGET_FILE:${target_name}>
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
add_subdirectory(compile-only)
|
||||
add_subdirectory(general)
|
||||
@ -0,0 +1,9 @@
|
||||
file(GLOB c_compile_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c")
|
||||
file(GLOB cxx_compile_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cc")
|
||||
|
||||
set(compile_tests ${c_compile_tests} ${cxx_compile_tests})
|
||||
|
||||
foreach(test IN LISTS compile_tests)
|
||||
add_testcase("" ${test})
|
||||
endforeach()
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
extern char **environ;
|
||||
|
||||
extern void __dso_handle;
|
||||
#if !defined(__clang_major__) || __clang_major__ >= 10
|
||||
extern void __data_end;
|
||||
extern void __global_base;
|
||||
extern void __heap_base;
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("NULL=%p\n", NULL);
|
||||
printf("__dso_handle=%p\n", &__dso_handle);
|
||||
#if !defined(__clang_major__) || __clang_major__ >= 10
|
||||
printf("__data_end=%p\n", &__data_end);
|
||||
printf("__global_base=%p\n", &__global_base);
|
||||
printf("__heap_base=%p\n", &__heap_base);
|
||||
#endif
|
||||
printf("__builtin_frame_address(0)=%p\n", __builtin_frame_address(0));
|
||||
printf("__builtin_alloca(0)=%p\n", __builtin_alloca(0));
|
||||
printf("__builtin_wasm_memory_size(0)=%p\n", (void *)(__builtin_wasm_memory_size(0) * PAGE_SIZE));
|
||||
printf("&errno=%p\n", (void *)&errno);
|
||||
printf("&environ=%p\n", (void *)&environ);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
volatile long double x = 42.0L;
|
||||
|
||||
int main(void) {
|
||||
printf("the answer is %Lf\n", x);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
int main(){}
|
||||
@ -0,0 +1 @@
|
||||
0
|
||||
@ -0,0 +1,8 @@
|
||||
file(GLOB c_general_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS "*.c")
|
||||
file(GLOB cxx_general_tests RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS "*.cc")
|
||||
|
||||
set(general_tests ${c_general_tests} ${cxx_general_tests})
|
||||
|
||||
foreach(test IN LISTS general_tests)
|
||||
add_testcase(${WASI_SDK_RUNWASI} ${test})
|
||||
endforeach()
|
||||
@ -0,0 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
134
|
||||
@ -0,0 +1,7 @@
|
||||
Error: failed to run main module `abort.c.---.wasm`
|
||||
|
||||
Caused by:
|
||||
0: failed to invoke ---
|
||||
1: error while executing at wasm backtrace:
|
||||
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
|
||||
2: wasm trap: wasm `unreachable` instruction executed
|
||||
@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cat \
|
||||
| sed -e 's/main module `.*abort\.c\.wasm`/main module `abort.c.---.wasm`/' \
|
||||
| sed -e 's/failed to invoke.*/failed to invoke ---/' \
|
||||
| sed -E '/0x[[:xdigit:]]+/d'
|
||||
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
puts("hello from argc argv main!");
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
hello from argc argv main!
|
||||
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
puts("hello from C++ argc argv main!");
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
hello from C++ argc argv main!
|
||||
@ -0,0 +1,11 @@
|
||||
#ifdef NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int main(void) {
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
134
|
||||
@ -0,0 +1,8 @@
|
||||
Assertion failed: false (assert-fail.c: main: 9)
|
||||
Error: failed to run main module `assert-fail.c.---.wasm`
|
||||
|
||||
Caused by:
|
||||
0: failed to invoke ---
|
||||
1: error while executing at wasm backtrace:
|
||||
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
|
||||
2: wasm trap: wasm `unreachable` instruction executed
|
||||
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cat \
|
||||
| sed -e 's/main module `.*assert-fail\.c\.wasm`/main module `assert-fail.c.---.wasm`/' \
|
||||
| sed -e 's/failed to invoke.*/failed to invoke ---/' \
|
||||
| sed -e 's/Assertion failed: false (.*assert-fail.c/Assertion failed: false (assert-fail.c/' \
|
||||
| sed -E '/0x[[:xdigit:]]+/d'
|
||||
@ -0,0 +1,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int main(void) {
|
||||
assert(true);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
#include <time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/times.h>
|
||||
#include <assert.h>
|
||||
|
||||
static void test_clock(void) {
|
||||
clock_t a = clock();
|
||||
clock_t b = clock();
|
||||
assert(a != -1);
|
||||
assert(b != -1);
|
||||
assert(a > 0);
|
||||
assert(b >= a);
|
||||
}
|
||||
|
||||
static void test_times(void) {
|
||||
struct tms before;
|
||||
struct tms after;
|
||||
clock_t a = times(&before);
|
||||
clock_t b = times(&after);
|
||||
assert(a != -1);
|
||||
assert(b != -1);
|
||||
assert(b >= a);
|
||||
assert(after.tms_utime >= before.tms_utime);
|
||||
}
|
||||
|
||||
static void test_getrusage(void) {
|
||||
struct rusage before;
|
||||
struct rusage after;
|
||||
int a = getrusage(RUSAGE_SELF, &before);
|
||||
int b = getrusage(RUSAGE_SELF, &after);
|
||||
assert(a != -1);
|
||||
assert(b != -1);
|
||||
assert(after.ru_utime.tv_sec >= before.ru_utime.tv_sec);
|
||||
assert(after.ru_utime.tv_sec != before.ru_utime.tv_sec ||
|
||||
after.ru_utime.tv_usec >= before.ru_utime.tv_usec);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_clock();
|
||||
test_times();
|
||||
test_getrusage();
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
struct c { ~c() {} };
|
||||
thread_local c v;
|
||||
int main() { (void)v; }
|
||||
@ -0,0 +1,52 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
extern char **environ;
|
||||
|
||||
static void from_atexit(void) {
|
||||
printf("hello from_atexit\n");
|
||||
}
|
||||
|
||||
static void another_from_atexit(void) {
|
||||
printf("hello another_from_atexit\n");
|
||||
}
|
||||
|
||||
__attribute__((constructor)) static void from_constructor(void) {
|
||||
printf("hello from_constructor\n");
|
||||
}
|
||||
|
||||
__attribute__((constructor(101))) static void from_constructor_101(void) {
|
||||
assert(errno == 0);
|
||||
printf("hello from_constructor101\n");
|
||||
|
||||
assert(environ && "environment should be initialized by this point");
|
||||
}
|
||||
|
||||
__attribute__((constructor(65535))) static void from_constructor_65535(void) {
|
||||
printf("hello from_constructor65535\n");
|
||||
}
|
||||
|
||||
__attribute__((destructor)) static void from_destructor(void) {
|
||||
printf("hello from_destructor\n");
|
||||
}
|
||||
|
||||
__attribute__((destructor(101))) static void from_destructor101(void) {
|
||||
printf("hello from_destructor101\n");
|
||||
}
|
||||
|
||||
__attribute__((destructor(65535))) static void from_destructor65535(void) {
|
||||
printf("hello from_destructor65535\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
printf("hello main\n");
|
||||
assert(argc != 0);
|
||||
assert(argv != NULL);
|
||||
assert(argv[argc] == NULL);
|
||||
|
||||
atexit(from_atexit);
|
||||
atexit(another_from_atexit);
|
||||
printf("goodbye main\n");
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
hello from_constructor101
|
||||
hello from_constructor
|
||||
hello from_constructor65535
|
||||
hello main
|
||||
goodbye main
|
||||
hello another_from_atexit
|
||||
hello from_atexit
|
||||
hello from_destructor65535
|
||||
hello from_destructor
|
||||
hello from_destructor101
|
||||
@ -0,0 +1,16 @@
|
||||
#include "ctors_dtors.c"
|
||||
|
||||
struct StaticObject {
|
||||
StaticObject();
|
||||
~StaticObject();
|
||||
};
|
||||
|
||||
StaticObject::StaticObject() {
|
||||
printf("hello StaticObject::StaticObject\n");
|
||||
}
|
||||
|
||||
StaticObject::~StaticObject() {
|
||||
printf("hello StaticObject::~StaticObject\n");
|
||||
}
|
||||
|
||||
static StaticObject static_object;
|
||||
@ -0,0 +1,12 @@
|
||||
hello from_constructor101
|
||||
hello from_constructor
|
||||
hello from_constructor65535
|
||||
hello StaticObject::StaticObject
|
||||
hello main
|
||||
goodbye main
|
||||
hello another_from_atexit
|
||||
hello from_atexit
|
||||
hello from_destructor65535
|
||||
hello from_destructor
|
||||
hello StaticObject::~StaticObject
|
||||
hello from_destructor101
|
||||
@ -0,0 +1 @@
|
||||
int main(void) { return 0; }
|
||||
@ -0,0 +1,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
printf("HELLO = %s\n", getenv("HELLO"));
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
HELLO = (null)
|
||||
@ -0,0 +1,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
printf("HELLO = %s\n", getenv("HELLO"));
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
HELLO=hello
|
||||
@ -0,0 +1 @@
|
||||
HELLO = hello
|
||||
@ -0,0 +1,18 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
extern char **environ;
|
||||
|
||||
int main(void) {
|
||||
assert(environ != NULL);
|
||||
for (char **p = environ; *p; ++p) {
|
||||
assert(p != NULL);
|
||||
}
|
||||
for (char **p = environ; *p; ++p) {
|
||||
if (strncmp(*p, "HELLO=", 5) == 0) {
|
||||
printf("HELLO = %s\n", *p + 6);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
HELLO=hello
|
||||
@ -0,0 +1 @@
|
||||
HELLO = hello
|
||||
@ -0,0 +1,17 @@
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main() {
|
||||
#ifdef __wasm_exception_handling__
|
||||
try {
|
||||
throw std::runtime_error("An error occurred");
|
||||
abort();
|
||||
} catch (const std::runtime_error& e) {
|
||||
// ..
|
||||
return 0;
|
||||
}
|
||||
abort();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int main() {
|
||||
char buf[256] = {0};
|
||||
int ret = getentropy(buf, 256);
|
||||
assert(ret == 0);
|
||||
|
||||
bool something_nonzero = false;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (buf[i] != 0)
|
||||
something_nonzero = true;
|
||||
}
|
||||
|
||||
assert(something_nonzero);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "hello from C++ main with cout!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
hello from C++ main with cout!
|
||||
@ -0,0 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
// It isn't required that errno be zero on entry to main, but
|
||||
// for tidiness' sake, if we ever do things during startup that
|
||||
// do set errno, we should reset it for tidiness' sake.
|
||||
int main(void) {
|
||||
int n = errno;
|
||||
printf("initial errno is %d: %s\n", n, strerror(n));
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
initial errno is 0: Success
|
||||
@ -0,0 +1,87 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __GLIBC__
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
#define perror_and_exit(message) \
|
||||
do { \
|
||||
perror(message); \
|
||||
return EXIT_FAILURE; \
|
||||
} while (0)
|
||||
|
||||
#define OFFSET 10726
|
||||
#define LENGTH 143
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <dir>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
char *filename;
|
||||
if (asprintf(&filename, "%s/input.txt", argv[1]) == -1) {
|
||||
fprintf(stderr, "can't allocate filename");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
perror_and_exit("open");
|
||||
|
||||
struct stat stat_buf;
|
||||
if (fstat(fd, &stat_buf) != 0)
|
||||
perror_and_exit("fstat");
|
||||
|
||||
off_t offset = OFFSET;
|
||||
if (offset < 0) {
|
||||
fprintf(stderr, "negative offset\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (offset > (off_t)SIZE_MAX) {
|
||||
fprintf(stderr, "offset overflow\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
off_t aligned_offset = offset & -(off_t)PAGE_SIZE;
|
||||
|
||||
if (offset >= stat_buf.st_size) {
|
||||
fprintf(stderr, "offset is past end of file\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
size_t length = LENGTH;
|
||||
if ((off_t)length < 0) {
|
||||
fprintf(stderr, "length overflow\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if ((off_t)length > stat_buf.st_size - offset)
|
||||
length = (size_t)(stat_buf.st_size - offset);
|
||||
|
||||
size_t mmap_length = length + (size_t)(offset - aligned_offset);
|
||||
char *addr = mmap(NULL, mmap_length, PROT_READ, MAP_PRIVATE, fd, aligned_offset);
|
||||
if (addr == MAP_FAILED)
|
||||
perror_and_exit("mmap");
|
||||
|
||||
ssize_t nwritten = write(STDOUT_FILENO, addr + (offset - aligned_offset), length);
|
||||
if (nwritten < 0)
|
||||
perror_and_exit("write");
|
||||
|
||||
if ((size_t)nwritten != length) {
|
||||
fprintf(stderr, "partial write");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (munmap(addr, mmap_length) != 0)
|
||||
perror_and_exit("munmap");
|
||||
|
||||
if (close(fd) != 0)
|
||||
perror_and_exit("close");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
# This input is read at runtime during testing so ensure that the same input is
|
||||
# read on unix and windows by forcing just-a-newline for line endings.
|
||||
*.txt text eol=lf
|
||||
@ -0,0 +1,3 @@
|
||||
“Would you tell me, please, which way I ought to go from here?”
|
||||
|
||||
“That depends a good deal on where you want to get to,” said the Cat.
|
||||
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
puts("hello from no-arg main!");
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
hello from no-arg main!
|
||||
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
puts("hello from C++ no-arg main!");
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
hello from C++ no-arg main!
|
||||
@ -0,0 +1,72 @@
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define perror_and_exit(message) \
|
||||
do { \
|
||||
perror(message); \
|
||||
return EXIT_FAILURE; \
|
||||
} while (0)
|
||||
|
||||
#define OFFSET 10726
|
||||
#define LENGTH 143
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s <dir>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
DIR *dir = opendir(argv[1]);
|
||||
if (dir == NULL) {
|
||||
perror_and_exit("opendir");
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
int zeros = 0;
|
||||
errno = 0;
|
||||
for (;; count += 1) {
|
||||
struct dirent *ent = readdir(dir);
|
||||
if (ent == NULL) {
|
||||
if (errno == 0) {
|
||||
break;
|
||||
}
|
||||
perror_and_exit("readdir");
|
||||
}
|
||||
|
||||
if (strcmp(ent->d_name, "file.md") == 0) {
|
||||
assert(ent->d_type == DT_REG);
|
||||
} else if (strcmp(ent->d_name, "dir") == 0) {
|
||||
assert(ent->d_type == DT_DIR);
|
||||
} else if (strcmp(ent->d_name, "file-symlink") == 0) {
|
||||
assert(ent->d_type == DT_LNK);
|
||||
} else if (strcmp(ent->d_name, "dir-symlink") == 0) {
|
||||
assert(ent->d_type == DT_LNK);
|
||||
} else if (strcmp(ent->d_name, ".") == 0) {
|
||||
assert(ent->d_type == DT_DIR);
|
||||
} else if (strcmp(ent->d_name, "..") == 0) {
|
||||
assert(ent->d_type == DT_DIR);
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
if (ent->d_ino == 0) {
|
||||
zeros += 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(count == 6);
|
||||
assert(zeros <= 1);
|
||||
|
||||
if (closedir(dir) != 0)
|
||||
perror_and_exit("closedir");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
dir
|
||||
@ -0,0 +1 @@
|
||||
This is a file in a directory.
|
||||
@ -0,0 +1 @@
|
||||
file.md
|
||||
@ -0,0 +1 @@
|
||||
# This is a top-level file
|
||||
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
volatile long double x = 42.0L;
|
||||
|
||||
int main(void) {
|
||||
printf("the answer is %Lf\n", x);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
the answer is 42.000000
|
||||
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
volatile int x = 42;
|
||||
|
||||
int main(void) {
|
||||
printf("the answer is %d\n", x);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
the answer is 42
|
||||
@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
volatile double x = 42.0;
|
||||
|
||||
int main(void) {
|
||||
printf("the answer is %f\n", x);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
the answer is 42.000000
|
||||
@ -0,0 +1,10 @@
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
fprintf(stderr, "raising SIGABRT...\n");
|
||||
raise(SIGABRT);
|
||||
fprintf(stderr, "oops!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
134
|
||||
@ -0,0 +1,6 @@
|
||||
raising SIGABRT...
|
||||
Program received fatal signal: Aborted
|
||||
Error: failed to run main module `sigabrt.c.---.wasm`
|
||||
|
||||
Caused by:
|
||||
0: failed to invoke ---
|
||||
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
cat \
|
||||
| sed -e 's/main module `.*sigabrt\.c\.wasm`/main module `sigabrt.c.---.wasm`/' \
|
||||
| sed -e 's/source location: @[[:xdigit:]]*$/source location: @----/' \
|
||||
| sed -e 's/failed to invoke.*/failed to invoke ---/' \
|
||||
| head -n 6
|
||||
@ -0,0 +1,6 @@
|
||||
raising SIGABRT...
|
||||
Program received fatal signal: Aborted
|
||||
Error: failed to run main module `sigabrt.c.---.wasm`
|
||||
|
||||
Caused by:
|
||||
0: failed to invoke `run` function
|
||||
@ -0,0 +1,6 @@
|
||||
raising SIGABRT...
|
||||
Program received fatal signal: Aborted
|
||||
Error: failed to run main module `sigabrt.c.---.wasm`
|
||||
|
||||
Caused by:
|
||||
0: failed to invoke `run` function
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue