Skip to content

Commit

Permalink
Rewrite build system to build everything from scratch.
Browse files Browse the repository at this point in the history
This also builds a "true" thread-free llvm, and tries to otherwise
minimize LLVM changes in favour of libc changes.
  • Loading branch information
veluca93 committed Jan 4, 2024
1 parent 67ad378 commit f786a28
Show file tree
Hide file tree
Showing 16 changed files with 5,244 additions and 864 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "cpython"]
path = cpython
url = https://github.com/python/cpython.git
[submodule "wasi-libc"]
path = wasi-libc
url = https://github.com/WebAssembly/wasi-libc.git
216 changes: 163 additions & 53 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,61 +1,171 @@
WASI_SDK_PREFIX ?= /opt/wasi-sdk/
PYTHON ?= /usr/bin/env python3
PYTHON := /usr/bin/env python3
DIR := $(shell pwd)
WASMTIME ?= $(shell which wasmtime)
WASMTIME_FLAGS ?= --wasm max-wasm-stack=8388608 --dir {HOST_DIR}::{GUEST_DIR} \
--env {ENV_VAR_NAME}={ENV_VAR_VALUE} {PYTHON_WASM}

.PHONY:
all: test build/output.tar.br

build/output.tar.br: build/output/python build/output/cpp
tar c -C build/output . | brotli --large_window=30 > $@

build/output/python:
rm -rf "$@"
${PYTHON} cpython/Tools/wasm/wasi.py build \
--host-runner="${WASMTIME} run ${WASMTIME_FLAGS}" -- \
--prefix="${DIR}/$@" --exec-prefix="${DIR}/$@" \
--disable-test-modules
make -C cpython/cross-build/wasm32-wasi install

build/libwasishim.a: wasi_shim.cpp
${WASI_SDK_PREFIX}/bin/clang++ -fno-exceptions -std=c++20 $< -O3 -c -o $@

build/llvm-sources: llvm.patch
rm -rf "$@"
cp -r llvm "$@"
cd "$@" && patch -p1 < ${DIR}/llvm.patch

build/llvm-build: build/llvm-sources build/libwasishim.a
cmake -B build/llvm-build build/llvm-sources/llvm \
-G Ninja -DCMAKE_BUILD_TYPE=Release \
-DWASI_SDK_PREFIX=${WASI_SDK_PREFIX} \
-DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_PREFIX}/share/cmake/wasi-sdk.cmake \
-DLLVM_TARGETS_TO_BUILD=WebAssembly -DLLVM_ENABLE_PROJECTS="clang;lld" \
SYSROOT := ${DIR}/build/sysroot
WASMTIME := $(shell which wasmtime)
CLANG_VERSION := $(shell /usr/bin/env bash ./llvm_version_major.sh llvm)

OUTPUT := ${DIR}/build/output

LLVM_HOST := ${DIR}/build/llvm-host

WASM_CC := ${LLVM_HOST}/bin/clang
WASM_CXX := ${LLVM_HOST}/bin/clang++
WASM_NM := ${LLVM_HOST}/bin/llvm-nm
WASM_AR := ${LLVM_HOST}/bin/llvm-ar
WASM_CFLAGS := -ffile-prefix-map=${DIR}=/
WASM_CXXFLAGS := -ffile-prefix-map=${DIR}=/
WASM_LDFLAGS := -Wl,-z -Wl,stack-size=1048576
MAKE := make

all: ${OUTPUT}.DONE test

build:
mkdir -p build

build/llvm-host.BUILT: llvm | build
rsync -a --delete llvm/ build/llvm-host-src
cmake -S build/llvm-host-src/llvm -B build/llvm-host-build \
-DCMAKE_INSTALL_PREFIX="${DIR}/build/llvm-host" -DDEFAULT_SYSROOT=${SYSROOT} \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_TARGETS_TO_BUILD=WebAssembly -DLLVM_DEFAULT_TARGET_TRIPLE=wasm32-wasi \
-DLLVM_ENABLE_PROJECTS="clang;lld"
$(MAKE) -C build/llvm-host-build install
touch $@

