diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 05090de3a..d56dc9190 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -57,10 +57,4 @@ runs: echo "CC=clang-$v" >> $GITHUB_ENV echo "AR=llvm-ar-$v" >> $GITHUB_ENV echo "NM=llvm-nm-$v" >> $GITHUB_ENV - # Note: wasm-component-ld is only needed for Linux because - # currently, wasm32-wasip2 is only tested on Linux. If that changes, - # this step will have to be added to the other targets. - curl -fsSLO https://github.com/bytecodealliance/wasm-component-ld/releases/download/v0.5.15/wasm-component-ld-v0.5.15-x86_64-linux.tar.gz - tar xzf wasm-component-ld-v0.5.15-x86_64-linux.tar.gz - echo "$(pwd)/wasm-component-ld-v0.5.15-x86_64-linux" >> $GITHUB_PATH if: runner.os == 'Linux' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 575b3017e..45977c841 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,6 @@ jobs: buildlibc: name: ${{ matrix.name }} runs-on: ${{ matrix.os }} - env: ${{ matrix.env || fromJSON('{}') }} strategy: fail-fast: false matrix: @@ -33,122 +32,101 @@ jobs: clang_version: 15.0.7 llvm_asset_suffix: arm64-apple-darwin22.0 upload: macos-clang-15 + args: -DBUILD_SHARED=OFF -DCMAKE_C_COMPILER_WORKS=ON - name: Build on Windows x86_64 os: windows-2025 clang_version: 20.1.8 upload: windows-clang-20 + args: -DBUILD_SHARED=OFF # Other versions of LLVM - name: Build with LLVM 11 os: ubuntu-22.04 clang_version: 11 upload: linux-x86_64-clang-11 - env: - BUILD_LIBSETJMP: no + args: -DSETJMP=OFF -DBUILD_SHARED=OFF - name: Build with LLVM 18 os: ubuntu-24.04 clang_version: 18 upload: linux-x86_64-clang-18 - env: - MAKE_TARGETS: "default libc_so" # Test various combinations of target triples. # - # Configuration here can happen through `env` which is inherited to - # jobs below. For now this only runs tests on Linux with Clang 16, - # but that can be expanded as necessary in the future too. Note that - # some targets run the build for the `libc_so` makefile target to - # ensure the PIC build works. + # Configuration here can happen through `args` which are all passed + # to CMake. For now this only runs tests on Linux with Clang 16, + # but that can be expanded as necessary in the future too. - name: Test wasm32-wasi os: ubuntu-24.04 clang_version: 19 test: true upload: wasm32-wasi - env: - TARGET_TRIPLE: wasm32-wasi - MAKE_TARGETS: "default libc_so" + args: -DTARGET_TRIPLE=wasm32-wasi + - name: Test wasm32-wasip1 os: ubuntu-24.04 clang_version: 19 test: true upload: wasm32-wasip1 - env: - TARGET_TRIPLE: wasm32-wasip1 - MAKE_TARGETS: "default libc_so" + args: -DTARGET_TRIPLE=wasm32-wasip1 + - name: Test wasm32-wasip2 os: ubuntu-24.04 clang_version: 19 test: true upload: wasm32-wasip2 - env: - TARGET_TRIPLE: wasm32-wasip2 - WASI_SNAPSHOT: p2 - MAKE_TARGETS: "default libc_so" + args: -DTARGET_TRIPLE=wasm32-wasip2 + - name: Test wasm32-wasip1-threads os: ubuntu-24.04 clang_version: 19 test: true upload: wasm32-wasip1-threads - env: - TARGET_TRIPLE: wasm32-wasip1-threads - THREAD_MODEL: posix + args: -DTARGET_TRIPLE=wasm32-wasip1-threads + - name: Test wasm32-wasip1 in V8 os: ubuntu-24.04 clang_version: 19 test: true test_with_v8: true - env: - TARGET_TRIPLE: wasm32-wasip1 + args: -DTARGET_TRIPLE=wasm32-wasip1 + - name: Test wasm32-wasip1-threads in V8 os: ubuntu-24.04 clang_version: 19 test: true test_with_v8: true - env: - TARGET_TRIPLE: wasm32-wasip1-threads - THREAD_MODEL: posix + args: -DTARGET_TRIPLE=wasm32-wasip1-threads - name: Test wasm32-wasi-simd os: ubuntu-24.04 clang_version: 19 test: true upload: wasm32-wasi-simd - env: - TARGET_TRIPLE: wasm32-wasip1 - MAKE_TARGETS: "no-check-symbols" - EXTRA_CFLAGS: "-O2 -DNDEBUG -msimd128 -mrelaxed-simd -mbulk-memory -D__wasilibc_simd_string" + args: -DSIMD=ON -DCHECK_SYMBOLS=OFF - name: Test wasm32-wasip1 (debug) os: ubuntu-24.04 clang_version: 19 test: true - env: - TARGET_TRIPLE: wasm32-wasip1 - DEBUG: true + args: -DCMAKE_BUILD_TYPE=Debug + - name: Test wasm32-wasip2 (debug) os: ubuntu-24.04 clang_version: 19 test: true - env: - TARGET_TRIPLE: wasm32-wasip2 - WASI_SNAPSHOT: p2 - DEBUG: true + args: -DCMAKE_BUILD_TYPE=Debug -DTARGET_TRIPLE=wasm32-wasip2 + - name: Test wasm32-wasip1-threads (debug) os: ubuntu-24.04 clang_version: 19 test: true - env: - TARGET_TRIPLE: wasm32-wasip1-threads - THREAD_MODEL: posix - DEBUG: true + args: -DCMAKE_BUILD_TYPE=Debug -DTARGET_TRIPLE=wasm32-wasip1-threads - name: Test emmalloc os: ubuntu-24.04 clang_version: 19 test: true - env: - TARGET_TRIPLE: wasm32-wasip1 - MALLOC_IMPL: emmalloc + args: -DMALLOC=emmalloc steps: - uses: actions/checkout@v4.1.7 @@ -160,9 +138,6 @@ jobs: clang_version: ${{ matrix.clang_version }} llvm_asset_suffix: ${{ matrix.llvm_asset_suffix }} - - name: Build libc - run: make -j4 $MAKE_TARGETS CHECK_SYMBOLS=yes - - name: Install V8 dependencies if: matrix.test_with_v8 run: | @@ -171,29 +146,29 @@ jobs: echo ENGINE="$PWD/test/scripts/browser-test/harness.mjs" >> $GITHUB_ENV echo CTEST_ARGS="--label-exclude v8fail" >> $GITHUB_ENV - - name: Setup testing - if: matrix.test + - name: Configure libc run: | - cmake -S test -B testbuild -G Ninja \ - -DTARGET_TRIPLE=${{ env.TARGET_TRIPLE }} \ - -DENGINE=${{ env.ENGINE }} \ - -DCMAKE_LINK_DEPENDS_USE_LINKER=OFF \ - -DMALLOC_IMPL=${{ env.MALLOC_IMPL }} + cmake -G Ninja -S . -B build \ + -DCHECK_SYMBOLS=ON \ + ${{ matrix.args }} \ + -DCMAKE_LINK_DEPENDS_USE_LINKER=OFF - - name: Build tests + - name: Configure testing if: matrix.test - run: ninja -C testbuild + run: cmake -S . -B build -DBUILD_TESTS=ON -DENGINE=${{ env.ENGINE }} + + - name: Build + run: ninja -C build -v - name: Test if: matrix.test - run: ctest --test-dir testbuild --output-on-failure -j4 $CTEST_ARGS - + run: ctest --test-dir build/test --output-on-failure -j4 $CTEST_ARGS - uses: actions/upload-artifact@v4.4.0 if: matrix.upload with: name: ${{ format( 'sysroot-{0}.tgz', matrix.upload) }} - path: sysroot + path: build/sysroot # Disable the headerstest job for now, while WASI transitions from the @@ -244,7 +219,8 @@ jobs: - uses: actions/checkout@v4.1.7 with: submodules: true - - run: make bindings + - run: CC=clang cmake -S . -B build -G Ninja + - run: ninja -C build bindings - run: git diff --exit-code # Currently wasi-libc's test suite is pretty bare-bones. To try to increase @@ -253,28 +229,25 @@ jobs: # the end this runs at least some Python tests against a from-source-built # copy of wasi-libc. python: - name: Test Python + name: Test Python ${{ matrix.name }} runs-on: ubuntu-24.04-arm - env: ${{ matrix.env || fromJSON('{}') }} strategy: fail-fast: false matrix: include: - - env: - TARGET_TRIPLE: wasm32-wasip1 - - env: - TARGET_TRIPLE: wasm32-wasip2 - WASI_SNAPSHOT: p2 - - env: - TARGET_TRIPLE: wasm32-wasip1 - MALLOC_IMPL: emmalloc + - name: wasm32-wasip1 + args: -DTARGET_TRIPLE=wasm32-wasip1 + - name: emmalloc + args: -DTARGET_TRIPLE=wasm32-wasip1 -DMALLOC=emmalloc + - name: wasm32-wasip2 + args: -DTARGET_TRIPLE=wasm32-wasip2 steps: - uses: actions/checkout@v4.1.7 with: submodules: true - run: | - curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-arm64-linux.tar.gz -L | tar xzvf - - echo "WASI_SDK_PATH=`pwd`/wasi-sdk-24.0-arm64-linux" >> $GITHUB_ENV + curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-arm64-linux.tar.gz -L | tar xzvf - + echo "WASI_SDK_PATH=`pwd`/wasi-sdk-25.0-arm64-linux" >> $GITHUB_ENV if: runner.os == 'Linux' shell: bash working-directory: ${{ runner.tool_cache }} @@ -282,13 +255,13 @@ jobs: uses: bytecodealliance/actions/wasmtime/setup@v1 with: version: "38.0.3" - - run: make -j4 CC=$WASI_SDK_PATH/bin/clang AR=$WASI_SDK_PATH/bin/llvm-ar - - name: Setup testing + - name: Setup wasi-libc run: | - cmake -S test -B testbuild -G Ninja \ - -DTARGET_TRIPLE=${{ env.TARGET_TRIPLE }} \ + cmake -S . -B build -G Ninja \ + ${{ matrix.args }} \ -DCMAKE_LINK_DEPENDS_USE_LINKER=OFF \ -DPYTHON_TESTS=ON \ - -DCMAKE_C_COMPILER=clang + -DBUILD_TESTS=ON \ + -DCMAKE_C_COMPILER=$WASI_SDK_PATH/bin/clang - name: Build and test python - run: ninja -C testbuild python + run: ninja -C build -v python diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..ec27d77df --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,370 @@ +cmake_minimum_required(VERSION 3.26) + +# Give access to our `./cmake` local folder for `include(...)`. +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +# Use `--format=gnu` to generate identical archives regardless of the host. +set(CMAKE_C_ARCHIVE_CREATE " --format=gnu qc ") + +# If no `CMAKE_BUILD_TYPE` was specified, default to `Release`. +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type to use" FORCE) +endif() + +# Force a cross-compile to WASI at all times. +set(CMAKE_SYSTEM_NAME WASI) + +# I'm not entirely sure why this is necessary on Windows. This may be a bug in +# CMake, I'm not sure. The problem is that, at least on CI, CMake detects that +# the compiler in use in clang but doesn't understand the `SYSTEM` header +# option meaning it just pass `-I...` instead of +# `-isystem ...`. This in turn causes the build to fail for... somewhat +# unknown reasons which may also be bugs in wasi-libc. Setting this seems +# to work around the issue however. +if (CMAKE_HOST_WIN32) + set(CMAKE_INCLUDE_SYSTEM_FLAG_C "-isystem ") +endif() + +project(wasi-libc LANGUAGES C ASM) + +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() + +message(STATUS "Found executable for `nm`: ${CMAKE_NM}") +message(STATUS "Found executable for `ar`: ${CMAKE_AR}") +message(STATUS "Found executable for `ranlib`: ${CMAKE_RANLIB}") + +set(TARGET_TRIPLE "wasm32-wasip1" CACHE STRING "WASI target to test") +# Note: thin LTO here is just for experimentation. It has known issues: +# - https://github.com/llvm/llvm-project/issues/91700 +# - https://github.com/llvm/llvm-project/issues/91711 +set(LTO "" CACHE STRING "LTO mode to use") +set(MALLOC "dlmalloc" CACHE STRING "Malloc implementation to use (dlmalloc, jemalloc, or none)") +set(BUILTINS_LIB "" CACHE STRING "Path to precompiled compiler-rt builtins library") +set(BULK_MEMORY_THRESHOLD "32" CACHE STRING "Threshold to compile code with") +option(SETJMP "Build setjmp/longjmp support" ON) +option(BUILD_TESTS "Whether or not to build tests" OFF) +option(SIMD "Whether or not to build simd-enabled intrinsics into wasi-libc" OFF) +option(BUILD_SHARED "Whether or not to build shared libraries" ON) +option(CHECK_SYMBOLS "Whether or not to check the exported symbols of libc.a" OFF) + +if(TARGET_TRIPLE MATCHES "-threads$") + set(WASI p1) + # TODO: As of this writing, wasi_thread_start.s uses non-position-independent + # code, and I'm not sure how to make it position-independent. Once we've + # done that, we can enable libc.so for the wasi-threads build. + set(SHARED OFF) +elseif(TARGET_TRIPLE MATCHES "-wasi$") + set(WASI p1) + set(SHARED ON) +elseif(TARGET_TRIPLE MATCHES "-wasip1$") + set(WASI p1) + set(SHARED ON) +elseif(TARGET_TRIPLE MATCHES "-wasip2$") + set(WASI p2) + set(__wasilibc_use_wasip2 ON) + add_compile_definitions(-D__wasilibc_use_wasip2) + set(SHARED ON) +else() + message(FATAL_ERROR "Unknown WASI target triple: ${TARGET_TRIPLE}") +endif() + +if(BUILD_SHARED) + if (NOT SHARED) + message(WARNING "Disabling shared library builds as target is incompatible with shared libs") + endif() +else() + if (SHARED) + message(STATUS "Disabling shared library builds as BUILD_SHARED=OFF") + endif() + set(SHARED OFF) +endif() + +if(TARGET_TRIPLE MATCHES "-threads$") + set(THREADS ON) + add_compile_options(-mthread-model posix -pthread -ftls-model=local-exec -matomics) +else() + set(THREADS OFF) + add_compile_options(-mthread-model single) +endif() + +if(MALLOC STREQUAL "dlmalloc") + message(STATUS "Using dlmalloc as the malloc implementation") + set(malloc_target dlmalloc) +elseif(MALLOC STREQUAL "emmalloc") + message(STATUS "Using emmalloc as the malloc implementation") + set(malloc_target emmalloc) +elseif(MALLOC STREQUAL "none") + message(STATUS "Using nothing as the malloc implementation") +else() + message(FATAL_ERROR "Unsupported malloc implementation: ${MALLOC}") +endif() + +execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion + OUTPUT_VARIABLE clang_version + OUTPUT_STRIP_TRAILING_WHITESPACE) +set(SYSROOT ${CMAKE_CURRENT_BINARY_DIR}/sysroot) +set(SYSROOT_INC ${SYSROOT}/include/${TARGET_TRIPLE}) +set(SYSROOT_LIB ${SYSROOT}/lib/${TARGET_TRIPLE}) + +add_custom_target(sysroot ALL) +add_custom_target(sysroot_inc) + +if(LTO) + message(STATUS "Enabling LTO: ${LTO}") + set(SYSROOT_LIB ${SYSROOT_LIB}/llvm-lto/${clang_version}) + if(LTO STREQUAL "thin") + add_compile_options(-flto=thin) + elseif(LTO STREQUAL "full") + add_compile_options(-flto) + else() + message(FATAL_ERROR "Unknown LTO mode: ${LTO}") + endif() +endif() + +if(SIMD) + add_compile_options(-msimd128 -mrelaxed-simd -mbulk-memory + -D__wasilibc_simd_string) +endif() + +include(bindings) +include(builtins) +if (NOT (WASI STREQUAL "p1")) + include(wasm-component-ld) +endif() +include(check-symbols) + +# ============================================================================= +# Generic top-level build flags/settings +# +add_compile_options(--target=${TARGET_TRIPLE}) + +add_link_options( + --target=${TARGET_TRIPLE} + --sysroot=${SYSROOT} + + # By default clang will try to find, locate, and link compiler-rt. To get + # this to work a `-resource-dir` argument is passed to ensure that our + # custom `tmp_resource_dir` built here locally is used instead of the system + # directory which may or may not already have compiler-rt for wasm. + -resource-dir ${tmp_resource_dir} +) + +# Expose the public headers to the implementation. We use `-isystem` for +# purpose for two reasons: +# +# 1. It only does `<...>` not `"...."` lookup. We are making a libc, +# which is a system library, so all public headers should be +# accessible via `<...>` and never also need `"..."`. `-isystem` main +# purpose is to only effect `<...>` lookup. +# +# 2. The `-I` for private headers added for specific C files below +# should come earlier in the search path, so they can "override" +# and/or `#include_next` the public headers. `-isystem` (like +# `-idirafter`) comes later in the search path than `-I`. +# add_compile_options(-isystem ${SYSROOT_INC}) +include_directories(SYSTEM ${SYSROOT_INC}) + +include_directories(libc-bottom-half/cloudlibc/src) + + +add_compile_options( + # WebAssembly floating-point match doesn't trap. + # TODO: Add -fno-signaling-nans when the compiler supports it. + -fno-trapping-math + + # Add all warnings, but disable a few which occur in third-party code. + -Wall -Wextra -Werror + -Wno-null-pointer-arithmetic + -Wno-unused-parameter + -Wno-sign-compare + -Wno-unused-variable + -Wno-unused-function + -Wno-ignored-attributes + -Wno-missing-braces + -Wno-ignored-pragmas + -Wno-unused-but-set-variable + -Wno-unknown-warning-option + -Wno-unterminated-string-initialization + + # Compiling assembly flags lots of arguments as unused but that's not too + # interesting so just ignore that. + $<$:-Wno-unused-command-line-argument> +) + +# ============================================================================= +# Helper functions for adding libraries. + +# Helper to add the `src` file to the sysroot at `dst`. Adds to the `sysroot_inc` +# list of dependencies. +function(add_sysroot_header src dst) + string(REPLACE "/" "_" target_name ${dst}) + add_custom_command( + OUTPUT ${SYSROOT_INC}/${dst} + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/${src} + ${SYSROOT_INC}/${dst} + DEPENDS ${src} + ) + add_custom_target(sysroot-header-${target_name} DEPENDS ${SYSROOT_INC}/${dst}) + add_dependencies(sysroot_inc sysroot-header-${target_name}) +endfunction() + +# Adds two object libraries named `${name}-{shared,static}` and hook them up to +# the sysroot. The `*-shared` library is compiled with `-fPIC`. +function(add_object_library name) + add_library(${name}-shared OBJECT EXCLUDE_FROM_ALL ${ARGN}) + set_target_properties(${name}-shared PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + target_compile_options(${name}-shared PRIVATE -fvisibility=default) + add_dependencies(${name}-shared sysroot_inc) + + add_library(${name}-static OBJECT EXCLUDE_FROM_ALL ${ARGN}) + add_dependencies(${name}-static sysroot_inc) +endfunction() + +# Same as `add_object_library`, but also adds dependencies on +# `musl-top-half-interface` for compiler flags and include dirs. +function(add_internal_object_library name) + add_object_library(${name} ${ARGN}) + target_link_libraries(${name}-shared PUBLIC musl-top-half-interface) + target_link_libraries(${name}-static PUBLIC musl-top-half-interface) +endfunction() + +# Adds a shared library `name` with the following arguments as the +# sources. +# +# Adds a dependnecy on `musl-top-half-interface` for compiler flags, +# `sysroot-c` and `builtins` to ensure link-time dependencies are met, +# and then ensures compile options are configured. +function(add_internal_shared_library name) + add_library(${name} SHARED EXCLUDE_FROM_ALL ${ARGN}) + target_link_libraries(${name} PUBLIC musl-top-half-interface) + add_dependencies(${name} sysroot-c builtins) + target_compile_options(${name} PRIVATE -fvisibility=default) + set_target_properties(${name} PROPERTIES NO_SONAME 1) +endfunction() + +# Adds `${name}` and `${name}-static. +# +# Wrapper around `add_internal_shared_library` and then adding +# a static library as well. +function(add_internal_library_pair name) + add_internal_shared_library(${name} ${ARGN}) + + add_library(${name}-static STATIC EXCLUDE_FROM_ALL ${ARGN}) + target_link_libraries(${name}-static PUBLIC musl-top-half-interface) +endfunction() + +# Helper to add `target`, a cmake library target, to the sysroot at `file`. +# +# Copies the output into place and adds it to the top-level `sysroot` +# target. +function(sysroot_lib target file) + set(dst ${SYSROOT_LIB}/${file}) + add_custom_command( + OUTPUT ${dst} + COMMAND ${CMAKE_COMMAND} -E copy $ ${dst} + DEPENDS ${target} + ) + add_custom_target(sysroot-${target} DEPENDS ${dst}) + if (NOT (${file} MATCHES "\\.so$") OR SHARED) + add_dependencies(sysroot sysroot-${target}) + endif() +endfunction() + +# ============================================================================= +# subdirectories +# + +add_subdirectory(dlmalloc) +add_subdirectory(emmalloc) +add_subdirectory(fts) +add_subdirectory(libc-bottom-half) +add_subdirectory(libc-top-half) + +if (BUILD_TESTS) + add_subdirectory(test) +endif() + +#============================================================================== +# libc.{a,so} +# + +# TODO: if this `*.o` file is added to the `bottom-half-*` object libraries it +# doesn't make its way to the linker. I don't know if that's a bug in cmake or +# me not understanding cmake. This should ideally be bottom-half logic but it's +# here since I can't figure out anything else that works for now. +if (WASI STREQUAL "p2") + set(libc_extra_objects libc-bottom-half/sources/wasip2_component_type.o) +endif() + +add_library(c SHARED EXCLUDE_FROM_ALL + $ + $ + $ + $ + $ + $ + ${libc_extra_objects} +) +add_library(c-static STATIC EXCLUDE_FROM_ALL + $ + $ + $ + $ + $ + $ + ${libc_extra_objects} +) +add_dependencies(c sysroot-startup-objects builtins) + +target_link_options(c PRIVATE + # Note: libc.so is special because it shouldn't link to libc.so, and the + # -nodefaultlibs flag here disables the default `-lc` logic that clang has. + # Note though that this also disables linking of compiler-rt libraries so + # that is explicitly passed in via `${builtins_lib_path}` + -nodefaultlibs + ${builtins_lib_path} + + # Note: --allow-undefined-file=linker-provided-symbols.txt is a workaround + # for https://github.com/llvm/llvm-project/issues/103592 + -Wl,--allow-undefined-file=${CMAKE_CURRENT_SOURCE_DIR}/linker-provided-symbols.txt +) + +# TODO: Specify SDK version, e.g. libc.so.wasi-sdk-21, as SO_NAME once `wasm-ld` +# supports it. +set_target_properties(c PROPERTIES NO_SONAME 1) + +sysroot_lib(c-static libc.a) +sysroot_lib(c libc.so) + +# ============================================================================= +# Empty archives in the sysroot to satisfy `-l` flags + +function(empty_sysroot_archive file) + set(dst ${SYSROOT_LIB}/lib${file}.a) + add_custom_command( + OUTPUT ${dst} + COMMAND ${CMAKE_COMMAND} -E make_directory ${SYSROOT_LIB} + COMMAND ${CMAKE_AR} crs ${dst} + ) + add_custom_target(sysroot-empty-${file} DEPENDS ${dst}) + add_dependencies(sysroot sysroot-empty-${file}) +endfunction() + +empty_sysroot_archive(crypt) +empty_sysroot_archive(m) +empty_sysroot_archive(pthread) +empty_sysroot_archive(resolv) +empty_sysroot_archive(rt) +empty_sysroot_archive(util) +empty_sysroot_archive(xnet) + +# ============================================================================= +# Installation +# +include(GNUInstallDirs) +install(DIRECTORY ${SYSROOT}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(DIRECTORY ${SYSROOT}/lib/ DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/Makefile b/Makefile deleted file mode 100644 index 3dc301877..000000000 --- a/Makefile +++ /dev/null @@ -1,1111 +0,0 @@ -# These variables are specifically meant to be overridable via the make -# command-line. -# ?= doesn't work for CC and AR because make has a default value for them. -ifeq ($(origin CC), default) -CC := clang -endif -NM ?= $(patsubst %clang,%llvm-nm,$(filter-out ccache sccache,$(CC))) -ifeq ($(origin AR), default) -AR = $(patsubst %clang,%llvm-ar,$(filter-out ccache sccache,$(CC))) -endif -ifeq ($(origin ARFLAGS), default) -# Use `--format=gnu` to generate identical archives regardless of the host. -ARFLAGS = --format=gnu crs -endif -ifeq ($(DEBUG), true) -EXTRA_CFLAGS ?= -O0 -g -else -EXTRA_CFLAGS ?= -O2 -DNDEBUG -endif -# The directory where we build the sysroot. -SYSROOT ?= $(CURDIR)/sysroot -# A directory to install to for "make install". -INSTALL_DIR ?= /usr/local -# single or posix; note that pthread support is still a work-in-progress. -THREAD_MODEL ?= single -# p1 or p2; the latter is not (yet) compatible with multithreading -WASI_SNAPSHOT ?= p1 -# dlmalloc or none -MALLOC_IMPL ?= dlmalloc -# yes or no -BUILD_LIBC_TOP_HALF ?= yes -# yes or no -BUILD_LIBSETJMP ?= yes - -# Set the default WASI target triple. -TARGET_TRIPLE ?= wasm32-wasi - -# Threaded version necessitates a different target, as objects from different -# targets can't be mixed together while linking. -ifeq ($(THREAD_MODEL), posix) -TARGET_TRIPLE = wasm32-wasip1-threads -endif - -ifeq ($(WASI_SNAPSHOT), p2) -TARGET_TRIPLE = wasm32-wasip2 -endif - -# The directory where we will store intermediate artifacts. -OBJDIR ?= build/$(TARGET_TRIPLE) - -# LTO; no, full, or thin -# Note: thin LTO here is just for experimentation. It has known issues: -# - https://github.com/llvm/llvm-project/issues/91700 -# - https://github.com/llvm/llvm-project/issues/91711 -LTO ?= no -ifneq ($(LTO),no) -CLANG_VERSION ?= $(shell ${CC} -dumpversion) -override OBJDIR := $(OBJDIR)/llvm-lto/$(CLANG_VERSION) -endif - -# When the length is no larger than this threshold, we consider the -# overhead of bulk memory opcodes to outweigh the performance benefit, -# and fall back to the original musl implementation. See -# https://github.com/WebAssembly/wasi-libc/pull/263 for relevant -# discussion -BULK_MEMORY_THRESHOLD ?= 32 - -# Variables from this point on are not meant to be overridable via the -# make command-line. - -# These artifacts are "stamps" that we use to mark that some task (e.g., copying -# files) has been completed. -INCLUDE_DIRS := $(OBJDIR)/copy-include-headers.stamp - -# These variables describe the locations of various files and directories in -# the source tree. -DLMALLOC_DIR = dlmalloc -DLMALLOC_SRC_DIR = $(DLMALLOC_DIR)/src -DLMALLOC_SOURCES = $(DLMALLOC_SRC_DIR)/dlmalloc.c -DLMALLOC_INC = $(DLMALLOC_DIR)/include -EMMALLOC_DIR = emmalloc -EMMALLOC_SOURCES = $(EMMALLOC_DIR)/emmalloc.c -THREAD_STUB_DIR = thread-stub -LIBC_BOTTOM_HALF_DIR = libc-bottom-half -LIBC_BOTTOM_HALF_CLOUDLIBC_SRC = $(LIBC_BOTTOM_HALF_DIR)/cloudlibc/src -LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC = $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/include -LIBC_BOTTOM_HALF_HEADERS_PUBLIC = $(LIBC_BOTTOM_HALF_DIR)/headers/public -LIBC_BOTTOM_HALF_HEADERS_PRIVATE = $(LIBC_BOTTOM_HALF_DIR)/headers/private -LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources -LIBC_BOTTOM_HALF_ALL_SOURCES = \ - $(sort \ - $(shell find $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) -name \*.c) \ - $(shell find $(LIBC_BOTTOM_HALF_SOURCES) -name \*.c)) - -ifeq ($(WASI_SNAPSHOT), p1) -# Omit source files not relevant to WASIp1. As we introduce files -# supporting `wasi-sockets` for `wasm32-wasip2`, we'll add those files to -# this list. -LIBC_BOTTOM_HALF_OMIT_SOURCES := \ - $(LIBC_BOTTOM_HALF_SOURCES)/wasip2.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/descriptor_table.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/connect.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/socket.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/send.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/recv.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/sockets_utils.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/bind.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/listen.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/accept-wasip2.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/shutdown.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/sockopt.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/poll-wasip2.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/getsockpeername.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/netdb.c -LIBC_BOTTOM_HALF_ALL_SOURCES := $(filter-out $(LIBC_BOTTOM_HALF_OMIT_SOURCES),$(LIBC_BOTTOM_HALF_ALL_SOURCES)) -# Omit p2-specific headers from include-all.c test. -# for exception-handling. -INCLUDE_ALL_CLAUSES := -not -name wasip2.h -not -name descriptor_table.h -endif - -ifeq ($(WASI_SNAPSHOT), p2) -# Omit source files not relevant to WASIp2. -LIBC_BOTTOM_HALF_OMIT_SOURCES := \ - $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/libc/sys/socket/send.c \ - $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/libc/sys/socket/recv.c \ - $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/libc/sys/socket/shutdown.c \ - $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/libc/sys/socket/getsockopt.c \ - $(LIBC_BOTTOM_HALF_SOURCES)/accept-wasip1.c -LIBC_BOTTOM_HALF_ALL_SOURCES := $(filter-out $(LIBC_BOTTOM_HALF_OMIT_SOURCES),$(LIBC_BOTTOM_HALF_ALL_SOURCES)) -endif - -# FIXME(https://reviews.llvm.org/D85567) - due to a bug in LLD the weak -# references to a function defined in `chdir.c` only work if `chdir.c` is at the -# end of the archive, but once that LLD review lands and propagates into LLVM -# then we don't have to do this. -LIBC_BOTTOM_HALF_ALL_SOURCES := $(filter-out $(LIBC_BOTTOM_HALF_SOURCES)/chdir.c,$(LIBC_BOTTOM_HALF_ALL_SOURCES)) -LIBC_BOTTOM_HALF_ALL_SOURCES := $(LIBC_BOTTOM_HALF_ALL_SOURCES) $(LIBC_BOTTOM_HALF_SOURCES)/chdir.c - -LIBWASI_EMULATED_MMAN_SOURCES = \ - $(sort $(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c)) -LIBWASI_EMULATED_PROCESS_CLOCKS_SOURCES = \ - $(sort $(shell find $(LIBC_BOTTOM_HALF_DIR)/clocks -name \*.c)) -LIBWASI_EMULATED_GETPID_SOURCES = \ - $(sort $(shell find $(LIBC_BOTTOM_HALF_DIR)/getpid -name \*.c)) -LIBWASI_EMULATED_SIGNAL_SOURCES = \ - $(sort $(shell find $(LIBC_BOTTOM_HALF_DIR)/signal -name \*.c)) -LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES = \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/signal/psignal.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/strsignal.c -LIBDL_SOURCES = $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/dl.c -LIBSETJMP_SOURCES = $(LIBC_TOP_HALF_MUSL_SRC_DIR)/setjmp/wasm32/rt.c -LIBC_BOTTOM_HALF_CRT_SOURCES = $(wildcard $(LIBC_BOTTOM_HALF_DIR)/crt/*.c) -LIBC_TOP_HALF_DIR = libc-top-half -LIBC_TOP_HALF_MUSL_DIR = $(LIBC_TOP_HALF_DIR)/musl -LIBC_TOP_HALF_MUSL_SRC_DIR = $(LIBC_TOP_HALF_MUSL_DIR)/src -LIBC_TOP_HALF_MUSL_INC = $(LIBC_TOP_HALF_MUSL_DIR)/include -LIBC_TOP_HALF_MUSL_SOURCES = \ - $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \ - misc/a64l.c \ - misc/basename.c \ - misc/dirname.c \ - misc/ffs.c \ - misc/ffsl.c \ - misc/ffsll.c \ - misc/fmtmsg.c \ - misc/getdomainname.c \ - misc/gethostid.c \ - misc/getopt.c \ - misc/getopt_long.c \ - misc/getsubopt.c \ - misc/realpath.c \ - misc/uname.c \ - misc/nftw.c \ - errno/strerror.c \ - network/htonl.c \ - network/htons.c \ - network/in6addr_any.c \ - network/in6addr_loopback.c \ - network/inet_addr.c \ - network/inet_aton.c \ - network/inet_legacy.c \ - network/inet_ntoa.c \ - network/inet_ntop.c \ - network/inet_pton.c \ - network/ntohl.c \ - network/ntohs.c \ - fenv/fenv.c \ - fenv/fesetround.c \ - fenv/feupdateenv.c \ - fenv/fesetexceptflag.c \ - fenv/fegetexceptflag.c \ - fenv/feholdexcept.c \ - exit/exit.c \ - exit/atexit.c \ - exit/assert.c \ - exit/quick_exit.c \ - exit/at_quick_exit.c \ - time/strftime.c \ - time/asctime.c \ - time/asctime_r.c \ - time/ctime.c \ - time/ctime_r.c \ - time/wcsftime.c \ - time/strptime.c \ - time/difftime.c \ - time/timegm.c \ - time/ftime.c \ - time/gmtime.c \ - time/gmtime_r.c \ - time/timespec_get.c \ - time/getdate.c \ - time/localtime.c \ - time/localtime_r.c \ - time/mktime.c \ - time/__tm_to_secs.c \ - time/__month_to_secs.c \ - time/__secs_to_tm.c \ - time/__year_to_secs.c \ - time/__tz.c \ - fcntl/creat.c \ - dirent/alphasort.c \ - dirent/versionsort.c \ - env/__stack_chk_fail.c \ - env/clearenv.c \ - env/getenv.c \ - env/putenv.c \ - env/setenv.c \ - env/unsetenv.c \ - unistd/posix_close.c \ - unistd/gethostname.c \ - stat/futimesat.c \ - legacy/getpagesize.c \ - thread/thrd_sleep.c \ - ) \ - $(filter-out %/procfdname.c %/syscall.c %/syscall_ret.c %/vdso.c %/version.c %/emulate_wait4.c, \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal/*.c)) \ - $(filter-out %/flockfile.c %/funlockfile.c %/__lockfile.c %/ftrylockfile.c \ - %/rename.c \ - %/tmpnam.c %/tmpfile.c %/tempnam.c \ - %/popen.c %/pclose.c \ - %/remove.c \ - %/gets.c, \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdio/*.c)) \ - $(filter-out %/strsignal.c, \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/*.c)) \ - $(filter-out %/dcngettext.c %/textdomain.c %/bind_textdomain_codeset.c, \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/locale/*.c)) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdlib/*.c) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/search/*.c) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/multibyte/*.c) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/regex/*.c) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/prng/*.c) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/conf/*.c) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/ctype/*.c) \ - $(filter-out %/__signbit.c %/__signbitf.c %/__signbitl.c \ - %/__fpclassify.c %/__fpclassifyf.c %/__fpclassifyl.c \ - %/ceilf.c %/ceil.c \ - %/floorf.c %/floor.c \ - %/truncf.c %/trunc.c \ - %/rintf.c %/rint.c \ - %/nearbyintf.c %/nearbyint.c \ - %/sqrtf.c %/sqrt.c \ - %/fabsf.c %/fabs.c \ - %/copysignf.c %/copysign.c \ - %/fminf.c %/fmaxf.c \ - %/fmin.c %/fmax.c, \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/math/*.c)) \ - $(filter-out %/crealf.c %/creal.c %creall.c \ - %/cimagf.c %/cimag.c %cimagl.c, \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/complex/*.c)) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/crypt/*.c) - -LIBC_NONLTO_SOURCES = \ - $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \ - exit/atexit.c \ - setjmp/wasm32/rt.c \ - ) - -ifeq ($(WASI_SNAPSHOT), p2) -LIBC_TOP_HALF_MUSL_SOURCES += \ - $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \ - network/gai_strerror.c \ - ) -endif - -# pthreads functions (possibly stub) for either thread model -LIBC_TOP_HALF_MUSL_SOURCES += \ - $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \ - env/__init_tls.c \ - thread/default_attr.c \ - thread/pthread_attr_destroy.c \ - thread/pthread_attr_get.c \ - thread/pthread_attr_init.c \ - thread/pthread_attr_setdetachstate.c \ - thread/pthread_attr_setguardsize.c \ - thread/pthread_attr_setschedparam.c \ - thread/pthread_attr_setstack.c \ - thread/pthread_attr_setstacksize.c \ - thread/pthread_barrierattr_destroy.c \ - thread/pthread_barrierattr_init.c \ - thread/pthread_barrierattr_setpshared.c \ - thread/pthread_cancel.c \ - thread/pthread_cleanup_push.c \ - thread/pthread_condattr_destroy.c \ - thread/pthread_condattr_init.c \ - thread/pthread_condattr_setclock.c \ - thread/pthread_condattr_setpshared.c \ - thread/pthread_equal.c \ - thread/pthread_getattr_np.c \ - thread/pthread_getspecific.c \ - thread/pthread_key_create.c \ - thread/pthread_mutex_destroy.c \ - thread/pthread_mutex_init.c \ - thread/pthread_mutexattr_destroy.c \ - thread/pthread_mutexattr_init.c \ - thread/pthread_mutexattr_setprotocol.c \ - thread/pthread_mutexattr_setpshared.c \ - thread/pthread_mutexattr_setrobust.c \ - thread/pthread_mutexattr_settype.c \ - thread/pthread_rwlock_destroy.c \ - thread/pthread_rwlock_init.c \ - thread/pthread_rwlockattr_destroy.c \ - thread/pthread_rwlockattr_init.c \ - thread/pthread_rwlockattr_setpshared.c \ - thread/pthread_self.c \ - thread/pthread_setcancelstate.c \ - thread/pthread_setcanceltype.c \ - thread/pthread_setspecific.c \ - thread/pthread_spin_destroy.c \ - thread/pthread_spin_init.c \ - thread/pthread_testcancel.c \ - ) -ifeq ($(THREAD_MODEL), posix) -# pthreads functions needed for actual thread support -LIBC_TOP_HALF_MUSL_SOURCES += \ - $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \ - stdio/__lockfile.c \ - stdio/flockfile.c \ - stdio/ftrylockfile.c \ - stdio/funlockfile.c \ - thread/__lock.c \ - thread/__wait.c \ - thread/__timedwait.c \ - thread/pthread_barrier_destroy.c \ - thread/pthread_barrier_init.c \ - thread/pthread_barrier_wait.c \ - thread/pthread_cond_broadcast.c \ - thread/pthread_cond_destroy.c \ - thread/pthread_cond_init.c \ - thread/pthread_cond_signal.c \ - thread/pthread_cond_timedwait.c \ - thread/pthread_cond_wait.c \ - thread/pthread_create.c \ - thread/pthread_detach.c \ - thread/pthread_join.c \ - thread/pthread_mutex_consistent.c \ - thread/pthread_mutex_getprioceiling.c \ - thread/pthread_mutex_lock.c \ - thread/pthread_mutex_timedlock.c \ - thread/pthread_mutex_trylock.c \ - thread/pthread_mutex_unlock.c \ - thread/pthread_once.c \ - thread/pthread_rwlock_rdlock.c \ - thread/pthread_rwlock_timedrdlock.c \ - thread/pthread_rwlock_timedwrlock.c \ - thread/pthread_rwlock_tryrdlock.c \ - thread/pthread_rwlock_trywrlock.c \ - thread/pthread_rwlock_unlock.c \ - thread/pthread_rwlock_wrlock.c \ - thread/pthread_spin_lock.c \ - thread/pthread_spin_trylock.c \ - thread/pthread_spin_unlock.c \ - thread/sem_destroy.c \ - thread/sem_getvalue.c \ - thread/sem_init.c \ - thread/sem_post.c \ - thread/sem_timedwait.c \ - thread/sem_trywait.c \ - thread/sem_wait.c \ - thread/wasm32/wasi_thread_start.s \ - thread/wasm32/__wasilibc_busywait.c \ - ) -endif -ifeq ($(THREAD_MODEL), single) -# pthreads stubs for single-threaded environment -LIBC_TOP_HALF_MUSL_SOURCES += \ - $(addprefix $(THREAD_STUB_DIR)/, \ - pthread_barrier_destroy.c \ - pthread_barrier_init.c \ - pthread_barrier_wait.c \ - pthread_cond_broadcast.c \ - pthread_cond_destroy.c \ - pthread_cond_init.c \ - pthread_cond_signal.c \ - pthread_cond_timedwait.c \ - pthread_cond_wait.c \ - pthread_create.c \ - pthread_detach.c \ - pthread_join.c \ - pthread_mutex_consistent.c \ - pthread_mutex_getprioceiling.c \ - pthread_mutex_lock.c \ - pthread_mutex_timedlock.c \ - pthread_mutex_trylock.c \ - pthread_mutex_unlock.c \ - pthread_once.c \ - pthread_rwlock_rdlock.c \ - pthread_rwlock_timedrdlock.c \ - pthread_rwlock_timedwrlock.c \ - pthread_rwlock_tryrdlock.c \ - pthread_rwlock_trywrlock.c \ - pthread_rwlock_unlock.c \ - pthread_rwlock_wrlock.c \ - pthread_spin_lock.c \ - pthread_spin_trylock.c \ - pthread_spin_unlock.c \ - ) -endif - -MUSL_PRINTSCAN_SOURCES = \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal/floatscan.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdio/vfprintf.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdio/vfwprintf.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdio/vfscanf.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdlib/strtod.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdlib/wcstod.c -BULK_MEMORY_SOURCES = \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memcpy.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memmove.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memset.c -LIBC_TOP_HALF_HEADERS_PRIVATE = $(LIBC_TOP_HALF_DIR)/headers/private -LIBC_TOP_HALF_SOURCES = $(LIBC_TOP_HALF_DIR)/sources -LIBC_TOP_HALF_ALL_SOURCES = \ - $(LIBC_TOP_HALF_MUSL_SOURCES) \ - $(sort $(shell find $(LIBC_TOP_HALF_SOURCES) -name \*.[cs])) - -FTS_SRC_DIR = fts -MUSL_FTS_SRC_DIR = $(FTS_SRC_DIR)/musl-fts -FTS_SOURCES = $(MUSL_FTS_SRC_DIR)/fts.c - -# Add any extra flags -CFLAGS = $(EXTRA_CFLAGS) -# Set the target. -CFLAGS += --target=$(TARGET_TRIPLE) -ASMFLAGS += --target=$(TARGET_TRIPLE) -# WebAssembly floating-point match doesn't trap. -# TODO: Add -fno-signaling-nans when the compiler supports it. -CFLAGS += -fno-trapping-math -# Add all warnings, but disable a few which occur in third-party code. -CFLAGS += -Wall -Wextra -Werror \ - -Wno-null-pointer-arithmetic \ - -Wno-unused-parameter \ - -Wno-sign-compare \ - -Wno-unused-variable \ - -Wno-unused-function \ - -Wno-ignored-attributes \ - -Wno-missing-braces \ - -Wno-ignored-pragmas \ - -Wno-unused-but-set-variable \ - -Wno-unknown-warning-option \ - -Wno-unterminated-string-initialization - -# Configure support for threads. -ifeq ($(THREAD_MODEL), single) -CFLAGS += -mthread-model single -endif -ifeq ($(THREAD_MODEL), posix) -# Specify the tls-model until LLVM 15 is released (which should contain -# https://reviews.llvm.org/D130053). -CFLAGS += -mthread-model posix -pthread -ftls-model=local-exec -ASMFLAGS += -matomics -endif - -# Include cloudlib's directory to access the structure definition of clockid_t -CFLAGS += -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) - -ifneq ($(LTO),no) -ifeq ($(LTO),full) -CFLAGS += -flto=full -else -ifeq ($(LTO),thin) -CFLAGS += -flto=thin -else -$(error unknown LTO value: $(LTO)) -endif -endif -endif - -ifeq ($(WASI_SNAPSHOT), p2) -CFLAGS += -D__wasilibc_use_wasip2 -endif - -# Expose the public headers to the implementation. We use `-isystem` for -# purpose for two reasons: -# -# 1. It only does `<...>` not `"...."` lookup. We are making a libc, -# which is a system library, so all public headers should be -# accessible via `<...>` and never also need `"..."`. `-isystem` main -# purpose is to only effect `<...>` lookup. -# -# 2. The `-I` for private headers added for specific C files below -# should come earlier in the search path, so they can "override" -# and/or `#include_next` the public headers. `-isystem` (like -# `-idirafter`) comes later in the search path than `-I`. -CFLAGS += -isystem "$(SYSROOT_INC)" - -# These variables describe the locations of various files and directories in -# the build tree. -objs = $(patsubst %.c,$(OBJDIR)/%.o,$(1)) -asmobjs = $(patsubst %.s,$(OBJDIR)/%.o,$(1)) -DLMALLOC_OBJS = $(call objs,$(DLMALLOC_SOURCES)) -EMMALLOC_OBJS = $(call objs,$(EMMALLOC_SOURCES)) -LIBC_BOTTOM_HALF_ALL_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_ALL_SOURCES)) -LIBC_TOP_HALF_ALL_OBJS = $(call asmobjs,$(call objs,$(LIBC_TOP_HALF_ALL_SOURCES))) -FTS_OBJS = $(call objs,$(FTS_SOURCES)) -ifeq ($(WASI_SNAPSHOT), p2) -LIBC_OBJS += $(OBJDIR)/wasip2_component_type.o -endif -ifeq ($(MALLOC_IMPL),dlmalloc) -LIBC_OBJS += $(DLMALLOC_OBJS) -else ifeq ($(MALLOC_IMPL),emmalloc) -LIBC_OBJS += $(EMMALLOC_OBJS) -else ifeq ($(MALLOC_IMPL),none) -# No object files to add. -else -$(error unknown malloc implementation $(MALLOC_IMPL)) -endif -# Add libc-bottom-half's objects. -LIBC_OBJS += $(LIBC_BOTTOM_HALF_ALL_OBJS) -ifeq ($(BUILD_LIBC_TOP_HALF),yes) -# libc-top-half is musl. -LIBC_OBJS += $(LIBC_TOP_HALF_ALL_OBJS) -endif -LIBC_OBJS += $(FTS_OBJS) -MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES)) -MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS)) -MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS)) -BULK_MEMORY_OBJS = $(call objs,$(BULK_MEMORY_SOURCES)) -LIBWASI_EMULATED_MMAN_OBJS = $(call objs,$(LIBWASI_EMULATED_MMAN_SOURCES)) -LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS = $(call objs,$(LIBWASI_EMULATED_PROCESS_CLOCKS_SOURCES)) -LIBWASI_EMULATED_GETPID_OBJS = $(call objs,$(LIBWASI_EMULATED_GETPID_SOURCES)) -LIBWASI_EMULATED_SIGNAL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_SOURCES)) -LIBWASI_EMULATED_SIGNAL_MUSL_OBJS = $(call objs,$(LIBWASI_EMULATED_SIGNAL_MUSL_SOURCES)) -LIBDL_OBJS = $(call objs,$(LIBDL_SOURCES)) -LIBSETJMP_OBJS = $(call objs,$(LIBSETJMP_SOURCES)) -LIBC_BOTTOM_HALF_CRT_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_CRT_SOURCES)) -LIBC_NONLTO_OBJS = $(call objs,$(LIBC_NONLTO_SOURCES)) - -# These variables describe the locations of various files and -# directories in the generated sysroot tree. -SYSROOT_LIB := $(SYSROOT)/lib/$(TARGET_TRIPLE) -ifneq ($(LTO),no) -override SYSROOT_LIB := $(SYSROOT_LIB)/llvm-lto/$(CLANG_VERSION) -endif -SYSROOT_INC = $(SYSROOT)/include/$(TARGET_TRIPLE) -SYSROOT_SHARE = $(SYSROOT)/share/$(TARGET_TRIPLE) - -default: finish - -LIBC_SO_OBJS = $(patsubst %.o,%.pic.o,$(filter-out $(MUSL_PRINTSCAN_OBJS),$(LIBC_OBJS))) -MUSL_PRINTSCAN_LONG_DOUBLE_SO_OBJS = $(patsubst %.o,%.pic.o,$(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS)) -LIBWASI_EMULATED_MMAN_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_MMAN_OBJS)) -LIBWASI_EMULATED_PROCESS_CLOCKS_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS)) -LIBWASI_EMULATED_GETPID_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_GETPID_OBJS)) -LIBWASI_EMULATED_SIGNAL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_SIGNAL_OBJS)) -LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS)) -LIBDL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBDL_OBJS)) -LIBSETJMP_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBSETJMP_OBJS)) -BULK_MEMORY_SO_OBJS = $(patsubst %.o,%.pic.o,$(BULK_MEMORY_OBJS)) -DLMALLOC_SO_OBJS = $(patsubst %.o,%.pic.o,$(DLMALLOC_OBJS)) -LIBC_BOTTOM_HALF_ALL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBC_BOTTOM_HALF_ALL_OBJS)) -LIBC_TOP_HALF_ALL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBC_TOP_HALF_ALL_OBJS)) -FTS_SO_OBJS = $(patsubst %.o,%.pic.o,$(FTS_OBJS)) - -PIC_OBJS = \ - $(LIBC_SO_OBJS) \ - $(MUSL_PRINTSCAN_LONG_DOUBLE_SO_OBJS) \ - $(LIBWASI_EMULATED_MMAN_SO_OBJS) \ - $(LIBWASI_EMULATED_PROCESS_CLOCKS_SO_OBJS) \ - $(LIBWASI_EMULATED_GETPID_SO_OBJS) \ - $(LIBWASI_EMULATED_SIGNAL_SO_OBJS) \ - $(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS) \ - $(LIBDL_SO_OBJS) \ - $(LIBSETJMP_SO_OBJS) \ - $(BULK_MEMORY_SO_OBJS) \ - $(DLMALLOC_SO_OBJS) \ - $(LIBC_BOTTOM_HALF_ALL_SO_OBJS) \ - $(LIBC_TOP_HALF_ALL_SO_OBJS) \ - $(LIBC_BOTTOM_HALF_CRT_OBJS) \ - $(FTS_SO_OBJS) - -# Figure out what to do about compiler-rt. -# -# The compiler-rt library is not built here in the wasi-libc repository, but it -# is required to link artifacts. Notably `libc.so` and test and such all require -# it to exist. Currently the ways this is handled are: -# -# * If `BUILTINS_LIB` is defined at build time then that's assumed to be a path -# to the libcompiler-rt.a. That's then ingested into the build here and copied -# around to special locations to get the `*.so` rules below to work (see docs -# there). -# -# * If `BUILTINS_LIB` is not defined then a known-good copy is downloaded from -# wasi-sdk CI and used instead. -# -# In the future this may also want some form of configuration to support -# assuming the system compiler has a compiler-rt, e.g. if $(SYSTEM_BUILTINS_LIB) -# exists that should be used instead. -SYSTEM_BUILTINS_LIB := $(shell ${CC} ${CFLAGS} --print-libgcc-file-name) -SYSTEM_RESOURCE_DIR := $(shell ${CC} ${CFLAGS} -print-resource-dir) -BUILTINS_LIB_REL_1 := $(subst $(SYSTEM_RESOURCE_DIR),,$(SYSTEM_BUILTINS_LIB)) -# Substitute '/' for '\' so Windows paths work -BUILTINS_LIB_REL := $(subst \,/,$(BUILTINS_LIB_REL_1)) -TMP_RESOURCE_DIR := $(OBJDIR)/resource-dir -BUILTINS_LIB_PATH := $(TMP_RESOURCE_DIR)/$(BUILTINS_LIB_REL) -BUILTINS_LIB_DIR := $(dir $(BUILTINS_LIB_PATH)) - -ifneq ($(BUILTINS_LIB),) -$(BUILTINS_LIB_PATH): $(BUILTINS_LIB) - mkdir -p $(BUILTINS_LIB_DIR) - cp $(BUILTINS_LIB) $(BUILTINS_LIB_PATH) -else - -BUILTINS_URL := https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/libclang_rt.builtins-wasm32-wasi-25.0.tar.gz - -$(BUILTINS_LIB_PATH): -# mkdir on Windows will error if the directory already exists -ifeq ("$(wildcard $(BUILTINS_LIB_DIR))","") - mkdir -p "$(BUILTINS_LIB_DIR)" -endif - curl -sSfL $(BUILTINS_URL) | \ - tar xzf - -C $(BUILTINS_LIB_DIR) --strip-components 1 - if [ ! -f $(BUILTINS_LIB_PATH) ]; then \ - mv $(BUILTINS_LIB_DIR)/*.a $(BUILTINS_LIB_PATH); \ - fi -endif - -builtins: $(BUILTINS_LIB_PATH) - -# TODO: Specify SDK version, e.g. libc.so.wasi-sdk-21, as SO_NAME once `wasm-ld` -# supports it. -# -# Note that we collect the object files for each shared library into a .a and -# link that using `--whole-archive` rather than pass the object files directly -# to CC. This is a workaround for a Windows command line size limitation. See -# the `%.a` rule below for details. - -# Note: libc.so is special because it shouldn't link to libc.so, and the -# -nodefaultlibs flag here disables the default `-lc` logic that clang -# has. Note though that this also disables linking of compiler-rt -# libraries so that is explicitly passed in via `$(BUILTINS_LIB_PATH)` -# -# Note: --allow-undefined-file=linker-provided-symbols.txt is -# a workaround for https://github.com/llvm/llvm-project/issues/103592 -$(SYSROOT_LIB)/libc.so: $(OBJDIR)/libc.so.a $(BUILTINS_LIB_PATH) - $(CC) --target=${TARGET_TRIPLE} -nodefaultlibs \ - -shared --sysroot=$(SYSROOT) \ - -o $@ -Wl,--whole-archive $< -Wl,--no-whole-archive \ - -Wl,--allow-undefined-file=linker-provided-symbols.txt \ - $(BUILTINS_LIB_PATH) \ - $(EXTRA_CFLAGS) $(LDFLAGS) - -# Note that unlike `libc.so` above this rule does not pass `-nodefaultlibs` -# which means that libc will be linked by default. Additionally clang will try -# to find, locate, and link compiler-rt. To get compiler-rt to work a -# `-resource-dir` argument is passed to ensure that our custom -# `TMP_RESOURCE_DIR` built here locally is used instead of the system directory -# which may or may not already have compiler-rt. -$(SYSROOT_LIB)/%.so: $(OBJDIR)/%.so.a $(SYSROOT_LIB)/libc.so - $(CC) --target=${TARGET_TRIPLE} \ - -shared --sysroot=$(SYSROOT) \ - -o $@ -Wl,--whole-archive $< -Wl,--no-whole-archive \ - -Wl,--allow-undefined-file=linker-provided-symbols.txt \ - -resource-dir $(TMP_RESOURCE_DIR) \ - $(EXTRA_CFLAGS) $(LDFLAGS) - -$(OBJDIR)/libc.so.a: $(LIBC_SO_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_SO_OBJS) - -$(OBJDIR)/libwasi-emulated-mman.so.a: $(LIBWASI_EMULATED_MMAN_SO_OBJS) - -$(OBJDIR)/libwasi-emulated-process-clocks.so.a: $(LIBWASI_EMULATED_PROCESS_CLOCKS_SO_OBJS) - -$(OBJDIR)/libwasi-emulated-getpid.so.a: $(LIBWASI_EMULATED_GETPID_SO_OBJS) - -$(OBJDIR)/libwasi-emulated-signal.so.a: $(LIBWASI_EMULATED_SIGNAL_SO_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS) - -$(OBJDIR)/libdl.so.a: $(LIBDL_SO_OBJS) - -$(OBJDIR)/libsetjmp.so.a: $(LIBSETJMP_SO_OBJS) - -$(SYSROOT_LIB)/libc.a: $(LIBC_OBJS) - -$(SYSROOT_LIB)/libc-printscan-long-double.a: $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) - -$(SYSROOT_LIB)/libc-printscan-no-floating-point.a: $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS) - -$(SYSROOT_LIB)/libwasi-emulated-mman.a: $(LIBWASI_EMULATED_MMAN_OBJS) - -$(SYSROOT_LIB)/libwasi-emulated-process-clocks.a: $(LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS) - -$(SYSROOT_LIB)/libwasi-emulated-getpid.a: $(LIBWASI_EMULATED_GETPID_OBJS) - -$(SYSROOT_LIB)/libwasi-emulated-signal.a: $(LIBWASI_EMULATED_SIGNAL_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS) - -$(SYSROOT_LIB)/libdl.a: $(LIBDL_OBJS) - -$(SYSROOT_LIB)/libsetjmp.a: $(LIBSETJMP_OBJS) - -%.a: - @mkdir -p "$(@D)" - # On Windows, the commandline for the ar invocation got too long, so it needs to be split up. - $(AR) $(ARFLAGS) $@ $(wordlist 1, 199, $(sort $^)) - $(AR) $(ARFLAGS) $@ $(wordlist 200, 399, $(sort $^)) - $(AR) $(ARFLAGS) $@ $(wordlist 400, 599, $(sort $^)) - $(AR) $(ARFLAGS) $@ $(wordlist 600, 799, $(sort $^)) - # This might eventually overflow again, but at least it'll do so in a loud way instead of - # silently dropping the tail. - $(AR) $(ARFLAGS) $@ $(wordlist 800, 100000, $(sort $^)) - -$(PIC_OBJS): CFLAGS += -fPIC -fvisibility=default - -$(LIBC_NONLTO_OBJS): CFLAGS := $(filter-out -flto% -fno-lto, $(CFLAGS)) -fno-lto - -$(MUSL_PRINTSCAN_OBJS): CFLAGS += \ - -D__wasilibc_printscan_no_long_double \ - -D__wasilibc_printscan_full_support_option="\"add -lc-printscan-long-double to the link command\"" - -$(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): CFLAGS += \ - -D__wasilibc_printscan_no_floating_point \ - -D__wasilibc_printscan_floating_point_support_option="\"remove -lc-printscan-no-floating-point from the link command\"" - -# TODO: apply -mbulk-memory globally, once -# https://github.com/llvm/llvm-project/issues/52618 is resolved -$(BULK_MEMORY_OBJS) $(BULK_MEMORY_SO_OBJS): CFLAGS += \ - -mbulk-memory - -$(BULK_MEMORY_OBJS) $(BULK_MEMORY_SO_OBJS): CFLAGS += \ - -DBULK_MEMORY_THRESHOLD=$(BULK_MEMORY_THRESHOLD) - -$(LIBSETJMP_OBJS) $(LIBSETJMP_SO_OBJS): CFLAGS += \ - -mllvm -wasm-enable-sjlj - -$(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS): CFLAGS += \ - -D_WASI_EMULATED_SIGNAL - -$(OBJDIR)/%.long-double.pic.o: %.c $(INCLUDE_DIRS) - @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -MD -MP -o $@ -c $< - -$(OBJDIR)/wasip2_component_type.pic.o $(OBJDIR)/wasip2_component_type.o: $(LIBC_BOTTOM_HALF_SOURCES)/wasip2_component_type.o - @mkdir -p "$(@D)" - cp $< $@ - -$(OBJDIR)/%.pic.o: %.c $(INCLUDE_DIRS) - @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -MD -MP -o $@ -c $< - -$(OBJDIR)/%.long-double.o: %.c $(INCLUDE_DIRS) - @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -MD -MP -o $@ -c $< - -$(OBJDIR)/%.no-floating-point.o: %.c $(INCLUDE_DIRS) - @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -MD -MP -o $@ -c $< - -$(OBJDIR)/%.o: %.c $(INCLUDE_DIRS) - @mkdir -p "$(@D)" - $(CC) $(CFLAGS) -MD -MP -o $@ -c $< - -$(OBJDIR)/%.o: %.s $(INCLUDE_DIRS) - @mkdir -p "$(@D)" - $(CC) $(ASMFLAGS) -o $@ -c $< - --include $(shell find $(OBJDIR) -name \*.d) - -$(DLMALLOC_OBJS) $(DLMALLOC_SO_OBJS): CFLAGS += \ - -I$(DLMALLOC_INC) - -$(STARTUP_FILES) $(LIBC_BOTTOM_HALF_ALL_OBJS) $(LIBC_BOTTOM_HALF_ALL_SO_OBJS): CFLAGS += \ - -I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \ - -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \ - -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) \ - -I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/include \ - -I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal - -$(LIBC_TOP_HALF_ALL_OBJS) $(LIBC_TOP_HALF_ALL_SO_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_SO_OBJS) $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS) $(LIBDL_OBJS) $(LIBDL_SO_OBJS) $(LIBSETJMP_OBJS) $(LIBSETJMP_SO_OBJS): CFLAGS += \ - -I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/include \ - -I$(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal \ - -I$(LIBC_TOP_HALF_MUSL_DIR)/arch/wasm32 \ - -I$(LIBC_TOP_HALF_MUSL_DIR)/arch/generic \ - -I$(LIBC_TOP_HALF_HEADERS_PRIVATE) \ - -Wno-parentheses \ - -Wno-shift-op-parentheses \ - -Wno-bitwise-op-parentheses \ - -Wno-logical-op-parentheses \ - -Wno-string-plus-int \ - -Wno-dangling-else \ - -Wno-unknown-pragmas - -$(FTS_OBJS) $(FTS_SO_OBJS): CFLAGS += \ - -I$(MUSL_FTS_SRC_DIR) \ - -I$(FTS_SRC_DIR) # for config.h - -$(LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS) $(LIBWASI_EMULATED_PROCESS_CLOCKS_SO_OBJS): CFLAGS += \ - -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) - -# emmalloc uses a lot of pointer type-punning, which is UB under strict aliasing, -# and this was found to have real miscompilations in wasi-libc#421. -$(EMMALLOC_OBJS): CFLAGS += \ - -fno-strict-aliasing - -ALL_POSSIBLE_HEADERS += $(shell find $(LIBC_TOP_HALF_MUSL_DIR) -name \*.h) -ALL_POSSIBLE_HEADERS += $(shell find $(LIBC_BOTTOM_HALF_HEADERS_PUBLIC) -name \*.h) -ALL_POSSIBLE_HEADERS += $(shell find $(MUSL_FTS_SRC_DIR) -name \*.h) -$(INCLUDE_DIRS): $(ALL_POSSIBLE_HEADERS) - # - # Install the include files. - # - SYSROOT_INC=$(SYSROOT_INC) TARGET_TRIPLE=$(TARGET_TRIPLE) \ - $(CURDIR)/scripts/install-include-headers.sh - # Stamp the include installation. - @mkdir -p $(@D) - touch $@ - -STARTUP_FILES := $(OBJDIR)/copy-startup-files.stamp -$(STARTUP_FILES): $(INCLUDE_DIRS) $(LIBC_BOTTOM_HALF_CRT_OBJS) - # - # Install the startup files (crt1.o, etc.). - # - mkdir -p "$(SYSROOT_LIB)" - cp $(LIBC_BOTTOM_HALF_CRT_OBJS) "$(SYSROOT_LIB)" - - # Stamp the startup file installation. - @mkdir -p $(@D) - touch $@ - -startup_files: $(STARTUP_FILES) - -# TODO: As of this writing, wasi_thread_start.s uses non-position-independent -# code, and I'm not sure how to make it position-independent. Once we've done -# that, we can enable libc.so for the wasi-threads build. -ifneq ($(THREAD_MODEL), posix) -LIBC_SO = \ - $(SYSROOT_LIB)/libc.so \ - $(SYSROOT_LIB)/libwasi-emulated-mman.so \ - $(SYSROOT_LIB)/libwasi-emulated-process-clocks.so \ - $(SYSROOT_LIB)/libwasi-emulated-getpid.so \ - $(SYSROOT_LIB)/libwasi-emulated-signal.so \ - $(SYSROOT_LIB)/libdl.so -ifeq ($(BUILD_LIBSETJMP),yes) -LIBC_SO += \ - $(SYSROOT_LIB)/libsetjmp.so -endif -endif - -libc_so: $(INCLUDE_DIRS) $(LIBC_SO) - -STATIC_LIBS = \ - $(SYSROOT_LIB)/libc.a \ - $(SYSROOT_LIB)/libc-printscan-long-double.a \ - $(SYSROOT_LIB)/libc-printscan-no-floating-point.a \ - $(SYSROOT_LIB)/libwasi-emulated-mman.a \ - $(SYSROOT_LIB)/libwasi-emulated-process-clocks.a \ - $(SYSROOT_LIB)/libwasi-emulated-getpid.a \ - $(SYSROOT_LIB)/libwasi-emulated-signal.a \ - $(SYSROOT_LIB)/libdl.a -ifeq ($(BUILD_LIBSETJMP),yes) -STATIC_LIBS += \ - $(SYSROOT_LIB)/libsetjmp.a -endif - -libc: $(INCLUDE_DIRS) $(STATIC_LIBS) builtins - -DUMMY := m rt pthread crypt util xnet resolv -DUMMY_LIBS := $(patsubst %,$(SYSROOT_LIB)/lib%.a,$(DUMMY)) -$(DUMMY_LIBS): - # - # Create empty placeholder libraries. - # - mkdir -p "$(SYSROOT_LIB)" - for lib in $@; do \ - $(AR) $(ARFLAGS) "$$lib"; \ - done - -no-check-symbols: $(STARTUP_FILES) libc $(DUMMY_LIBS) - # - # The build succeeded! The generated sysroot is in $(SYSROOT). - # - -finish: no-check-symbols - -ifeq ($(CHECK_SYMBOLS),yes) -finish: check-symbols -endif - -install: finish - mkdir -p "$(INSTALL_DIR)" - cp -p -r "$(SYSROOT)/lib" "$(SYSROOT)/share" "$(SYSROOT)/include" "$(INSTALL_DIR)" - -DEFINED_SYMBOLS = $(SYSROOT_SHARE)/defined-symbols.txt -UNDEFINED_SYMBOLS = $(SYSROOT_SHARE)/undefined-symbols.txt - -ifeq ($(WASI_SNAPSHOT),p2) -EXPECTED_TARGET_DIR = expected/wasm32-wasip2 -else -ifeq ($(THREAD_MODEL),posix) -EXPECTED_TARGET_DIR = expected/wasm32-wasip1-threads -else -EXPECTED_TARGET_DIR = expected/wasm32-wasip1 -endif -endif - - -check-symbols: $(STARTUP_FILES) libc - # - # Collect metadata on the sysroot and perform sanity checks. - # - mkdir -p "$(SYSROOT_SHARE)" - - # - # Collect symbol information. - # - @# TODO: Use llvm-nm --extern-only instead of grep. This is blocked on - @# LLVM PR40497, which is fixed in 9.0, but not in 8.0. - @# Ignore certain llvm builtin symbols such as those starting with __mul - @# since these dependencies can vary between llvm versions. - "$(NM)" --defined-only "$(SYSROOT_LIB)"/libc.a "$(SYSROOT_LIB)"/libwasi-emulated-*.a "$(SYSROOT_LIB)"/*.o \ - |grep ' [[:upper:]] ' |sed 's/.* [[:upper:]] //' |LC_ALL=C sort |uniq > "$(DEFINED_SYMBOLS)" - for undef_sym in $$("$(NM)" --undefined-only "$(SYSROOT_LIB)"/libc.a "$(SYSROOT_LIB)"/libc-*.a "$(SYSROOT_LIB)"/*.o \ - |grep ' U ' |sed 's/.* U //' |LC_ALL=C sort |uniq); do \ - grep -q '\<'$$undef_sym'\>' "$(DEFINED_SYMBOLS)" || echo $$undef_sym; \ - done | grep -E -v "^__mul|__memory_base|__indirect_function_table|__tls_base" > "$(UNDEFINED_SYMBOLS)" -ifneq ($(WASI_SNAPSHOT), p2) - grep '^_*imported_wasi_' "$(UNDEFINED_SYMBOLS)" \ - > "$(SYSROOT_LIB)/libc.imports" -endif - - # - # Generate a test file that includes all public C header files. - # - # setjmp.h is excluded because it requires a different compiler option - # - cd "$(SYSROOT_INC)" && \ - for header in $$(find . -type f -not -name mman.h -not -name signal.h -not -name times.h -not -name resource.h -not -name setjmp.h $(INCLUDE_ALL_CLAUSES) |grep -v /bits/ |grep -v /c++/); do \ - echo '#include <'$$header'>' | sed 's/\.\///' ; \ - done |LC_ALL=C sort >$(SYSROOT_SHARE)/include-all.c ; \ - cd - >/dev/null - - # - # Test that it compiles. - # - $(CC) $(CFLAGS) -fsyntax-only "$(SYSROOT_SHARE)/include-all.c" -Wno-\#warnings - - # - # Collect all the predefined macros, except for compiler version macros - # which we don't need to track here. - # - @# - @# For the __*_ATOMIC_*_LOCK_FREE macros, squash individual compiler names - @# to attempt, toward keeping these files compiler-independent. - @# - @# We have to add `-isystem $(SYSROOT_INC)` because otherwise clang puts - @# its builtin include path first, which produces compiler-specific - @# output. - @# - @# TODO: Filter out __NO_MATH_ERRNO_ and a few __*WIDTH__ that are new to clang 14. - @# TODO: Filter out __GCC_HAVE_SYNC_COMPARE_AND_SWAP_* that are new to clang 16. - @# TODO: Filter out __FPCLASS_* that are new to clang 17. - @# TODO: Filter out __FLT128_* that are new to clang 18. - @# TODO: Filter out __MEMORY_SCOPE_* that are new to clang 18. - @# TODO: Filter out __GCC_(CON|DE)STRUCTIVE_SIZE that are new to clang 19. - @# TODO: Filter out __STDC_EMBED_* that are new to clang 19. - @# TODO: Filter out __*_NORM_MAX__ that are new to clang 19. - @# TODO: Filter out __INT*_C() that are new to clang 20. - @# TODO: clang defined __FLT_EVAL_METHOD__ until clang 15, so we force-undefine it - @# for older versions. - @# TODO: Undefine __wasm_mutable_globals__ and __wasm_sign_ext__, that are new to - @# clang 16 for -mcpu=generic. - @# TODO: Undefine __wasm_multivalue__ and __wasm_reference_types__, that are new to - @# clang 19 for -mcpu=generic. - @# TODO: Undefine __wasm_nontrapping_fptoint__, __wasm_bulk_memory__ and - @# __wasm_bulk_memory_opt__, that are new to clang 20. - @# TODO: As of clang 16, __GNUC_VA_LIST is #defined without a value. - $(CC) $(CFLAGS) "$(SYSROOT_SHARE)/include-all.c" \ - -isystem $(SYSROOT_INC) \ - -std=gnu17 \ - -E -dM -Wno-\#warnings \ - -D_ALL_SOURCE \ - -U__llvm__ \ - -U__clang__ \ - -U__clang_major__ \ - -U__clang_minor__ \ - -U__clang_patchlevel__ \ - -U__clang_version__ \ - -U__clang_literal_encoding__ \ - -U__clang_wide_literal_encoding__ \ - -U__wasm_extended_const__ \ - -U__wasm_mutable_globals__ \ - -U__wasm_sign_ext__ \ - -U__wasm_multivalue__ \ - -U__wasm_reference_types__ \ - -U__wasm_nontrapping_fptoint__ \ - $(if $(filter-out expected/wasm32-wasip1-threads,$(EXPECTED_TARGET_DIR)),-U__wasm_bulk_memory__) \ - -U__wasm_bulk_memory_opt__ \ - -U__GNUC__ \ - -U__GNUC_MINOR__ \ - -U__GNUC_PATCHLEVEL__ \ - -U__VERSION__ \ - -U__NO_MATH_ERRNO__ \ - -U__BITINT_MAXWIDTH__ \ - -U__FLT_EVAL_METHOD__ -Wno-builtin-macro-redefined \ - | sed -e 's/__[[:upper:][:digit:]]*_ATOMIC_\([[:upper:][:digit:]_]*\)_LOCK_FREE/__compiler_ATOMIC_\1_LOCK_FREE/' \ - | sed -e 's/__GNUC_VA_LIST $$/__GNUC_VA_LIST 1/' \ - | grep -v '^#define __\(BOOL\|INT_\(LEAST\|FAST\)\(8\|16\|32\|64\)\|INT\|LONG\|LLONG\|SHRT\)_WIDTH__' \ - | grep -v '^#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_\(1\|2\|4\|8\)' \ - | grep -v '^#define __FPCLASS_' \ - | grep -v '^#define __FLT128_' \ - | grep -v '^#define __MEMORY_SCOPE_' \ - | grep -v '^#define __GCC_\(CON\|DE\)STRUCTIVE_SIZE' \ - | grep -v '^#define __STDC_EMBED_' \ - | grep -v '^#define __\(DBL\|FLT\|LDBL\)_NORM_MAX__' \ - | grep -v '^#define NDEBUG' \ - | grep -v '^#define __OPTIMIZE__' \ - | grep -v '^#define assert' \ - | grep -v '^#define __NO_INLINE__' \ - | grep -v '^#define __U\?INT.*_C(' \ - > "$(SYSROOT_SHARE)/predefined-macros.txt" - - # Check that the computed metadata matches the expected metadata. - # This ignores whitespace because on Windows the output has CRLF line endings. - diff -wur "$(EXPECTED_TARGET_DIR)" "$(SYSROOT_SHARE)" - - -##### BINDINGS ################################################################# -# The `bindings` target retrieves the necessary WIT files for the wasi-cli world -# and generates a header file used by the wasip2 target. -################################################################################ - -# The directory where we store files and tools for generating WASIp2 bindings -BINDING_WORK_DIR ?= build/bindings -# URL from which to retrieve the WIT files used to generate the WASIp2 bindings -WASI_CLI_URL ?= https://github.com/WebAssembly/wasi-cli/archive/refs/tags/v0.2.0.tar.gz -# URL from which to retrieve the `wit-bindgen` command used to generate the -# WASIp2 bindings. -WIT_BINDGEN_URL ?= https://github.com/bytecodealliance/wit-bindgen/releases/download/v0.48.0/wit-bindgen-0.48.0-x86_64-linux.tar.gz - -$(BINDING_WORK_DIR)/wasi-cli: - mkdir -p "$(BINDING_WORK_DIR)" - cd "$(BINDING_WORK_DIR)" && \ - curl -L "$(WASI_CLI_URL)" -o wasi-cli.tar.gz && \ - tar xf wasi-cli.tar.gz && \ - mv wasi-cli-* wasi-cli - -$(BINDING_WORK_DIR)/wit-bindgen: - mkdir -p "$(BINDING_WORK_DIR)" - cd "$(BINDING_WORK_DIR)" && \ - curl -L "$(WIT_BINDGEN_URL)" -o wit-bindgen.tar.gz && \ - tar xf wit-bindgen.tar.gz && \ - mv wit-bindgen-* wit-bindgen - -bindings: $(BINDING_WORK_DIR)/wasi-cli $(BINDING_WORK_DIR)/wit-bindgen - cd "$(BINDING_WORK_DIR)" && \ - ./wit-bindgen/wit-bindgen c \ - --autodrop-borrows yes \ - --rename-world wasip2 \ - --type-section-suffix __wasi_libc \ - --world wasi:cli/imports@0.2.0 \ - --rename wasi:clocks/monotonic-clock@0.2.0=monotonic_clock \ - --rename wasi:clocks/wall-clock@0.2.0=wall_clock \ - --rename wasi:filesystem/preopens@0.2.0=filesystem_preopens \ - --rename wasi:filesystem/types@0.2.0=filesystem \ - --rename wasi:io/error@0.2.0=io_error \ - --rename wasi:io/poll@0.2.0=poll \ - --rename wasi:io/streams@0.2.0=streams \ - --rename wasi:random/insecure-seed@0.2.0=random_insecure_seed \ - --rename wasi:random/insecure@0.2.0=random_insecure \ - --rename wasi:random/random@0.2.0=random \ - --rename wasi:sockets/instance-network@0.2.0=instance_network \ - --rename wasi:sockets/ip-name-lookup@0.2.0=ip_name_lookup \ - --rename wasi:sockets/network@0.2.0=network \ - --rename wasi:sockets/tcp-create-socket@0.2.0=tcp_create_socket \ - --rename wasi:sockets/tcp@0.2.0=tcp \ - --rename wasi:sockets/udp-create-socket@0.2.0=udp_create_socket \ - --rename wasi:sockets/udp@0.2.0=udp \ - --rename wasi:cli/environment@0.2.0=environment \ - --rename wasi:cli/exit@0.2.0=exit \ - --rename wasi:cli/stdin@0.2.0=stdin \ - --rename wasi:cli/stdout@0.2.0=stdout \ - --rename wasi:cli/stderr@0.2.0=stderr \ - --rename wasi:cli/terminal-input@0.2.0=terminal_input \ - --rename wasi:cli/terminal-output@0.2.0=terminal_output \ - --rename wasi:cli/terminal-stdin@0.2.0=terminal_stdin \ - --rename wasi:cli/terminal-stdout@0.2.0=terminal_stdout \ - --rename wasi:cli/terminal-stderr@0.2.0=terminal_stderr \ - ./wasi-cli/wit && \ - mv wasip2.h ../../libc-bottom-half/headers/public/wasi/ && \ - mv wasip2_component_type.o ../../libc-bottom-half/sources && \ - sed 's_#include "wasip2\.h"_#include "wasi/wasip2.h"_' \ - < wasip2.c \ - > ../../libc-bottom-half/sources/wasip2.c && \ - rm wasip2.c - sed -i 's/extern void exit_exit/_Noreturn extern void exit_exit/' libc-bottom-half/headers/public/wasi/wasip2.h - sed -i 's/extern void __wasm_import_exit_exit/_Noreturn extern void __wasm_import_exit_exit/' libc-bottom-half/sources/wasip2.c - - -clean: - $(RM) -r "$(BINDING_WORK_DIR)" - $(RM) -r "$(OBJDIR)" - $(RM) -r "$(SYSROOT)" - -.PHONY: default libc libc_so finish install clean check-symbols no-check-symbols bindings startup_files diff --git a/README.md b/README.md index 89c4eef06..e7ea7da34 100644 --- a/README.md +++ b/README.md @@ -21,18 +21,49 @@ build of `wasi-libc` in its sysroot. To build a WASI sysroot from source, obtain a WebAssembly-supporting C compiler (currently this is only clang 10+, though we'd like to support other compilers -as well), and then run: +as well). The build is configured with: ```sh -make CC=/path/to/clang/with/wasm/support \ - AR=/path/to/llvm-ar \ - NM=/path/to/llvm-nm +cmake -S . -B build ``` -This makes a directory called "sysroot" by default. See the top of the Makefile -for customization options. +You can configure the build system with the `-G` argument to `cmake`, for +example `-G Ninja`, to build with a different build system instead. + +Supported options to the configuration step are: + +* `-DCMAKE_C_COMPILER=clang` - specify a C compiler to use. +* `-DCMAKE_AR=llvm-ar` - specify a specific `ar` program to use. +* `-DCMAKE_INSTALL_PREFIX=path` - where to install the sysroot. +* `-DTARGET_TRIPLE=...` - which target to build: for example `wasm32-wasip1`, + `wasm32-wasip2`, `wasm32-wasip1-threads`, ... +* `-DMALLOC=...` - one of `dlmalloc`, `emmalloc`, or `none`. +* `-DBUILTINS_LIB=...` - optional path to compiler-rt which, if not present, + will be downloaded automatically. +* `-DBULK_MEMORY_THRESHOLD=...` - used to tune bulk-memory-related copying + functions. +* `-DSETJMP=(ON|OFF)` - whether or not to build libsetjmp.{a,so} +* `-DBUILD_TESTS=(ON|OFF)` - whether or not to build tests +* `-DSIMD=(ON|OFF)` - whether or not to enable simd-related string routines +* `-DBUILD_SHARED=(ON|OFF)` - forcibly enable or disable building shared + libraries. + +After the build is configured you can use the generated build system to build +wasi-libc. For example. -To use the sysroot, use the `--sysroot=` option: +```sh +cd build && make -j$(nproc) +``` + +This can then be installed using the `install` target of your build system. For +example: + +```sh +cd build && make install +``` + +This will install to the directory specified by `-DCMAKE_INSTALL_PREFIX=...`. +This path can then be used as a sysroot for C: ```sh /path/to/wasm/supporting/c/compiler --sysroot=/path/to/the/newly/built/sysroot ... @@ -50,22 +81,22 @@ libraries, notably `libclang_rt.builtins-wasm32.a`, by default. This is one of the things [wasi-sdk] simplifies, as it includes cross-compiled builds of compiler-rt, `libc++.a`, and `libc++abi.a`. -The build of wasi-libc itself may depend on compiler-rt, or +The build of wasi-libc itself depends on compiler-rt, or `libclang_rt.builtins-wasm32.a`. This manifests in error messages such as `undefined symbol: __muloti4` for example. Specifically the PIC build of wasi-libc will require that Clang can locate `libclang_rt.builtins-wasm32.a`, -meaning that `libc.so` requires this library to be present. To handle this the -default behavior of the build system is to download the latest version of -compiler-rt from [wasi-sdk] and use that for the build of `libc.so`. You can -also set `BUILTINS_LIB` as a path to `libclang_rt.builtins-wasm32.a` as well to -use that instead of downloading a version. +meaning that `libc.so` requires this library to be present. This library is +downloaded automatically as part of the build but it can also be manually +specified with `-DBUILTINS_LIB=...`. ## Building in pthread support -To enable pthreads support via the [wasi-threads] proposal, follow the above -build directions with one addition: `make ... THREAD_MODEL=posix`. This creates -additional artifacts in `sysroot/lib/wasm32-wasi-threads` to support `--target -wasm32-wasi-threads`. +The `wasm32-wasip1` and `wasm32-wasip2` targets have pthread-related symbols, +but they all return an error. For example spawning a thread will return an +error. Only the `wasm32-wasip1-threads` target supports spawning a thread. Note +that threading support is experimental at this time and only very lightly +tested. Much of libc needs to be modified to be threadsafe and this transition +is not fully complete. ## Arch Linux AUR package diff --git a/cmake/Platform/WASI.cmake b/cmake/Platform/WASI.cmake new file mode 100644 index 000000000..b49713f1b --- /dev/null +++ b/cmake/Platform/WASI.cmake @@ -0,0 +1 @@ +set(WASI 1) diff --git a/cmake/ba-download.cmake b/cmake/ba-download.cmake new file mode 100644 index 000000000..a5726e516 --- /dev/null +++ b/cmake/ba-download.cmake @@ -0,0 +1,48 @@ +include(ExternalProject) + +function(ba_download target repo version) + if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(arch "x86_64") + elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") + set(arch "aarch64") + elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(arch "aarch64") + elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") + set(arch "x86_64") + else() + message(FATAL_ERROR "Unsupported architecture ${CMAKE_HOST_SYSTEM_PROCESSOR} for ${target}") + endif() + + if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(os macos) + elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + set(os linux) + elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(os windows) + else() + message(FATAL_ERROR "Unsupported system ${CMAKE_HOST_SYSTEM_NAME} for ${target}") + endif() + + if (target STREQUAL wasmtime) + set(fmt xz) + else() + set(fmt gz) + endif() + + if (target STREQUAL wit-bindgen) + set(tag v${version}) + else() + set(tag ${version}) + endif() + + message(STATUS "Using ${target} ${version} for ${arch}-${os} from ${repo}") + + ExternalProject_Add( + ${target} + EXCLUDE_FROM_ALL ON + URL "${repo}/releases/download/${tag}/${target}-${version}-${arch}-${os}.tar.${fmt}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) +endfunction() diff --git a/cmake/bindings.cmake b/cmake/bindings.cmake new file mode 100644 index 000000000..e181e22c6 --- /dev/null +++ b/cmake/bindings.cmake @@ -0,0 +1,66 @@ +include(ba-download) + +ba_download( + wit-bindgen + "https://github.com/bytecodealliance/wit-bindgen" + "0.48.0" +) +ExternalProject_Get_Property(wit-bindgen SOURCE_DIR) +set(wit_bindgen "${SOURCE_DIR}/wit-bindgen") + +ExternalProject_Add( + wasi-wits + URL https://github.com/WebAssembly/wasi-cli/archive/refs/tags/v0.2.0.tar.gz + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + EXCLUDE_FROM_ALL TRUE +) +ExternalProject_Get_Property(wasi-wits SOURCE_DIR) +set(wit_dir ${SOURCE_DIR}/wit) +set(bottom_half "${CMAKE_SOURCE_DIR}/libc-bottom-half") + +add_custom_target( + bindings + COMMAND + ${wit_bindgen} c + --autodrop-borrows yes + --rename-world wasip2 + --type-section-suffix __wasi_libc + --world wasi:cli/imports@0.2.0 + --rename wasi:clocks/monotonic-clock@0.2.0=monotonic_clock + --rename wasi:clocks/wall-clock@0.2.0=wall_clock + --rename wasi:filesystem/preopens@0.2.0=filesystem_preopens + --rename wasi:filesystem/types@0.2.0=filesystem + --rename wasi:io/error@0.2.0=io_error + --rename wasi:io/poll@0.2.0=poll + --rename wasi:io/streams@0.2.0=streams + --rename wasi:random/insecure-seed@0.2.0=random_insecure_seed + --rename wasi:random/insecure@0.2.0=random_insecure + --rename wasi:random/random@0.2.0=random + --rename wasi:sockets/instance-network@0.2.0=instance_network + --rename wasi:sockets/ip-name-lookup@0.2.0=ip_name_lookup + --rename wasi:sockets/network@0.2.0=network + --rename wasi:sockets/tcp-create-socket@0.2.0=tcp_create_socket + --rename wasi:sockets/tcp@0.2.0=tcp + --rename wasi:sockets/udp-create-socket@0.2.0=udp_create_socket + --rename wasi:sockets/udp@0.2.0=udp + --rename wasi:cli/environment@0.2.0=environment + --rename wasi:cli/exit@0.2.0=exit + --rename wasi:cli/stdin@0.2.0=stdin + --rename wasi:cli/stdout@0.2.0=stdout + --rename wasi:cli/stderr@0.2.0=stderr + --rename wasi:cli/terminal-input@0.2.0=terminal_input + --rename wasi:cli/terminal-output@0.2.0=terminal_output + --rename wasi:cli/terminal-stdin@0.2.0=terminal_stdin + --rename wasi:cli/terminal-stdout@0.2.0=terminal_stdout + --rename wasi:cli/terminal-stderr@0.2.0=terminal_stderr + ${wit_dir} + COMMAND cmake -E copy wasip2.h ${bottom_half}/headers/public/wasi/ + COMMAND cmake -E copy wasip2_component_type.o ${bottom_half}/sources + COMMAND cmake -E copy wasip2.c ${bottom_half}/sources + COMMAND sed -i "'s_#include .wasip2\.h._#include \"wasi/wasip2.h\"_'" ${bottom_half}/sources/wasip2.c + COMMAND sed -i "s/extern void exit_exit/_Noreturn extern void exit_exit/" ${bottom_half}/headers/public/wasi/wasip2.h + COMMAND sed -i "s/extern void __wasm_import_exit_exit/_Noreturn extern void __wasm_import_exit_exit/" ${bottom_half}/sources/wasip2.c + DEPENDS wit-bindgen wasi-wits +) diff --git a/cmake/builtins.cmake b/cmake/builtins.cmake new file mode 100644 index 000000000..45b861f38 --- /dev/null +++ b/cmake/builtins.cmake @@ -0,0 +1,67 @@ +# +# Figure out what to do about compiler-rt. +# +# The compiler-rt library is not built here in the wasi-libc repository, but it +# is required to link artifacts. Notably `libc.so` and test and such all require +# it to exist. Currently the ways this is handled are: +# +# * If `BUILTINS_LIB` is defined at build time then that's assumed to be a path +# to the libcompiler-rt.a. That's then ingested into the build here and copied +# around to special locations to get the `*.so` rules below to work (see docs +# there). +# +# * If `BUILTINS_LIB` is not defined then a known-good copy is downloaded from +# wasi-sdk CI and used instead. +# +# In the future this may also want some form of configuration to support +# assuming the system compiler has a compiler-rt, e.g. if $(SYSTEM_BUILTINS_LIB) +# exists that should be used instead. +get_property(directory_cflags DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_OPTIONS) +execute_process( + COMMAND ${CMAKE_C_COMPILER} --target=${TARGET_TRIPLE} --print-libgcc-file-name + OUTPUT_VARIABLE system_builtins_lib + OUTPUT_STRIP_TRAILING_WHITESPACE +) +execute_process( + COMMAND ${CMAKE_C_COMPILER} --target=${TARGET_TRIPLE} -print-resource-dir + OUTPUT_VARIABLE system_resource_dir + OUTPUT_STRIP_TRAILING_WHITESPACE +) +cmake_path( + RELATIVE_PATH system_builtins_lib + BASE_DIRECTORY ${system_resource_dir} + OUTPUT_VARIABLE builtins_lib_rel_1 +) + + +set(tmp_resource_dir ${CMAKE_BINARY_DIR}/temp-resource-dir) +set(builtins_lib_path ${tmp_resource_dir}/${builtins_lib_rel_1}) +cmake_path(GET builtins_lib_path PARENT_PATH builtins_lib_dir) + +if(BUILTINS_LIB) + message(STATUS "Using builtins lib: ${BUILTINS_LIB}") + add_custom_command( + OUTPUT ${builtins_lib_path} + COMMAND ${CMAKE_COMMAND} -E copy ${BUILTINS_LIB} ${builtins_lib_path} + DEPENDS ${BUILTINS_LIB} + ) +else() + message(STATUS "Using historical builtins lib from wasi-sdk...") + include(ExternalProject) + ExternalProject_Add( + wasi-sdk-builtins + EXCLUDE_FROM_ALL ON + URL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/libclang_rt.builtins-wasm32-wasi-25.0.tar.gz + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) + ExternalProject_Get_Property(wasi-sdk-builtins SOURCE_DIR) + set(src ${SOURCE_DIR}/libclang_rt.builtins-wasm32.a) + add_custom_command( + OUTPUT ${builtins_lib_path} + COMMAND ${CMAKE_COMMAND} -E copy ${src} ${builtins_lib_path} + DEPENDS wasi-sdk-builtins + ) +endif() +add_custom_target(builtins DEPENDS ${builtins_lib_path}) diff --git a/cmake/check-symbols.cmake b/cmake/check-symbols.cmake new file mode 100644 index 000000000..e472f8adc --- /dev/null +++ b/cmake/check-symbols.cmake @@ -0,0 +1,53 @@ +set(SYSROOT_SHARE ${SYSROOT}/share/${TARGET_TRIPLE}) +set(undefined_symbols ${SYSROOT_SHARE}/undefined-symbols.txt) +set(defined_symbols ${SYSROOT_SHARE}/defined-symbols.txt) +set(include_all ${SYSROOT_SHARE}/include-all.c) + +add_custom_command( + OUTPUT + ${defined_symbols} + ${undefined_symbols} + ${include_all} + COMMAND + ${CMAKE_COMMAND} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_C_FLAGS="$" + -DSYSROOT_LIB=${SYSROOT_LIB} + -DSYSROOT_INC=${SYSROOT_INC} + -DCMAKE_NM=${CMAKE_NM} + -DOUT_DIR=${SYSROOT_SHARE} + -P ${CMAKE_CURRENT_LIST_DIR}/scripts/run-check-symbols.cmake + DEPENDS + sysroot + ${CMAKE_CURRENT_LIST_DIR}/scripts/run-check-symbols.cmake +) + +if(THREADS) + set(expected "${CMAKE_SOURCE_DIR}/expected/wasm32-wasip1-threads") +elseif(WASI STREQUAL "p1") + set(expected "${CMAKE_SOURCE_DIR}/expected/wasm32-wasip1") +elseif(WASI STREQUAL "p2") + set(expected "${CMAKE_SOURCE_DIR}/expected/wasm32-wasip2") +else() + message(FATAL_ERROR "Unknown WASI version: ${WASI}") +endif() + + +add_custom_target( + check-symbols + COMMAND + diff -wur ${expected} ${SYSROOT_SHARE} + DEPENDS ${defined_symbols} ${undefined_symbols} +) + +if(CHECK_SYMBOLS) + set_target_properties(check-symbols PROPERTIES EXCLUDE_FROM_ALL FALSE) +endif() + +# Helper target to auto-update the expectations of symbols +add_custom_target( + update-symbols + COMMAND + cp -r ${SYSROOT_SHARE}/* ${expected}/ + DEPENDS ${defined_symbols} ${undefined_symbols} +) diff --git a/cmake/scripts/run-check-symbols.cmake b/cmake/scripts/run-check-symbols.cmake new file mode 100644 index 000000000..f44cc149f --- /dev/null +++ b/cmake/scripts/run-check-symbols.cmake @@ -0,0 +1,178 @@ +# A CMake-based script to populate files in `share/*` related to +# defined/undefined symbols/macros. +# +# You might rightfully recoil a bit to see such a meaty script written in CMake. +# Given the choice of using shell, which isn't portable, or something like +# Python, which would only be used for this, I opted to go with CMake. Unsure +# if that was a good idea but it's at least all here and hopefully working well +# enough. If you need to edit this it's probably gonna be at the bottom related +# to filtering out macros and such. + +file(GLOB objects ${SYSROOT_LIB}/*.[ao]) + +# =========================================== +# Generate defined-symbols.txt and undefined-symbols.txt + +set(defined_symbols) +set(undefined_symbols) + +foreach(file ${objects}) + if (file MATCHES "lib(setjmp|dl).a$") + continue() + endif() + # TODO: Use llvm-nm --extern-only instead of grep. This is blocked on + # LLVM PR40497, which is fixed in 9.0, but not in 8.0. + execute_process( + COMMAND ${CMAKE_NM} --defined-only ${file} + OUTPUT_VARIABLE nm_output + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + string(REPLACE "\n" ";" nm_lines "${nm_output}") + list(APPEND defined_symbols ${nm_lines}) + + execute_process( + COMMAND ${CMAKE_NM} --undefined-only ${file} + OUTPUT_VARIABLE nm_output + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + string(REPLACE "\n" ";" nm_lines "${nm_output}") + list(APPEND undefined_symbols ${nm_lines}) +endforeach() + +# Filter/transform/sort `defined_symbols` into `final_defined_symbols`. +list(FILTER defined_symbols INCLUDE REGEX " [A-Z] ") +foreach(line IN LISTS defined_symbols) + string(REGEX REPLACE ".* [A-Z] " "" symbol "${line}") + list(APPEND final_defined_symbols ${symbol}) +endforeach() +list(SORT final_defined_symbols) +list(REMOVE_DUPLICATES final_defined_symbols) + + +# Filter/transform/sort `undefined_symbols` into `final_undefined_symbols`. +list(FILTER undefined_symbols INCLUDE REGEX " U ") +foreach(line IN LISTS undefined_symbols) + string(REGEX REPLACE ".* U " "" symbol "${line}") + list(APPEND final_undefined_symbols ${symbol}) +endforeach() +list(SORT final_undefined_symbols) +list(REMOVE_DUPLICATES final_undefined_symbols) + +# Write out `defined-symbos.txt` with all our symbols. +set(out_defined_symbols ${OUT_DIR}/defined-symbols.txt) +string(JOIN "\n" defined_symbols_content ${final_defined_symbols}) +file(WRITE ${out_defined_symbols} "${defined_symbols_content}") + +# Write out `undefined-symbosl.txt`, but skip some symbols. +set(out_undefined_symbols ${OUT_DIR}/undefined-symbols.txt) +file(WRITE ${out_undefined_symbols} "") +foreach(symbol IN LISTS final_undefined_symbols) + list(FIND final_defined_symbols "${symbol}" found_index) + if(NOT(found_index EQUAL -1)) + continue() + endif() + # Ignore certain llvm builtin symbols such as those starting with __mul + # since these dependencies can vary between llvm versions. + if(NOT symbol MATCHES "^__mul" AND + NOT symbol STREQUAL "__memory_base" AND + NOT symbol STREQUAL "__indirect_function_table" AND + NOT symbol STREQUAL "__tls_base") + file(APPEND ${out_undefined_symbols} "${symbol}\n") + endif() +endforeach() + +# =========================================== +# Generate include-all.c + +file(GLOB_RECURSE headers RELATIVE ${SYSROOT_INC} ${SYSROOT_INC}/*.h) +set(out_include_all ${OUT_DIR}/include-all.c) +file(WRITE ${out_include_all} "") +foreach(header IN LISTS headers) + if(header MATCHES bits/ OR + header MATCHES /c\\+\\+/ OR + # setjmp.h is excluded because it requires a different compiler option + header MATCHES "^(setjmp|signal).h$" OR + # Ignore some headers that require extra options for example. + header MATCHES "/(mman|times|signal|resource|descriptor_table).h$") + continue() + endif() + file(APPEND ${out_include_all} "#include <${header}>\n") +endforeach() + +# =========================================== +# Generate predefined-macros.txt + +set(out_predefined_macros ${OUT_DIR}/predefined-macros.txt) +execute_process( + COMMAND + ${CMAKE_C_COMPILER} + ${CMAKE_C_FLAGS} + ${out_include_all} + -isystem ${SYSROOT_INC} + -std=gnu17 + -E -dM + -D_ALL_SOURCE + # Skip compiler version macros + -U__llvm__ + -U__clang__ + -U__clang_major__ + -U__clang_minor__ + -U__clang_patchlevel__ + -U__clang_version__ + -U__clang_literal_encoding__ + -U__clang_wide_literal_encoding__ + # Skip macros related to wasm features being on or off + -U__wasm_extended_const__ + -U__wasm_mutable_globals__ + -U__wasm_sign_ext__ + -U__wasm_multivalue__ + -U__wasm_reference_types__ + -U__wasm_nontrapping_fptoint__ + -U__wasm_bulk_memory__ + -U__wasm_bulk_memory_opt__ + # Skip some other macros that vary between compiler versions + -U__GNUC__ + -U__GNUC_MINOR__ + -U__GNUC_PATCHLEVEL__ + -U__VERSION__ + -U__NO_MATH_ERRNO__ + -U__BITINT_MAXWIDTH__ + -U__FLT_EVAL_METHOD__ + "-Wno-#warnings" + -Wno-builtin-macro-redefined + OUTPUT_FILE ${out_predefined_macros} + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY +) +file(STRINGS ${out_predefined_macros} predefined_macro_lines) +file(WRITE ${out_predefined_macros} "") +foreach(line IN LISTS predefined_macro_lines) + # Try to normalize some macros + if(line MATCHES "__[A-Z0-9]*_ATOMIC_[A-Z0-9_]*_LOCK_FREE") + string(REGEX REPLACE "__[A-Z0-9]*_ATOMIC_([A-Z0-9_]*)_LOCK_FREE" "__compiler_ATOMIC_\\1_LOCK_FREE" line "${line}") + endif() + if(line MATCHES "^#define __GNUC_VA_LIST $") + string(REPLACE "__GNUC_VA_LIST " "__GNUC_VA_LIST 1" line "${line}") + endif() + + # Skip a whole bunch of other macros that vary between compilers + if(line MATCHES "^#define __(BOOL|INT_(LEAST|FAST)(8|16|32|64)|INT|LONG|LLONG|SHRT)_WIDTH__" + OR line MATCHES "^#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_(1|2|4|8)" + OR line MATCHES "^#define __FPCLASS_" + OR line MATCHES "^#define __FLT128_" + OR line MATCHES "^#define __MEMORY_SCOPE_" + OR line MATCHES "^#define __GCC_(CON|DE)STRUCTIVE_SIZE" + OR line MATCHES "^#define __STDC_EMBED_" + OR line MATCHES "^#define __(DBL|FLT|LDBL)_NORM_MAX__" + OR line MATCHES "^#define NDEBUG" + OR line MATCHES "^#define __OPTIMIZE__" + OR line MATCHES "^#define assert" + OR line MATCHES "^#define __NO_INLINE__" + OR line MATCHES "^#define __U?INT.*_C\\(" + ) + continue() + endif() + file(APPEND ${out_predefined_macros} "${line}\n") +endforeach() diff --git a/cmake/wasm-component-ld.cmake b/cmake/wasm-component-ld.cmake new file mode 100644 index 000000000..7d8b711ae --- /dev/null +++ b/cmake/wasm-component-ld.cmake @@ -0,0 +1,14 @@ +find_program(WASM_COMPONENT_LD_EXECUTABLE NAMES wasm-component-ld) +include(ba-download) + +if (NOT WASM_COMPONENT_LD_EXECUTABLE) + ba_download( + wasm-component-ld + "https://github.com/bytecodealliance/wasm-component-ld" + "v0.5.19" + ) + ExternalProject_Get_Property(wasm-component-ld SOURCE_DIR) + set(WASM_COMPONENT_LD_EXECUTABLE "${SOURCE_DIR}/wasm-component-ld") + add_link_options(-fuse-ld=${WASM_COMPONENT_LD_EXECUTABLE}) + add_dependencies(sysroot_inc wasm-component-ld) +endif() diff --git a/dlmalloc/CMakeLists.txt b/dlmalloc/CMakeLists.txt new file mode 100644 index 000000000..8e2516de8 --- /dev/null +++ b/dlmalloc/CMakeLists.txt @@ -0,0 +1,4 @@ +add_object_library(dlmalloc src/dlmalloc.c) +foreach(obj dlmalloc-shared dlmalloc-static) + target_include_directories(${obj} PRIVATE include) +endforeach() diff --git a/emmalloc/CMakeLists.txt b/emmalloc/CMakeLists.txt new file mode 100644 index 000000000..b6fd9d969 --- /dev/null +++ b/emmalloc/CMakeLists.txt @@ -0,0 +1,8 @@ +add_object_library(emmalloc emmalloc.c) + +# emmalloc uses a lot of pointer type-punning, which is UB under strict +# aliasing, and this was found to have real miscompilations in wasi-libc#421. +foreach(obj emmalloc-shared emmalloc-static) + target_include_directories(${obj} PRIVATE emmalloc) + target_compile_options(${obj} PRIVATE -fno-strict-aliasing) +endforeach() diff --git a/expected/wasm32-wasip1-threads/predefined-macros.txt b/expected/wasm32-wasip1-threads/predefined-macros.txt index f691c853a..823ef8c93 100644 --- a/expected/wasm32-wasip1-threads/predefined-macros.txt +++ b/expected/wasm32-wasip1-threads/predefined-macros.txt @@ -3091,6 +3091,7 @@ #define __WASI_ROFLAGS_RECV_DATA_TRUNCATED ((__wasi_roflags_t)(1 << 0)) #define __WASI_SDFLAGS_RD ((__wasi_sdflags_t)(1 << 0)) #define __WASI_SDFLAGS_WR ((__wasi_sdflags_t)(1 << 1)) +#define __WASI_SNAPSHOT_H #define __WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME ((__wasi_subclockflags_t)(1 << 0)) #define __WASI_WHENCE_CUR (UINT8_C(1)) #define __WASI_WHENCE_END (UINT8_C(2)) @@ -3128,10 +3129,10 @@ #define __tg_real_remquo(x,y,z) (__RETCAST_2(x, y)( __FLT(x) && __FLT(y) ? remquof(x, y, z) : __LDBL((x)+(y)) ? remquol(x, y, z) : remquo(x, y, z) )) #define __tm_gmtoff tm_gmtoff #define __tm_zone tm_zone -#define __va_copy(d,s) __builtin_va_copy(d,s) +#define __va_copy(d,s) __builtin_va_copy(d, s) #define __wasi__ 1 #define __wasi_api_h -#define __wasi_libc_busywait_h +#define __wasi_libc_busywait_h #define __wasi_libc_environ_h #define __wasi_libc_find_relpath_h #define __wasi_libc_h @@ -3203,7 +3204,6 @@ #define __wasm32__ 1 #define __wasm__ 1 #define __wasm_atomics__ 1 -#define __wasm_bulk_memory__ 1 #define _tolower(a) ((a)|0x20) #define _toupper(a) ((a)&0x5f) #define acos(x) __tg_real_complex(acos, (x)) diff --git a/expected/wasm32-wasip1/predefined-macros.txt b/expected/wasm32-wasip1/predefined-macros.txt index 66f4c4c88..493b767eb 100644 --- a/expected/wasm32-wasip1/predefined-macros.txt +++ b/expected/wasm32-wasip1/predefined-macros.txt @@ -3088,6 +3088,7 @@ #define __WASI_ROFLAGS_RECV_DATA_TRUNCATED ((__wasi_roflags_t)(1 << 0)) #define __WASI_SDFLAGS_RD ((__wasi_sdflags_t)(1 << 0)) #define __WASI_SDFLAGS_WR ((__wasi_sdflags_t)(1 << 1)) +#define __WASI_SNAPSHOT_H #define __WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME ((__wasi_subclockflags_t)(1 << 0)) #define __WASI_WHENCE_CUR (UINT8_C(1)) #define __WASI_WHENCE_END (UINT8_C(2)) @@ -3128,7 +3129,7 @@ #define __va_copy(d,s) __builtin_va_copy(d, s) #define __wasi__ 1 #define __wasi_api_h -#define __wasi_libc_busywait_h +#define __wasi_libc_busywait_h #define __wasi_libc_environ_h #define __wasi_libc_find_relpath_h #define __wasi_libc_h diff --git a/expected/wasm32-wasip2/predefined-macros.txt b/expected/wasm32-wasip2/predefined-macros.txt index 1ae2e1fd2..912b5e0f5 100644 --- a/expected/wasm32-wasip2/predefined-macros.txt +++ b/expected/wasm32-wasip2/predefined-macros.txt @@ -3240,6 +3240,7 @@ #define __WASI_ROFLAGS_RECV_DATA_TRUNCATED ((__wasi_roflags_t)(1 << 0)) #define __WASI_SDFLAGS_RD ((__wasi_sdflags_t)(1 << 0)) #define __WASI_SDFLAGS_WR ((__wasi_sdflags_t)(1 << 1)) +#define __WASI_SNAPSHOT_H #define __WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME ((__wasi_subclockflags_t)(1 << 0)) #define __WASI_WHENCE_CUR (UINT8_C(1)) #define __WASI_WHENCE_END (UINT8_C(2)) @@ -3280,7 +3281,7 @@ #define __va_copy(d,s) __builtin_va_copy(d, s) #define __wasi__ 1 #define __wasi_api_h -#define __wasi_libc_busywait_h +#define __wasi_libc_busywait_h #define __wasi_libc_environ_h #define __wasi_libc_find_relpath_h #define __wasi_libc_h @@ -3347,7 +3348,7 @@ #define __wasilibc___typedef_suseconds_t_h #define __wasilibc___typedef_time_t_h #define __wasilibc___typedef_uid_t_h -#define __wasilibc_use_wasip2 1 +#define __wasilibc_use_wasip2 #define __wasm 1 #define __wasm32 1 #define __wasm32__ 1 diff --git a/fts/CMakeLists.txt b/fts/CMakeLists.txt new file mode 100644 index 000000000..987f5f46a --- /dev/null +++ b/fts/CMakeLists.txt @@ -0,0 +1,6 @@ +add_internal_object_library(fts musl-fts/fts.c) +foreach(obj fts-shared fts-static) + target_include_directories(${obj} PRIVATE . musl-fts) +endforeach() + +add_sysroot_header(musl-fts/fts.h fts.h) diff --git a/libc-bottom-half/CMakeLists.txt b/libc-bottom-half/CMakeLists.txt new file mode 100644 index 000000000..b3a891871 --- /dev/null +++ b/libc-bottom-half/CMakeLists.txt @@ -0,0 +1,213 @@ +add_subdirectory(clocks) +add_subdirectory(mman) +add_subdirectory(getpid) +add_subdirectory(signal) + +# ============================================================================= +# sysroot headers from the bottom half +# +configure_file(headers/public/__wasi_snapshot.h.in ${SYSROOT_INC}/__wasi_snapshot.h) +add_custom_target(sysroot-wasi-snapshot-header DEPENDS ${SYSROOT_INC}/__wasi_snapshot.h) +add_dependencies(sysroot_inc sysroot-wasi-snapshot-header) + +file( + GLOB_RECURSE globbed_headers + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + CONFIGURE_DEPENDS + headers/public/*.h +) + +# TODO: these headers are not actually installed in the sysroot since the +# musl-sourced ones are. These should probably be deleted from the source +# tree and the musl ones used instead. +list(REMOVE_ITEM globbed_headers + headers/public/dirent.h + headers/public/errno.h + headers/public/fcntl.h + headers/public/inttypes.h + headers/public/netinet/in.h + headers/public/poll.h + headers/public/stdlib.h + headers/public/string.h + headers/public/sys/ioctl.h + headers/public/sys/resource.h + headers/public/sys/select.h + headers/public/sys/socket.h + headers/public/sys/stat.h + headers/public/sys/time.h + headers/public/sys/times.h + headers/public/sys/types.h + headers/public/sys/uio.h + headers/public/sys/un.h + headers/public/time.h + headers/public/unistd.h + headers/public/wchar.h +) + +if (WASI STREQUAL "p1") + list(REMOVE_ITEM globbed_headers headers/public/wasi/wasip2.h) +endif() + +foreach(header ${globbed_headers}) + string(REPLACE "headers/public/" "" dst ${header}) + add_sysroot_header(${header} ${dst}) +endforeach() + +# ============================================================================= +# building bottom-half sources +# +set(bottom_half_sources + cloudlibc/src/libc/dirent/closedir.c + cloudlibc/src/libc/dirent/dirfd.c + cloudlibc/src/libc/dirent/fdclosedir.c + cloudlibc/src/libc/dirent/fdopendir.c + cloudlibc/src/libc/dirent/opendirat.c + cloudlibc/src/libc/dirent/readdir.c + cloudlibc/src/libc/dirent/rewinddir.c + cloudlibc/src/libc/dirent/scandirat.c + cloudlibc/src/libc/dirent/seekdir.c + cloudlibc/src/libc/dirent/telldir.c + cloudlibc/src/libc/errno/errno.c + cloudlibc/src/libc/fcntl/fcntl.c + cloudlibc/src/libc/fcntl/openat.c + cloudlibc/src/libc/fcntl/posix_fadvise.c + cloudlibc/src/libc/fcntl/posix_fallocate.c + cloudlibc/src/libc/poll/poll.c + cloudlibc/src/libc/sched/sched_yield.c + cloudlibc/src/libc/stdio/renameat.c + cloudlibc/src/libc/stdlib/_Exit.c + cloudlibc/src/libc/sys/ioctl/ioctl.c + cloudlibc/src/libc/sys/select/pselect.c + cloudlibc/src/libc/sys/select/select.c + cloudlibc/src/libc/sys/stat/fstat.c + cloudlibc/src/libc/sys/stat/fstatat.c + cloudlibc/src/libc/sys/stat/futimens.c + cloudlibc/src/libc/sys/stat/mkdirat.c + cloudlibc/src/libc/sys/stat/utimensat.c + cloudlibc/src/libc/sys/time/gettimeofday.c + cloudlibc/src/libc/sys/uio/preadv.c + cloudlibc/src/libc/sys/uio/pwritev.c + cloudlibc/src/libc/sys/uio/readv.c + cloudlibc/src/libc/sys/uio/writev.c + cloudlibc/src/libc/time/CLOCK_MONOTONIC.c + cloudlibc/src/libc/time/CLOCK_REALTIME.c + cloudlibc/src/libc/time/clock_getres.c + cloudlibc/src/libc/time/clock_gettime.c + cloudlibc/src/libc/time/clock_nanosleep.c + cloudlibc/src/libc/time/nanosleep.c + cloudlibc/src/libc/time/time.c + cloudlibc/src/libc/unistd/faccessat.c + cloudlibc/src/libc/unistd/fdatasync.c + cloudlibc/src/libc/unistd/fsync.c + cloudlibc/src/libc/unistd/ftruncate.c + cloudlibc/src/libc/unistd/linkat.c + cloudlibc/src/libc/unistd/lseek.c + cloudlibc/src/libc/unistd/pread.c + cloudlibc/src/libc/unistd/pwrite.c + cloudlibc/src/libc/unistd/read.c + cloudlibc/src/libc/unistd/readlinkat.c + cloudlibc/src/libc/unistd/sleep.c + cloudlibc/src/libc/unistd/symlinkat.c + cloudlibc/src/libc/unistd/unlinkat.c + cloudlibc/src/libc/unistd/usleep.c + cloudlibc/src/libc/unistd/write.c + sources/__errno_location.c + sources/__main_void.c + sources/__wasilibc_dt.c + sources/__wasilibc_environ.c + sources/__wasilibc_fd_renumber.c + sources/__wasilibc_initialize_environ.c + sources/__wasilibc_random.c + sources/__wasilibc_real.c + sources/__wasilibc_rmdirat.c + sources/__wasilibc_tell.c + sources/__wasilibc_unlinkat.c + sources/abort.c + sources/at_fdcwd.c + sources/chdir.c + sources/complex-builtins.c + sources/environ.c + sources/errno.c + sources/getcwd.c + sources/getentropy.c + sources/isatty.c + sources/math/fmin-fmax.c + sources/math/math-builtins.c + sources/posix.c + sources/preopens.c + sources/reallocarray.c + sources/sbrk.c + sources/truncate.c +) + +if (WASI STREQUAL "p1") + list(APPEND bottom_half_sources + cloudlibc/src/libc/sys/socket/getsockopt.c + cloudlibc/src/libc/sys/socket/recv.c + cloudlibc/src/libc/sys/socket/send.c + cloudlibc/src/libc/sys/socket/shutdown.c + sources/accept-wasip1.c + ) +elseif(WASI STREQUAL "p2") + list(APPEND bottom_half_sources + sources/accept-wasip2.c + sources/bind.c + sources/connect.c + sources/descriptor_table.c + sources/getsockpeername.c + sources/listen.c + sources/netdb.c + sources/poll-wasip2.c + sources/recv.c + sources/send.c + sources/shutdown.c + sources/socket.c + sources/sockets_utils.c + sources/sockopt.c + sources/wasip2.c + sources/wasip2_file.c + sources/wasip2_file_utils.c + sources/wasip2_stdio.c + sources/wasip2_tcp.c + sources/wasip2_udp.c + ) +endif() + +add_object_library(bottom-half ${bottom_half_sources}) +foreach(obj bottom-half-shared bottom-half-static) + target_link_libraries(${obj} PUBLIC musl-top-half-interface) + target_include_directories(${obj} PRIVATE + cloudlibc/src/include + cloudlibc/src + headers/private + ) +endforeach() + +add_custom_target(sysroot-startup-objects) +add_dependencies(sysroot sysroot-startup-objects) + +# ============================================================================= +# startup objects +# +foreach(file crt/crt1.c + crt/crt1-command.c + crt/crt1-reactor.c) + # get the filename without the directory and extension + cmake_path(GET file STEM filename) + + # create a custom target for each file + add_library(${filename}.o OBJECT ${file}) + target_link_libraries(${filename}.o PUBLIC musl-top-half-interface) + set_target_properties(${filename}.o PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + target_compile_options(${filename}.o PRIVATE -fvisibility=default) + + # add a custom command to compile the file + set(dst ${SYSROOT_LIB}/${filename}.o) + add_custom_command( + OUTPUT ${dst} + COMMAND ${CMAKE_COMMAND} -E copy $ ${dst} + DEPENDS ${filename}.o + ) + add_custom_target(sysroot-startup-${filename}.o DEPENDS ${dst}) + add_dependencies(sysroot-startup-objects sysroot-startup-${filename}.o) +endforeach() diff --git a/libc-bottom-half/clocks/CMakeLists.txt b/libc-bottom-half/clocks/CMakeLists.txt new file mode 100644 index 000000000..3a31ff350 --- /dev/null +++ b/libc-bottom-half/clocks/CMakeLists.txt @@ -0,0 +1,7 @@ +add_internal_library_pair(wasi-emulated-process-clocks + clock.c + getrusage.c + times.c) + +sysroot_lib(wasi-emulated-process-clocks-static libwasi-emulated-process-clocks.a) +sysroot_lib(wasi-emulated-process-clocks libwasi-emulated-process-clocks.so) diff --git a/libc-bottom-half/cloudlibc/src/common/time.h b/libc-bottom-half/cloudlibc/src/common/time.h index ede81012d..32bf4d2b5 100644 --- a/libc-bottom-half/cloudlibc/src/common/time.h +++ b/libc-bottom-half/cloudlibc/src/common/time.h @@ -57,7 +57,7 @@ static inline bool timespec_to_timestamp_clamp( if (timespec->tv_sec < 0) { // Timestamps before the Epoch are not supported. -#if __wasilibc_use_wasip2 +#ifdef __wasilibc_use_wasip2 timestamp->seconds = 0; timestamp->nanoseconds = 0; } else { diff --git a/libc-bottom-half/getpid/CMakeLists.txt b/libc-bottom-half/getpid/CMakeLists.txt new file mode 100644 index 000000000..c112bcc2d --- /dev/null +++ b/libc-bottom-half/getpid/CMakeLists.txt @@ -0,0 +1,3 @@ +add_internal_library_pair(wasi-emulated-getpid getpid.c) +sysroot_lib(wasi-emulated-getpid-static libwasi-emulated-getpid.a) +sysroot_lib(wasi-emulated-getpid libwasi-emulated-getpid.so) diff --git a/libc-bottom-half/headers/public/__wasi_snapshot.h b/libc-bottom-half/headers/public/__wasi_snapshot.h deleted file mode 100644 index 9a1007805..000000000 --- a/libc-bottom-half/headers/public/__wasi_snapshot.h +++ /dev/null @@ -1,5 +0,0 @@ -/* This file is (practically) empty by default. The Makefile will replace it - with a non-empty version that defines `__wasilibc_use_wasip2` if targeting - `wasm32-wasip2`. - */ - diff --git a/libc-bottom-half/headers/public/__wasi_snapshot.h.in b/libc-bottom-half/headers/public/__wasi_snapshot.h.in new file mode 100644 index 000000000..0d155a22b --- /dev/null +++ b/libc-bottom-half/headers/public/__wasi_snapshot.h.in @@ -0,0 +1,6 @@ +#ifndef __WASI_SNAPSHOT_H +#define __WASI_SNAPSHOT_H + +#cmakedefine __wasilibc_use_wasip2 + +#endif /* __WASI_SNAPSHOT_H */ diff --git a/libc-bottom-half/mman/CMakeLists.txt b/libc-bottom-half/mman/CMakeLists.txt new file mode 100644 index 000000000..8a7f1a907 --- /dev/null +++ b/libc-bottom-half/mman/CMakeLists.txt @@ -0,0 +1,3 @@ +add_internal_library_pair(wasi-emulated-mman mman.c) +sysroot_lib(wasi-emulated-mman-static libwasi-emulated-mman.a) +sysroot_lib(wasi-emulated-mman libwasi-emulated-mman.so) diff --git a/libc-bottom-half/signal/CMakeLists.txt b/libc-bottom-half/signal/CMakeLists.txt new file mode 100644 index 000000000..da43c9bf2 --- /dev/null +++ b/libc-bottom-half/signal/CMakeLists.txt @@ -0,0 +1,19 @@ +add_internal_object_library(top-half-emulated-signal + ../../libc-top-half/musl/src/signal/psignal.c + ../../libc-top-half/musl/src/string/strsignal.c) +foreach(obj top-half-emulated-signal-shared top-half-emulated-signal-static) + target_compile_definitions(${obj} PRIVATE _WASI_EMULATED_SIGNAL) +endforeach() + +add_object_library(bottom-half-emulated-signal signal.c) + +add_internal_shared_library(wasi-emulated-signal + $ + $) + +add_library(wasi-emulated-signal-static STATIC + $ + $) + +sysroot_lib(wasi-emulated-signal-static libwasi-emulated-signal.a) +sysroot_lib(wasi-emulated-signal libwasi-emulated-signal.so) diff --git a/libc-top-half/CMakeLists.txt b/libc-top-half/CMakeLists.txt new file mode 100644 index 000000000..7d76d1b2f --- /dev/null +++ b/libc-top-half/CMakeLists.txt @@ -0,0 +1,560 @@ +# Dummy interface library which helps configure headers/options for internal +# libraries below. +add_library(musl-top-half-interface INTERFACE) +target_include_directories(musl-top-half-interface INTERFACE + musl/src/include + musl/src/internal + musl/arch/wasm32 + musl/arch/generic + headers/private) +target_compile_options(musl-top-half-interface INTERFACE + -Wno-parentheses + -Wno-shift-op-parentheses + -Wno-bitwise-op-parentheses + -Wno-logical-op-parentheses + -Wno-string-plus-int + -Wno-dangling-else + -Wno-unknown-pragmas) +add_dependencies(musl-top-half-interface sysroot_inc) + +# ============================================================================= +# sysroot headers from the top-half +# + +# Generates `bits/alltypes.h` from the input sed script. +find_program(SED sed REQUIRED) +add_custom_command( + OUTPUT ${SYSROOT_INC}/bits/alltypes.h + COMMAND ${CMAKE_COMMAND} -E make_directory ${SYSROOT_INC}/bits + COMMAND + ${SED} -f musl/tools/mkalltypes.sed + musl/arch/wasm32/bits/alltypes.h.in + musl/include/alltypes.h.in + > ${SYSROOT_INC}/bits/alltypes.h + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS + musl/tools/mkalltypes.sed + musl/arch/wasm32/bits/alltypes.h.in + musl/include/alltypes.h.in +) +add_custom_target(sysroot-bits-alltypes DEPENDS ${SYSROOT_INC}/bits/alltypes.h) +add_dependencies(sysroot_inc sysroot-bits-alltypes) + +file(GLOB_RECURSE globbed_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS + # Copy in the bulk of musl's public header files. + musl/include/*.h + # Copy in the musl's "bits" header files. + musl/arch/generic/bits/*.h + musl/arch/wasm32/bits/*.h +) + +list(REMOVE_ITEM globbed_headers + # Use the compiler's version of these headers. + musl/include/stdarg.h + musl/include/stddef.h + + # Use the WASI errno definitions. + musl/arch/generic/bits/errno.h + + # Remove headers that aren't supported yet or that aren't relevant for WASI. + musl/arch/generic/bits/dirent.h + musl/arch/generic/bits/fcntl.h + musl/arch/generic/bits/ioctl.h + musl/arch/generic/bits/ipc.h + musl/arch/generic/bits/kd.h + musl/arch/generic/bits/limits.h + musl/arch/generic/bits/link.h + musl/arch/generic/bits/msg.h + musl/arch/generic/bits/ptrace.h + musl/arch/generic/bits/sem.h + musl/arch/generic/bits/shm.h + musl/arch/generic/bits/soundcard.h + musl/arch/generic/bits/statfs.h + musl/arch/generic/bits/termios.h + musl/arch/generic/bits/vt.h + musl/include/aio.h + musl/include/elf.h + musl/include/grp.h + musl/include/lastlog.h + musl/include/libintl.h + musl/include/link.h + musl/include/mntent.h + musl/include/net/ethernet.h + musl/include/net/if.h + musl/include/net/if_arp.h + musl/include/net/route.h + musl/include/netinet/ether.h + musl/include/netinet/if_ether.h + musl/include/paths.h + musl/include/pty.h + musl/include/pwd.h + musl/include/pwd.h + musl/include/resolv.h + musl/include/scsi/scsi.h + musl/include/scsi/scsi_ioctl.h + musl/include/scsi/sg.h + musl/include/shadow.h + musl/include/spawn.h + musl/include/sys/acct.h + musl/include/sys/auxv.h + musl/include/sys/cachectl.h + musl/include/sys/epoll.h + musl/include/sys/fanotify.h + musl/include/sys/fsuid.h + musl/include/sys/inotify.h + musl/include/sys/io.h + musl/include/sys/ipc.h + musl/include/sys/kd.h + musl/include/sys/klog.h + musl/include/sys/membarrier.h + musl/include/sys/mount.h + musl/include/sys/msg.h + musl/include/sys/mtio.h + musl/include/sys/personality.h + musl/include/sys/prctl.h + musl/include/sys/procfs.h + musl/include/sys/ptrace.h + musl/include/sys/quota.h + musl/include/sys/reboot.h + musl/include/sys/sem.h + musl/include/sys/sendfile.h + musl/include/sys/shm.h + musl/include/sys/signalfd.h + musl/include/sys/soundcard.h + musl/include/sys/statfs.h + musl/include/sys/swap.h + musl/include/sys/syslog.h + musl/include/sys/sysmacros.h + musl/include/sys/termios.h + musl/include/sys/timerfd.h + musl/include/sys/ucontext.h + musl/include/sys/user.h + musl/include/sys/vfs.h + musl/include/sys/vt.h + musl/include/sys/wait.h + musl/include/sys/xattr.h + musl/include/syslog.h + musl/include/termios.h + musl/include/ucontext.h + musl/include/ulimit.h + musl/include/utmp.h + musl/include/utmpx.h + musl/include/wait.h + musl/include/wordexp.h +) + +# Exclude `netdb.h` from all of the p1 targets. +if(WASI STREQUAL "p1") + list(REMOVE_ITEM globbed_headers + musl/include/netdb.h + ) +endif() + +foreach(header ${globbed_headers}) + if(${header} MATCHES "^musl/include/") + string(REPLACE "musl/include/" "" dst ${header}) + elseif(${header} MATCHES "^musl/arch/generic/bits/") + string(REPLACE "musl/arch/generic/" "" dst ${header}) + elseif(${header} MATCHES "^musl/arch/wasm32/bits/") + string(REPLACE "musl/arch/wasm32/" "" dst ${header}) + else() + message(FATAL_ERROR "Unhandled header file path: ${header}") + endif() + add_sysroot_header(${header} ${dst}) +endforeach() + +# ============================================================================= +# Object libraries for in-tree source files +# + +set(top_half_sources + musl/src/dirent/alphasort.c + musl/src/dirent/versionsort.c + musl/src/env/__init_tls.c + musl/src/env/__stack_chk_fail.c + musl/src/env/clearenv.c + musl/src/env/getenv.c + musl/src/env/putenv.c + musl/src/env/setenv.c + musl/src/env/unsetenv.c + musl/src/errno/strerror.c + musl/src/exit/assert.c + musl/src/exit/at_quick_exit.c + musl/src/exit/atexit.c + musl/src/exit/exit.c + musl/src/exit/quick_exit.c + musl/src/fcntl/creat.c + musl/src/fenv/fegetexceptflag.c + musl/src/fenv/feholdexcept.c + musl/src/fenv/fenv.c + musl/src/fenv/fesetexceptflag.c + musl/src/fenv/fesetround.c + musl/src/fenv/feupdateenv.c + musl/src/internal/defsysinfo.c + musl/src/internal/intscan.c + musl/src/internal/libc.c + musl/src/internal/shgetc.c + musl/src/legacy/getpagesize.c + musl/src/misc/a64l.c + musl/src/misc/basename.c + musl/src/misc/dirname.c + musl/src/misc/ffs.c + musl/src/misc/ffsl.c + musl/src/misc/ffsll.c + musl/src/misc/fmtmsg.c + musl/src/misc/getdomainname.c + musl/src/misc/gethostid.c + musl/src/misc/getopt.c + musl/src/misc/getopt_long.c + musl/src/misc/getsubopt.c + musl/src/misc/nftw.c + musl/src/misc/realpath.c + musl/src/misc/uname.c + musl/src/network/htonl.c + musl/src/network/htons.c + musl/src/network/in6addr_any.c + musl/src/network/in6addr_loopback.c + musl/src/network/inet_addr.c + musl/src/network/inet_aton.c + musl/src/network/inet_legacy.c + musl/src/network/inet_ntoa.c + musl/src/network/inet_ntop.c + musl/src/network/inet_pton.c + musl/src/network/ntohl.c + musl/src/network/ntohs.c + musl/src/stat/futimesat.c + musl/src/thread/default_attr.c + musl/src/thread/pthread_attr_destroy.c + musl/src/thread/pthread_attr_get.c + musl/src/thread/pthread_attr_init.c + musl/src/thread/pthread_attr_setdetachstate.c + musl/src/thread/pthread_attr_setguardsize.c + musl/src/thread/pthread_attr_setschedparam.c + musl/src/thread/pthread_attr_setstack.c + musl/src/thread/pthread_attr_setstacksize.c + musl/src/thread/pthread_barrierattr_destroy.c + musl/src/thread/pthread_barrierattr_init.c + musl/src/thread/pthread_barrierattr_setpshared.c + musl/src/thread/pthread_cancel.c + musl/src/thread/pthread_cleanup_push.c + musl/src/thread/pthread_condattr_destroy.c + musl/src/thread/pthread_condattr_init.c + musl/src/thread/pthread_condattr_setclock.c + musl/src/thread/pthread_condattr_setpshared.c + musl/src/thread/pthread_equal.c + musl/src/thread/pthread_getattr_np.c + musl/src/thread/pthread_getspecific.c + musl/src/thread/pthread_key_create.c + musl/src/thread/pthread_mutex_destroy.c + musl/src/thread/pthread_mutex_init.c + musl/src/thread/pthread_mutexattr_destroy.c + musl/src/thread/pthread_mutexattr_init.c + musl/src/thread/pthread_mutexattr_setprotocol.c + musl/src/thread/pthread_mutexattr_setpshared.c + musl/src/thread/pthread_mutexattr_setrobust.c + musl/src/thread/pthread_mutexattr_settype.c + musl/src/thread/pthread_rwlock_destroy.c + musl/src/thread/pthread_rwlock_init.c + musl/src/thread/pthread_rwlockattr_destroy.c + musl/src/thread/pthread_rwlockattr_init.c + musl/src/thread/pthread_rwlockattr_setpshared.c + musl/src/thread/pthread_self.c + musl/src/thread/pthread_setcancelstate.c + musl/src/thread/pthread_setcanceltype.c + musl/src/thread/pthread_setspecific.c + musl/src/thread/pthread_spin_destroy.c + musl/src/thread/pthread_spin_init.c + musl/src/thread/pthread_testcancel.c + musl/src/thread/thrd_sleep.c + musl/src/time/__month_to_secs.c + musl/src/time/__secs_to_tm.c + musl/src/time/__tm_to_secs.c + musl/src/time/__tz.c + musl/src/time/__year_to_secs.c + musl/src/time/asctime.c + musl/src/time/asctime_r.c + musl/src/time/ctime.c + musl/src/time/ctime_r.c + musl/src/time/difftime.c + musl/src/time/ftime.c + musl/src/time/getdate.c + musl/src/time/gmtime.c + musl/src/time/gmtime_r.c + musl/src/time/localtime.c + musl/src/time/localtime_r.c + musl/src/time/mktime.c + musl/src/time/strftime.c + musl/src/time/strptime.c + musl/src/time/timegm.c + musl/src/time/timespec_get.c + musl/src/time/wcsftime.c + musl/src/unistd/gethostname.c + musl/src/unistd/posix_close.c + sources/arc4random.c +) + +set(MUSL_PRINTSCAN_SOURCES + musl/src/internal/floatscan.c + musl/src/stdio/vfprintf.c + musl/src/stdio/vfscanf.c + musl/src/stdio/vfwprintf.c + musl/src/stdlib/strtod.c + musl/src/stdlib/wcstod.c) + +set(MUSL_BULK_MEMORY_SOURCES + musl/src/string/memcpy.c + musl/src/string/memmove.c + musl/src/string/memset.c) + +# Note that cmake generally recommends against globbing sources, but there's so +# many here and this doesn't change enough that it feels worth it... +# +# THis also pulls in too many sources, so more are removed below. +file(GLOB globbed_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS + musl/src/complex/*.c + musl/src/conf/*.c + musl/src/crypt/*.c + musl/src/ctype/*.c + musl/src/locale/*.c + musl/src/math/*.c + musl/src/multibyte/*.c + musl/src/prng/*.c + musl/src/regex/*.c + musl/src/search/*.c + musl/src/stdio/*.c + musl/src/stdlib/*.c + musl/src/string/*.c +) +list(REMOVE_ITEM globbed_sources + # handled below during printscan/bulk-memory library handling + ${MUSL_PRINTSCAN_SOURCES} + ${MUSL_BULK_MEMORY_SOURCES} + # not needed and/or don't compile on wasi + musl/src/complex/cimag.c + musl/src/complex/cimagf.c + musl/src/complex/cimagl.c + musl/src/complex/creal.c + musl/src/complex/crealf.c + musl/src/complex/creall.c + musl/src/locale/bind_textdomain_codeset.c + musl/src/locale/dcngettext.c + musl/src/locale/textdomain.c + musl/src/math/__fpclassify.c + musl/src/math/__fpclassifyf.c + musl/src/math/__fpclassifyl.c + musl/src/math/__signbit.c + musl/src/math/__signbitf.c + musl/src/math/__signbitl.c + musl/src/math/ceil.c + musl/src/math/ceilf.c + musl/src/math/copysign.c + musl/src/math/copysignf.c + musl/src/math/fabs.c + musl/src/math/fabsf.c + musl/src/math/floor.c + musl/src/math/floorf.c + musl/src/math/fmax.c + musl/src/math/fmaxf.c + musl/src/math/fmin.c + musl/src/math/fminf.c + musl/src/math/nearbyint.c + musl/src/math/nearbyintf.c + musl/src/math/rint.c + musl/src/math/rintf.c + musl/src/math/sqrt.c + musl/src/math/sqrtf.c + musl/src/math/trunc.c + musl/src/math/truncf.c + musl/src/stdio/__lockfile.c + musl/src/stdio/flockfile.c + musl/src/stdio/ftrylockfile.c + musl/src/stdio/funlockfile.c + musl/src/stdio/gets.c + musl/src/stdio/pclose.c + musl/src/stdio/popen.c + musl/src/stdio/remove.c + musl/src/stdio/rename.c + musl/src/stdio/tempnam.c + musl/src/stdio/tmpfile.c + musl/src/stdio/tmpnam.c + musl/src/string/strsignal.c +) + +list(APPEND top_half_sources ${globbed_sources}) + +if (WASI STREQUAL "p2") + list(APPEND top_half_sources + musl/src/network/gai_strerror.c + ) +endif() + +if (THREADS) + # pthreads functions needed for actual thread support + list(APPEND top_half_sources + musl/src/stdio/__lockfile.c + musl/src/stdio/flockfile.c + musl/src/stdio/ftrylockfile.c + musl/src/stdio/funlockfile.c + musl/src/thread/__lock.c + musl/src/thread/__wait.c + musl/src/thread/__timedwait.c + musl/src/thread/pthread_barrier_destroy.c + musl/src/thread/pthread_barrier_init.c + musl/src/thread/pthread_barrier_wait.c + musl/src/thread/pthread_cond_broadcast.c + musl/src/thread/pthread_cond_destroy.c + musl/src/thread/pthread_cond_init.c + musl/src/thread/pthread_cond_signal.c + musl/src/thread/pthread_cond_timedwait.c + musl/src/thread/pthread_cond_wait.c + musl/src/thread/pthread_create.c + musl/src/thread/pthread_detach.c + musl/src/thread/pthread_join.c + musl/src/thread/pthread_mutex_consistent.c + musl/src/thread/pthread_mutex_getprioceiling.c + musl/src/thread/pthread_mutex_lock.c + musl/src/thread/pthread_mutex_timedlock.c + musl/src/thread/pthread_mutex_trylock.c + musl/src/thread/pthread_mutex_unlock.c + musl/src/thread/pthread_once.c + musl/src/thread/pthread_rwlock_rdlock.c + musl/src/thread/pthread_rwlock_timedrdlock.c + musl/src/thread/pthread_rwlock_timedwrlock.c + musl/src/thread/pthread_rwlock_tryrdlock.c + musl/src/thread/pthread_rwlock_trywrlock.c + musl/src/thread/pthread_rwlock_unlock.c + musl/src/thread/pthread_rwlock_wrlock.c + musl/src/thread/pthread_spin_lock.c + musl/src/thread/pthread_spin_trylock.c + musl/src/thread/pthread_spin_unlock.c + musl/src/thread/sem_destroy.c + musl/src/thread/sem_getvalue.c + musl/src/thread/sem_init.c + musl/src/thread/sem_post.c + musl/src/thread/sem_timedwait.c + musl/src/thread/sem_trywait.c + musl/src/thread/sem_wait.c + musl/src/thread/wasm32/wasi_thread_start.s + musl/src/thread/wasm32/__wasilibc_busywait.c + ) +else() + # pthreads stubs for single-threaded environment + list(APPEND top_half_sources + ../thread-stub/pthread_barrier_destroy.c + ../thread-stub/pthread_barrier_init.c + ../thread-stub/pthread_barrier_wait.c + ../thread-stub/pthread_cond_broadcast.c + ../thread-stub/pthread_cond_destroy.c + ../thread-stub/pthread_cond_init.c + ../thread-stub/pthread_cond_signal.c + ../thread-stub/pthread_cond_timedwait.c + ../thread-stub/pthread_cond_wait.c + ../thread-stub/pthread_create.c + ../thread-stub/pthread_detach.c + ../thread-stub/pthread_join.c + ../thread-stub/pthread_mutex_consistent.c + ../thread-stub/pthread_mutex_getprioceiling.c + ../thread-stub/pthread_mutex_lock.c + ../thread-stub/pthread_mutex_timedlock.c + ../thread-stub/pthread_mutex_trylock.c + ../thread-stub/pthread_mutex_unlock.c + ../thread-stub/pthread_once.c + ../thread-stub/pthread_rwlock_rdlock.c + ../thread-stub/pthread_rwlock_timedrdlock.c + ../thread-stub/pthread_rwlock_timedwrlock.c + ../thread-stub/pthread_rwlock_tryrdlock.c + ../thread-stub/pthread_rwlock_trywrlock.c + ../thread-stub/pthread_rwlock_unlock.c + ../thread-stub/pthread_rwlock_wrlock.c + ../thread-stub/pthread_spin_lock.c + ../thread-stub/pthread_spin_trylock.c + ../thread-stub/pthread_spin_unlock.c + ) +endif() + +add_object_library(top-half ${top_half_sources}) +foreach(obj top-half-shared top-half-static) + target_link_libraries(${obj} PUBLIC musl-top-half-interface) +endforeach() + +if (LTO) + set_source_files_properties(musl/src/exit/atexit.c + PROPERTIES COMPILE_OPTIONS -fno-lto) +endif() + +# ============================================================================= +# printscan library handling +# +# There are three copies of the printscan-related functions built: +# +# 1. `printscan_default` - long double support is disabled but float support +# is enabled. +# 2. `printscan_nofloat` - floats are entirely disabled. +# 3. `printscan_longdouble` - long double + floats enabled +# +# These are the included in various final artifacts in various ways. + +add_internal_object_library(printscan-default ${MUSL_PRINTSCAN_SOURCES}) +add_internal_object_library(printscan-nofloat ${MUSL_PRINTSCAN_SOURCES}) +add_internal_object_library(printscan-longdouble ${MUSL_PRINTSCAN_SOURCES}) + +foreach(obj printscan-default-shared printscan-default-static) + target_compile_definitions(${obj} PRIVATE + __wasilibc_printscan_no_long_double + __wasilibc_printscan_full_support_option="add -lc-printscan-long-double to the link command") +endforeach() + +foreach(obj printscan-nofloat-shared printscan-nofloat-static) + target_compile_definitions(${obj} PRIVATE + __wasilibc_printscan_no_floating_point + __wasilibc_printscan_floating_point_support_option="remove -lc-printscan-no-floating-point from the link command") +endforeach() + +# Add explicit `*.a` files to the sysroot which can be manually selected by +# consumers via `-l`. +add_library(c-printscan-long-double STATIC EXCLUDE_FROM_ALL $) +add_library(c-printscan-no-floating-point STATIC EXCLUDE_FROM_ALL $) +sysroot_lib(c-printscan-long-double libc-printscan-long-double.a) +sysroot_lib(c-printscan-no-floating-point libc-printscan-no-floating-point.a) + +# ============================================================================= +# bulk memory handling +# +# TODO: apply -mbulk-memory globally, once +# https://github.com/llvm/llvm-project/issues/52618 is resolved +add_internal_object_library(bulk-memory ${MUSL_BULK_MEMORY_SOURCES}) + +foreach(obj bulk-memory-shared bulk-memory-static) + target_compile_definitions(${obj} PRIVATE -DBULK_MEMORY_THRESHOLD=${BULK_MEMORY_THRESHOLD}) + target_compile_options(${obj} PRIVATE -mbulk-memory) +endforeach() + +# ============================================================================= +# libsetjmp.{a,so} +# +add_internal_library_pair(setjmp musl/src/setjmp/wasm32/rt.c) + +if (LTO) + set_source_files_properties(musl/src/setjmp/wasm32/rt.c + PROPERTIES COMPILE_OPTIONS -fno-lto) +endif() + +foreach(obj setjmp setjmp-static) + target_compile_options(${obj} PRIVATE -mllvm -wasm-enable-sjlj) + target_link_options(${obj} PRIVATE + -Wl,--allow-undefined-file=${CMAKE_SOURCE_DIR}/linker-provided-symbols.txt) +endforeach() + +if (SETJMP) + sysroot_lib(setjmp libsetjmp.so) + sysroot_lib(setjmp-static libsetjmp.a) +endif() + +# ============================================================================= +# libdl.{a,so} +# +add_internal_library_pair(dl musl/src/misc/dl.c) + +sysroot_lib(dl libdl.so) +sysroot_lib(dl-static libdl.a) diff --git a/scripts/install-include-headers.sh b/scripts/install-include-headers.sh deleted file mode 100755 index efa48aa6d..000000000 --- a/scripts/install-include-headers.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash -# -# Install all the necessary necessary include files from wasi-libc -# (`$WASI_LIBC`) into the sysroot include directory (`$SYSROOT_INC`). It uses a -# passed target triple (`$TARGET_TRIPLE`) to condition some of the -# copied/generated files. -# -# Usage: SYSROOT_INC=... TARGET_TRIPLE=... ./install-include-headers.sh - -set -euo pipefail - -PARENT_DIR=$(dirname $(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)) -WASI_LIBC="${WASI_LIBC:-$PARENT_DIR}" -if [[ -z "${SYSROOT_INC}" || -z "${TARGET_TRIPLE}" ]]; then - echo "usage: SYSROOT_INC=... TARGET_TRIPLE=... ./install-include-headers.sh" - exit 1 -fi -# The commands are available for override to allow dry runs. -CP="${CP:-cp -v}" -RM="${RM:-rm -v}" -MKDIR="${MKDIR:-mkdir}" -SED="${SED:-sed}" - -# Copy in the bottom half's public headers. -$MKDIR -p $SYSROOT_INC -$CP -r $WASI_LIBC/libc-bottom-half/headers/public/* $SYSROOT_INC - -# Copy in the bulk of musl's public header files. -$CP -r $WASI_LIBC/libc-top-half/musl/include/* $SYSROOT_INC - -# Copy in the musl's "bits" header files. -$MKDIR -p $SYSROOT_INC/bits -$CP -r $WASI_LIBC/libc-top-half/musl/arch/generic/bits/* $SYSROOT_INC/bits -$CP -r $WASI_LIBC/libc-top-half/musl/arch/wasm32/bits/* $SYSROOT_INC/bits - -# Generate musl's bits/alltypes.h header. -(set -x; $SED -f $WASI_LIBC/libc-top-half/musl/tools/mkalltypes.sed \ - $WASI_LIBC/libc-top-half/musl/arch/wasm32/bits/alltypes.h.in \ - $WASI_LIBC/libc-top-half/musl/include/alltypes.h.in \ - > $SYSROOT_INC/bits/alltypes.h) - -# Copy in the fts header files. -$CP $WASI_LIBC/fts/musl-fts/fts.h $SYSROOT_INC/fts.h - -# Remove selected header files. These are files from musl's include directory -# that we don't want to install in the sysroot's include directory. -MUSL_OMIT_HEADERS=() -# Remove files which aren't headers (we generate `alltypes.h` above). -MUSL_OMIT_HEADERS+=("bits/syscall.h.in" "bits/alltypes.h.in" "alltypes.h.in") -# Use the compiler's version of these headers. -MUSL_OMIT_HEADERS+=("stdarg.h" "stddef.h") -# Use the WASI errno definitions. -MUSL_OMIT_HEADERS+=("bits/errno.h") -# Remove headers that aren't supported yet or that aren't relevant for WASI. -MUSL_OMIT_HEADERS+=("sys/procfs.h" "sys/user.h" "sys/kd.h" "sys/vt.h" \ - "sys/soundcard.h" "sys/sem.h" "sys/shm.h" "sys/msg.h" "sys/ipc.h" \ - "sys/ptrace.h" "sys/statfs.h" "bits/kd.h" "bits/vt.h" "bits/soundcard.h" \ - "bits/sem.h" "bits/shm.h" "bits/msg.h" "bits/ipc.h" "bits/ptrace.h" \ - "bits/statfs.h" "sys/vfs.h" "syslog.h" "sys/syslog.h" "wait.h" \ - "sys/wait.h" "ucontext.h" "sys/ucontext.h" "paths.h" "utmp.h" "utmpx.h" \ - "lastlog.h" "sys/acct.h" "sys/cachectl.h" "sys/epoll.h" "sys/reboot.h" \ - "sys/swap.h" "sys/sendfile.h" "sys/inotify.h" "sys/quota.h" "sys/klog.h" \ - "sys/fsuid.h" "sys/io.h" "sys/prctl.h" "sys/mtio.h" "sys/mount.h" \ - "sys/fanotify.h" "sys/personality.h" "elf.h" "link.h" "bits/link.h" \ - "scsi/scsi.h" "scsi/scsi_ioctl.h" "scsi/sg.h" "sys/auxv.h" "pwd.h" \ - "shadow.h" "grp.h" "mntent.h" "resolv.h" "pty.h" "ulimit.h" "sys/xattr.h" \ - "wordexp.h" "spawn.h" "sys/membarrier.h" "sys/signalfd.h" "termios.h" \ - "sys/termios.h" "bits/termios.h" "net/if.h" "net/if_arp.h" \ - "net/ethernet.h" "net/route.h" "netinet/if_ether.h" "netinet/ether.h" \ - "sys/timerfd.h" "libintl.h" "sys/sysmacros.h" "aio.h") -# Exclude `netdb.h` from all of the p1 targets. -if [[ $TARGET_TRIPLE == *"wasi" || $TARGET_TRIPLE == *"wasi-threads" || \ - $TARGET_TRIPLE == *"wasip1" || $TARGET_TRIPLE == *"wasip1-threads" ]]; then - MUSL_OMIT_HEADERS+=("netdb.h") -fi - -# Remove all the `MUSL_OMIT_HEADERS` previously copied over. -for OMIT_HEADER in "${MUSL_OMIT_HEADERS[@]}"; do - $RM -f $SYSROOT_INC/$OMIT_HEADER -done - -# Update the `__wasi_snapshot.h` with some additional p2 definitions. -if [[ $TARGET_TRIPLE == *"p2" ]]; then - printf '#ifndef __wasilibc_use_wasip2\n#define __wasilibc_use_wasip2\n#endif\n' \ - > $SYSROOT_INC/__wasi_snapshot.h -fi diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2f53c7b5e..97582e09d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,40 +1,10 @@ -cmake_minimum_required(VERSION 3.26) -project(wasi-libc-tests) - -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() - -message(STATUS "Found executable for `nm`: ${CMAKE_NM}") -message(STATUS "Found executable for `ar`: ${CMAKE_AR}") -message(STATUS "Found executable for `ranlib`: ${CMAKE_RANLIB}") - include(FetchContent) include(ExternalProject) include(CTest) enable_testing() -set(TARGET_TRIPLE "wasm32-wasi" CACHE STRING "WASI target to test") -set(MALLOC_IMPL "" CACHE STRING "Malloc implementation in use") option(PYTHON_TESTS "Build Python with this wasi-libc and run its tests" OFF) -# ========= Sysroot sanity check ================================ - -cmake_path(GET CMAKE_CURRENT_SOURCE_DIR PARENT_PATH LIBC_SRC_DIR) -set(SYSROOT_DIR "${LIBC_SRC_DIR}/sysroot") -set(SYSROOT "${SYSROOT_DIR}/lib/${TARGET_TRIPLE}") - -# This build configuration does not currently manage the sysroot itself (but -# ideally it will one day). Double-check that the sysroot exists before actually -# trying to build any tests. -if (NOT EXISTS "${SYSROOT_DIR}") - message(FATAL_ERROR " - No sysroot for ${TARGET_TRIPLE} available at ${SYSROOT_DIR}; to build it, e.g.: - cd ${LIBC_SRC_DIR} - make TARGET_TRIPLE=${TARGET_TRIPLE} - ") -endif() - # ========= Clone libc-test ===================================== FetchContent_Declare( @@ -48,39 +18,18 @@ set(LIBC_TEST "${libc-test_SOURCE_DIR}") message(STATUS "libc-test source directory: ${LIBC_TEST}") # ========= Download wasmtime as a test runner ================== +include(ba-download) if(NOT ENGINE OR ENGINE STREQUAL "") - set(WASMTIME_VERSION "v38.0.2") - set(WASMTIME_REPO "https://github.com/bytecodealliance/wasmtime") - - if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(WASMTIME_ARCH "x86_64") - elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") - set(WASMTIME_ARCH "aarch64") - elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "aarch64") - set(WASMTIME_ARCH "aarch64") - else() - message(FATAL_ERROR "Unsupported architecture ${CMAKE_HOST_SYSTEM_PROCESSOR} for Wasmtime") - endif() - - if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") - set(WASMTIME_OS macos) - elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") - set(WASMTIME_OS linux) - else() - message(FATAL_ERROR "Unsupported system ${CMAKE_SYSTEM_NAME} for Wasmtime") - endif() - - ExternalProject_Add( - engine - URL "${WASMTIME_REPO}/releases/download/${WASMTIME_VERSION}/wasmtime-${WASMTIME_VERSION}-${WASMTIME_ARCH}-${WASMTIME_OS}.tar.xz" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" + ba_download( + wasmtime + "https://github.com/bytecodealliance/wasmtime" + "v38.0.2" ) - ExternalProject_Get_Property(engine SOURCE_DIR) + ExternalProject_Get_Property(wasmtime SOURCE_DIR) set(ENGINE "${SOURCE_DIR}/wasmtime") message(STATUS "Wasmtime executable: ${ENGINE}") + add_custom_target(engine ALL DEPENDS wasmtime) else() add_custom_target(engine) endif() @@ -88,17 +37,12 @@ endif() # ========= libc-test defined tests ============================= function(add_wasilibc_flags target) - target_compile_options(${target} PRIVATE - "--target=${TARGET_TRIPLE}" - "--sysroot=${SYSROOT_DIR}" - ) - target_link_options(${target} PRIVATE - "--target=${TARGET_TRIPLE}" - "--sysroot=${SYSROOT_DIR}" - "-resource-dir=${LIBC_SRC_DIR}/build/${TARGET_TRIPLE}/resource-dir" - ) + add_dependencies(${target} sysroot builtins) + # Using an `INTERFACE` looks to get what we want here which is to rebuild this + # if the library changes but not actually add any arguments to the link-line. + target_link_libraries(${target} INTERFACE c-static) + if (TARGET_TRIPLE MATCHES "-threads") - target_compile_options(${target} PRIVATE -pthread) target_link_options(${target} PRIVATE -pthread -Wl,--import-memory,--export-memory,--shared-memory,--max-memory=1073741824) endif() @@ -131,7 +75,7 @@ function(add_test_executable executable_name src) # Build the test exeutable itself and apply all custom options as applicable. add_executable(${executable_name} ${src}) add_wasilibc_flags(${executable_name}) - target_link_libraries(${executable_name} libc_test_support) + target_link_libraries(${executable_name} PRIVATE libc_test_support) foreach(flag IN LISTS arg_CFLAGS) target_compile_options(${executable_name} PRIVATE ${flag}) endforeach() @@ -235,14 +179,14 @@ add_libc_test(functional/memstream.c) add_libc_test(functional/qsort.c) add_libc_test(functional/random.c) add_libc_test(functional/search_hsearch.c) -if (MALLOC_IMPL STREQUAL "emmalloc") +if (MALLOC STREQUAL "emmalloc") set_tests_properties(libc_test_functional_search_hsearch.wasm PROPERTIES WILL_FAIL TRUE) endif() add_libc_test(functional/search_insque.c) add_libc_test(functional/search_lsearch.c) add_libc_test(functional/search_tsearch.c) add_libc_test(functional/snprintf.c) -add_libc_test(functional/sscanf.c) +add_libc_test(functional/sscanf.c CFLAGS -Wno-literal-range) add_libc_test(functional/strftime.c) add_libc_test(functional/string.c) add_libc_test(functional/string_memcpy.c) @@ -451,7 +395,7 @@ if (PYTHON_TESTS) find_program(PYTHON python3 python REQUIRED) find_program(MAKE make REQUIRED) - set(flags "--target=${TARGET_TRIPLE} --sysroot=${SYSROOT_DIR}") + set(flags "--target=${TARGET_TRIPLE} --sysroot=${SYSROOT}") ExternalProject_Add( python @@ -514,4 +458,5 @@ if (PYTHON_TESTS) -E env CFLAGS=${flags} LDFLAGS=${flags} -- ${MAKE} --directory cross-build/wasm32-wasip1 test ) + ExternalProject_Add_StepDependencies(python configure sysroot) endif()