build/wasi-libc.BUILT: wasi-libc wasi-libc-polyfill.c wasi-libc.patch build/llvm-host.BUILT | build
rsync -a --delete wasi-libc/ build/wasi-libc
cd "build/wasi-libc" && patch -p1 < ${DIR}/wasi-libc.patch
cp wasi-libc-polyfill.c build/wasi-libc
$(MAKE) -C build/wasi-libc THREAD_MODEL=single \
CC=${WASM_CC} AR=$(WASM_AR) NM=${WASM_NM} EXTRA_CFLAGS="${WASI_CFLAGS} -O2 -DNDEBUG" \
INSTALL_DIR=${SYSROOT} install
touch $@

build/llvm.SRC: llvm llvm.patch | build
rsync -a --delete llvm/ build/llvm-src
cd "build/llvm-src" && patch -p1 < ${DIR}/llvm.patch
touch $@

build/compiler-rt-host.BUILT: build/llvm.SRC build/wasi-libc.BUILT
mkdir -p build/compiler-rt-build-host
cmake -B build/compiler-rt-build-host -S build/llvm-src/compiler-rt/lib/builtins \
-DWASM_PREFIX=${LLVM_HOST} -DCMAKE_TOOLCHAIN_FILE=${DIR}/cmake/toolchain.cmake \
-DCMAKE_C_FLAGS="-I${DIR} ${WASM_C}" \
-DCOMPILER_RT_BAREMETAL_BUILD=On \
-DCOMPILER_RT_INCLUDE_TESTS=OFF \
-DCOMPILER_RT_HAS_FPIC_FLAG=OFF \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=On \
-DCOMPILER_RT_OS_DIR=wasi \
-DCMAKE_INSTALL_PREFIX=${LLVM_HOST}/lib/clang/$(CLANG_VERSION)/
$(MAKE) -C build/compiler-rt-build-host install
touch $@

build/compiler-rt.BUILT: build/llvm.SRC build/compiler-rt-host.BUILT
mkdir -p build/compiler-rt-build
cmake -B build/compiler-rt-build -S build/llvm-src/compiler-rt/lib/builtins \
-DWASM_PREFIX=${LLVM_HOST} -DCMAKE_TOOLCHAIN_FILE=${DIR}/cmake/toolchain.cmake \
-DCMAKE_C_FLAGS="-I${DIR} ${WASM_C}" \
-DCOMPILER_RT_BAREMETAL_BUILD=On \
-DCOMPILER_RT_INCLUDE_TESTS=OFF \
-DCOMPILER_RT_HAS_FPIC_FLAG=OFF \
-DCOMPILER_RT_DEFAULT_TARGET_ONLY=On \
-DCOMPILER_RT_OS_DIR=wasi \
-DCMAKE_INSTALL_PREFIX=${SYSROOT}/lib/clang/$(CLANG_VERSION)/
$(MAKE) -C build/compiler-rt-build install
touch $@

build/libcxx.BUILT: build/compiler-rt.BUILT
mkdir -p build/libcxx-build
# We disable checking the C++ compiler as we are building -lc++, which is needed by the check.
cmake -B build/libcxx-build -S build/llvm-src/runtimes \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_SYSROOT=$(SYSROOT) -DCMAKE_INSTALL_PREFIX="${SYSROOT}" -DDEFAULT_SYSROOT="/" \
-DWASM_PREFIX=${LLVM_HOST} -DCMAKE_TOOLCHAIN_FILE=${DIR}/cmake/toolchain.cmake \
-DCMAKE_C_FLAGS="-I${DIR} ${WASM_C}" \
-DCMAKE_CXX_FLAGS="-I${DIR} ${WASM_CXXFLAGS} -fno-exceptions" \
-DCMAKE_POSITION_INDEPENDENT_CODE=OFF \
-DCMAKE_C_COMPILER_WORKS=ON \
-DCMAKE_CXX_COMPILER_WORKS=ON \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \
-DLIBCXX_ENABLE_THREADS:BOOL=OFF \
-DLIBCXX_HAS_PTHREAD_API:BOOL=OFF \
-DLIBCXX_HAS_EXTERNAL_THREAD_API:BOOL=OFF \
-DLIBCXX_HAS_WIN32_THREAD_API:BOOL=OFF \
-DLIBCXX_ENABLE_SHARED:BOOL=OFF \
-DLIBCXX_ENABLE_EXCEPTIONS:BOOL=OFF \
-DLIBCXX_ENABLE_ABI_LINKER_SCRIPT:BOOL=OFF \
-DLIBCXX_CXX_ABI=libcxxabi \
-DLIBCXX_HAS_MUSL_LIBC:BOOL=ON \
-DLIBCXX_ABI_VERSION=2 \
-DLIBCXXABI_ENABLE_EXCEPTIONS:BOOL=OFF \
-DLIBCXXABI_ENABLE_SHARED:BOOL=OFF \
-DLIBCXXABI_SILENT_TERMINATE:BOOL=ON \
-DLIBCXXABI_ENABLE_THREADS:BOOL=OFF \
-DLIBCXXABI_HAS_PTHREAD_API:BOOL=OFF \
-DLIBCXXABI_HAS_EXTERNAL_THREAD_API:BOOL=OFF \
-DLIBCXXABI_HAS_WIN32_THREAD_API:BOOL=OFF \
-DLIBCXX_LIBDIR_SUFFIX=/wasm32-wasi \
-DLIBCXXABI_LIBDIR_SUFFIX=/wasm32-wasi
$(MAKE) -C build/libcxx-build install
touch $@

build/llvm.BUILT: build/llvm.SRC build/libcxx.BUILT
cmake -B build/llvm-build -S build/llvm-src/llvm \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_SYSROOT=$(SYSROOT) -DCMAKE_INSTALL_PREFIX="${SYSROOT}" -DDEFAULT_SYSROOT=/ \
-DWASM_PREFIX=${LLVM_HOST} -DCMAKE_TOOLCHAIN_FILE=${DIR}/cmake/toolchain.cmake \
-DCMAKE_C_FLAGS="-I${DIR} ${WASM_C}" \
-DCMAKE_CXX_FLAGS="-I${DIR} ${WASM_CXXFLAGS} -fno-exceptions" \
-DLLVM_TARGETS_TO_BUILD=WebAssembly -DLLVM_ENABLE_PROJECTS="clang;lld;clang-tools-extra" \
-DLLVM_ENABLE_THREADS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF \
-DLLVM_DEFAULT_TARGET_TRIPLE=wasm32-wasi -DCMAKE_MODULE_PATH=${DIR}/cmake \
-DCMAKE_CXX_FLAGS="-I${DIR} -fno-exceptions" -DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_DEFAULT_TARGET_TRIPLE=wasm32-wasi \
-DLLVM_INCLUDE_TESTS=OFF -DCLANG_PLUGIN_SUPPORT=OFF \
-DLLVM_BUILD_LLVM_DYLIB=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_ENABLE_PIC=OFF \
-DLLVM_INCLUDE_UTILS=OFF -DLLVM_BUILD_UTILS=OFF -DLLVM_ENABLE_PLUGINS=OFF \
-DCLANG_PLUGIN_SUPPORT=OFF \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-z -Wl,stack-size=1048576 -lwasishim -L${DIR}/build"
ninja -C build/llvm-build


build/output/cpp: build/llvm-build
rm -rf "$@"
mkdir -p $@/root
cp -Lr ${WASI_SDK_PREFIX}/share/wasi-sysroot/* $@/root/
cp -L ${WASI_SDK_PREFIX}/lib/clang/*/lib/wasi/libclang_rt.* $@/root/lib/wasm32-wasi/
rm -rf $@/root/share/wasm32-wasi-threads $@/root/lib/wasm32-wasi-threads
cp -Lr $</lib/clang/18/include $@/root/clang-include
cp -Lr $</bin/clang-18 $@/clang
cp -Lr $</bin/lld $@/wasm-ld

.PHONY:
test: | build/output/python build/output/cpp
-DCMAKE_EXE_LINKER_FLAGS="${WASM_LDFLAGS}"
$(MAKE) -C build/llvm-build install
touch "$@"

# Technically, this only needs wasi-libc, but errors get hidden otherwise.
build/python.BUILT: build/wasi-libc.BUILT build/llvm.BUILT
rsync -a --delete cpython/ build/cpython
mkdir -p build/cpython/host-build
cd build/cpython/host-build && ../configure --prefix=${DIR}/build/cpython/install --disable-test-modules
$(MAKE) -C build/cpython/host-build
mkdir -p build/cpython/wasm-build
cd build/cpython/wasm-build && \
../configure --target wasm32-wasi --host wasm32-wasi --build=$(shell $(CC) -dumpmachine) \
--with-build-python=${DIR}/build/cpython/host-build/python \
CC=${WASM_CC} AR=$(WASM_AR) NM=${WASM_NM} CFLAGS=${WASM_CFLAGS} \
--prefix=${DIR}/build/sysroot --with-lto=full \
--enable-wasm-pthreads=no --disable-test-modules \
CONFIG_SITE=${DIR}/cpython-config-override
$(MAKE) -C build/cpython/wasm-build install
touch "$@"

${OUTPUT}/cpp.COPIED: build/llvm.BUILT build/python.BUILT
mkdir -p ${OUTPUT}/cpp/{bin,lib,include}
rsync -avL ${SYSROOT}/bin/clang++ ${SYSROOT}/bin/wasm-ld ${OUTPUT}/cpp/bin/
rsync -avL ${SYSROOT}/lib/clang ${SYSROOT}/lib/wasm32-wasi ${OUTPUT}/cpp/lib/
rsync -avL ${SYSROOT}/include/c++ ${SYSROOT}/include/wasm32-wasi ${OUTPUT}/cpp/include/
touch "$@"

${OUTPUT}/python.COPIED: build/llvm.BUILT build/python.BUILT
mkdir -p ${OUTPUT}/python/{bin,lib,include}
rsync -avL ${SYSROOT}/bin/python3.13.wasm ${OUTPUT}/python/bin/
rsync -avL ${SYSROOT}/lib/libpython3.13.a ${SYSROOT}/lib/python3.13 --exclude python3.13/config-3.13-wasm32-wasi ${OUTPUT}/python/lib/
rsync -avL ${SYSROOT}/include/python3.13 ${OUTPUT}/python/include/
touch "$@"

test: test.sh ${OUTPUT}/cpp.COPIED ${OUTPUT}/python.COPIED
./test.sh

%.tar.br: %.COPIED
tar c -C $* . | brotli --large_window=30 > $@

${OUTPUT}.DONE: ${OUTPUT}/cpp.tar.br ${OUTPUT}/python.tar.br

clean:
rm -rf build/ cpython/cross-build

.PHONY: all test clean
4 changes: 1 addition & 3 deletions cmake/Platform/WASI.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
set(WASI 1)

# This is a lie, but llvm needs it.
set(UNIX 1)
set(TARGET_SUPPORTS_SHARED_LIBS FALSE)
24 changes: 24 additions & 0 deletions cmake/toolchain.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Inspired by wasi-sdk's toolchain file
cmake_minimum_required(VERSION 3.4.0)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")

set(CMAKE_SYSTEM_NAME WASI)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR wasm32)

set(triple wasm32-wasi)

set(CMAKE_C_COMPILER ${WASM_PREFIX}/bin/clang)
set(CMAKE_CXX_COMPILER ${WASM_PREFIX}/bin/clang++)
set(CMAKE_ASM_COMPILER ${WASM_PREFIX}/bin/clang)
set(CMAKE_AR ${WASM_PREFIX}/bin/llvm-ar)
set(CMAKE_RANLIB ${WASM_PREFIX}/bin/llvm-ranlib)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_ASM_COMPILER_TARGET ${triple})

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
45 changes: 45 additions & 0 deletions cpython-config-override
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# config.site override for cross compiling to wasm32-wasi platform,
# forked from the one written by Christian Heimes <[email protected]>

# cannot be detected in cross builds
ac_cv_buggy_getaddrinfo=no

# WASI has no /dev/pt*
ac_cv_file__dev_ptmx=no
ac_cv_file__dev_ptc=no

# get/setrlimit are not supported
ac_cv_header_sys_resource_h=no

# undefined symbols / unsupported features
ac_cv_func_eventfd=no

# WASI SDK 15.0 has no pipe syscall.
ac_cv_func_pipe=no

# WASI SDK 15.0 cannot create fifos and special files.
ac_cv_func_mkfifo=no
ac_cv_func_mkfifoat=no
ac_cv_func_mknod=no
ac_cv_func_mknodat=no
ac_cv_func_makedev=no

# fdopendir() fails on SDK 15.0,
# OSError: [Errno 28] Invalid argument: '.'
ac_cv_func_fdopendir=no

# WASI sockets are limited to operations on given socket fd and inet sockets.
# Disable AF_UNIX and AF_PACKET support, see socketmodule.h.
ac_cv_header_sys_un_h=no
ac_cv_header_netpacket_packet_h=no

# disable accept for WASM runtimes without sock_accept
#ac_cv_func_accept=no
#ac_cv_func_accept4=no

# Disable int-conversion for wask-sdk as it triggers an error from version 17.
ac_cv_disable_int_conversion=yes


# Disable dlopen
ac_cv_func_dlopen=no
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f786a28

Please sign in to comment.