From ada1b69fb14a17a76c92070145ef28571b52f0ec Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sat, 23 Nov 2019 12:30:33 -0800 Subject: [PATCH] Support whole-program LTO Build and install an LTO version of libc.a and the startup files, alongside the non-LTO versions. --- Makefile | 546 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 294 insertions(+), 252 deletions(-) diff --git a/Makefile b/Makefile index 4fa5fcb96..d5ad32da4 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -# These variables are specifically meant to be overridable via -# the make command-line. +# These variables are specifically meant to be overridable via the make +# command-line. WASM_CC ?= clang WASM_NM ?= $(patsubst %clang,%llvm-nm,$(WASM_CC)) WASM_AR ?= $(patsubst %clang,%llvm-ar,$(WASM_CC)) @@ -9,13 +9,17 @@ SYSROOT ?= $(CURDIR)/sysroot # A directory to install to for "make install". INSTALL_DIR ?= /usr/local # single or posix -THREAD_MODEL = single +THREAD_MODEL ?= single # yes or no -BUILD_DLMALLOC = yes -BUILD_LIBC_BOTTOM_HALF = yes -BUILD_LIBC_TOP_HALF = yes +BUILD_DLMALLOC ?= yes +BUILD_LIBC_BOTTOM_HALF ?= yes +BUILD_LIBC_TOP_HALF ?= yes # The directory where we're store intermediate artifacts. -OBJDIR = $(CURDIR)/build +BUILD_DIR ?= $(CURDIR)/build + +ifeq ($(CLANG_VERSION),) +$(error CLANG_VERSION should be set to the clang version string) +endif # Check dependencies. ifeq ($(BUILD_LIBC_TOP_HALF),yes) @@ -29,103 +33,80 @@ $(error BUILD_LIBC_BOTTOM_HALF=yes depends on BUILD_DLMALLOC=yes) endif endif -# These variables describe the locations of various files and -# directories in the source tree. -BASICS_DIR = $(CURDIR)/basics -BASICS_INC = $(BASICS_DIR)/include -BASICS_CRT_SOURCES = $(wildcard $(BASICS_DIR)/crt/*.c) -BASICS_SOURCES = \ - $(wildcard $(BASICS_DIR)/sources/*.c) \ - $(wildcard $(BASICS_DIR)/sources/math/*.c) -DLMALLOC_DIR = $(CURDIR)/dlmalloc -DLMALLOC_SRC_DIR = $(DLMALLOC_DIR)/src -DLMALLOC_SOURCES = $(DLMALLOC_SRC_DIR)/dlmalloc.c -DLMALLOC_INC = $(DLMALLOC_DIR)/include -LIBC_BOTTOM_HALF_DIR = $(CURDIR)/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_LIBPREOPEN_DIR = $(LIBC_BOTTOM_HALF_DIR)/libpreopen -LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources -LIBC_BOTTOM_HALF_ALL_SOURCES = \ +# Set the target variables. Multiarch triples notably omit the vendor field, +# which happens to be what we do for the main target triple too. +override TARGET_TRIPLE = wasm32-wasi +override MULTIARCH_TRIPLE = wasm32-wasi + +# The directory we built .o files in. +override OBJDIR := $(BUILD_DIR) +ifeq ($(LTO),yes) +override OBJDIR := $(OBJDIR)/llvm-lto/$(CLANG_VERSION) +endif + +# These variables describe the locations of various files and directories in +# the source tree. +override BASICS_DIR = $(CURDIR)/basics +override BASICS_INC = $(BASICS_DIR)/include +override BASICS_CRT_SOURCES = $(wildcard $(BASICS_DIR)/crt/*.c) +override BASICS_SOURCES = $(wildcard $(BASICS_DIR)/sources/*.c) +override DLMALLOC_DIR = $(CURDIR)/dlmalloc +override DLMALLOC_SRC_DIR = $(DLMALLOC_DIR)/src +override DLMALLOC_SOURCES = $(DLMALLOC_SRC_DIR)/dlmalloc.c +override DLMALLOC_INC = $(DLMALLOC_DIR)/include +override LIBC_BOTTOM_HALF_DIR = $(CURDIR)/libc-bottom-half +override LIBC_BOTTOM_HALF_CLOUDLIBC_SRC = $(LIBC_BOTTOM_HALF_DIR)/cloudlibc/src +override LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC = $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC)/include +override LIBC_BOTTOM_HALF_HEADERS_PUBLIC = $(LIBC_BOTTOM_HALF_DIR)/headers/public +override LIBC_BOTTOM_HALF_HEADERS_PRIVATE = $(LIBC_BOTTOM_HALF_DIR)/headers/private +override LIBC_BOTTOM_HALF_LIBPREOPEN_DIR = $(LIBC_BOTTOM_HALF_DIR)/libpreopen +override LIBC_BOTTOM_HALF_SOURCES = $(LIBC_BOTTOM_HALF_DIR)/sources +override LIBC_BOTTOM_HALF_ALL_SOURCES = \ $(shell find $(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) -name \*.c) \ $(LIBC_BOTTOM_HALF_LIBPREOPEN_DIR)/libpreopen.c \ $(shell find $(LIBC_BOTTOM_HALF_SOURCES) -name \*.c) -LIBWASI_EMULATED_MMAN_SOURCES = \ +override LIBWASI_EMULATED_MMAN_SOURCES = \ $(shell find $(LIBC_BOTTOM_HALF_DIR)/mman -name \*.c) -LIBC_BOTTOM_HALF_CRT_SOURCES = $(wildcard $(LIBC_BOTTOM_HALF_DIR)/crt/*.c) -LIBC_TOP_HALF_DIR = $(CURDIR)/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 = \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/a64l.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/basename.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/dirname.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/ffs.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/ffsl.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/ffsll.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/fmtmsg.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getdomainname.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/gethostid.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getopt.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getopt_long.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/getsubopt.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/uname.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/misc/nftw.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/errno/strerror.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/htonl.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/htons.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/ntohl.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/ntohs.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/inet_ntop.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/inet_pton.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/inet_aton.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/in6addr_any.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/network/in6addr_loopback.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fenv.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fesetround.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/feupdateenv.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fesetexceptflag.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/fegetexceptflag.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fenv/feholdexcept.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/exit.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/atexit.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/assert.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/quick_exit.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/exit/at_quick_exit.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/strftime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/asctime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/asctime_r.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/ctime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/ctime_r.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/wcsftime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/strptime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/difftime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/timegm.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/ftime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/gmtime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/gmtime_r.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/timespec_get.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/getdate.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/localtime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/localtime_r.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/mktime.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__tm_to_secs.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__month_to_secs.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__secs_to_tm.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__year_to_secs.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/time/__tz.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/fcntl/creat.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/dirent/alphasort.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/dirent/versionsort.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/clearenv.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/getenv.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/putenv.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/setenv.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/env/unsetenv.c \ - $(LIBC_TOP_HALF_MUSL_SRC_DIR)/unistd/posix_close.c \ +override LIBC_BOTTOM_HALF_CRT_SOURCES = $(wildcard $(LIBC_BOTTOM_HALF_DIR)/crt/*.c) +override LIBC_TOP_HALF_DIR = $(CURDIR)/libc-top-half +override LIBC_TOP_HALF_MUSL_DIR = $(LIBC_TOP_HALF_DIR)/musl +override LIBC_TOP_HALF_MUSL_SRC_DIR = $(LIBC_TOP_HALF_MUSL_DIR)/src +override LIBC_TOP_HALF_MUSL_INC = $(LIBC_TOP_HALF_MUSL_DIR)/include +override 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/uname.c \ + misc/nftw.c \ + errno/strerror.c \ + network/htonl.c network/htons.c network/ntohl.c network/ntohs.c \ + network/inet_ntop.c network/inet_pton.c network/inet_aton.c \ + network/in6addr_any.c network/in6addr_loopback.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/clearenv.c env/getenv.c env/putenv.c env/setenv.c env/unsetenv.c \ + unistd/posix_close.c \ + ) \ $(filter-out %/procfdname.c %/syscall.c %/syscall_ret.c %/vdso.c %/version.c, \ $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal/*.c)) \ $(filter-out %/flockfile.c %/funlockfile.c %/__lockfile.c %/ftrylockfile.c \ @@ -146,6 +127,20 @@ LIBC_TOP_HALF_MUSL_SOURCES = \ $(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 %/crealf.c %/creal.c \ + %/cimagf.c %/cimag.c, \ + $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/complex/*.c)) \ + $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/crypt/*.c) +override MUSL_PRINTSCAN_SOURCES = \ + $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \ + internal/floatscan.c \ + stdio/vfprintf.c stdio/vfwprintf.c stdio/vfscanf.c \ + stdlib/strtod.c stdlib/wcstod.c \ + ) +override LIBC_TOP_HALF_HEADERS_PRIVATE = $(LIBC_TOP_HALF_DIR)/headers/private +override LIBC_TOP_HALF_SOURCES = $(LIBC_TOP_HALF_DIR)/sources +override MATH_SOURCES = \ + $(wildcard $(BASICS_DIR)/sources/math/*.c) \ $(filter-out %/__signbit.c %/__signbitf.c %/__signbitl.c \ %/__fpclassify.c %/__fpclassifyf.c %/__fpclassifyl.c \ %/ceilf.c %/ceil.c \ @@ -158,53 +153,36 @@ LIBC_TOP_HALF_MUSL_SOURCES = \ %/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 \ - %/cimagf.c %/cimag.c, \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/complex/*.c)) \ - $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/crypt/*.c) -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 -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) \ - $(shell find $(LIBC_TOP_HALF_SOURCES) -name \*.c) - -# Set the target variables. Multiarch triples notably omit the vendor -# field, which happens to be what we do for the main target triple too. -TARGET_TRIPLE = wasm32-wasi -MULTIARCH_TRIPLE = wasm32-wasi - -# These variables describe the locations of various files and -# directories in the generated sysroot tree. -SYSROOT_LIB = $(SYSROOT)/lib/$(MULTIARCH_TRIPLE) -SYSROOT_INC = $(SYSROOT)/include -SYSROOT_SHARE = $(SYSROOT)/share/$(MULTIARCH_TRIPLE) - -# Set the target. -override WASM_CFLAGS += --target=$(TARGET_TRIPLE) -# WebAssembly floating-point match doesn't trap. -# TODO: Add -fno-signaling-nans when the compiler supports it. -override WASM_CFLAGS += -fno-trapping-math - -# Configure support for threads. -ifeq ($(THREAD_MODEL), single) -override WASM_CFLAGS += -mthread-model single + $(wildcard $(LIBC_TOP_HALF_MUSL_SRC_DIR)/math/*.c)) +ifeq ($(BUILD_LIBC_BOTTOM_HALF),no) +override CRT_SOURCES = $(BASICS_CRT_SOURCES) +else +override CRT_SOURCES = $(LIBC_BOTTOM_HALF_CRT_SOURCES) endif -ifeq ($(THREAD_MODEL), posix) -override WASM_CFLAGS += -mthread-model posix -pthread +ifeq ($(LTO),yes) +# The following files define functions which are called by LLVM CodeGen, +# which runs after LLVM LTO, so LTO libraries don't satisfy them. They're +# also relatively uninteresting to LTO, as LLVM recognizes most of them +# even without seeing their definitions. +override LIBC_NONLTO_SOURCES = \ + $(MATH_SOURCES) \ + $(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \ + exit/atexit.c \ + string/memcpy.c string/memmove.c string/memset.c \ + ) +override LIBC_TOP_HALF_ALL_SOURCES := \ + $(filter-out $(LIBC_NONLTO_SOURCES), $(LIBC_TOP_HALF_MUSL_SOURCES)) +else +override LIBC_TOP_HALF_ALL_SOURCES := \ + $(LIBC_TOP_HALF_MUSL_SOURCES) \ + $(MATH_SOURCES) endif +override LIBC_TOP_HALF_ALL_SOURCES += \ + $(shell find $(LIBC_TOP_HALF_SOURCES) -name \*.c) -# Set the sysroot. -override WASM_CFLAGS += --sysroot="$(SYSROOT)" - -objs = $(patsubst $(CURDIR)/%.c,$(OBJDIR)/%.o,$(1)) +# These variables describe the locations of various files and directories in +# the build tree. +override objs = $(patsubst $(CURDIR)/%.c,$(OBJDIR)/%.o,$(1)) override BASICS_OBJS = $(call objs,$(BASICS_SOURCES)) override DLMALLOC_OBJS = $(call objs,$(DLMALLOC_SOURCES)) override LIBC_BOTTOM_HALF_ALL_OBJS = $(call objs,$(LIBC_BOTTOM_HALF_ALL_SOURCES)) @@ -231,6 +209,87 @@ override MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES)) override MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS)) override MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS)) override LIBWASI_EMULATED_MMAN_OBJS = $(call objs,$(LIBWASI_EMULATED_MMAN_SOURCES)) +ifeq ($(LTO),yes) +override LIBC_NONLTO_OBJS = $(call objs,$(LIBC_NONLTO_SOURCES)) +endif + +# These variables describe the locations of various files and +# directories in the generated sysroot tree. +override SYSROOT_LIB := $(SYSROOT)/lib/$(MULTIARCH_TRIPLE) +ifeq ($(LTO),yes) +override SYSROOT_LIB := $(SYSROOT_LIB)/llvm-lto/$(CLANG_VERSION) +endif +override SYSROOT_INC = $(SYSROOT)/include +override SYSROOT_SHARE = $(SYSROOT)/share/$(MULTIARCH_TRIPLE) + +# Compute WASM_CFLAGS. + +# Set the target. +override WASM_CFLAGS += --target=$(TARGET_TRIPLE) +# WebAssembly floating-point match doesn't trap. +# TODO: Add -fno-signaling-nans when the compiler supports it. +override WASM_CFLAGS += -fno-trapping-math + +# Configure support for threads. +ifeq ($(THREAD_MODEL), single) +override WASM_CFLAGS += -mthread-model single +endif +ifeq ($(THREAD_MODEL), posix) +override WASM_CFLAGS += -mthread-model posix -pthread +endif + +# Set the sysroot. +override WASM_CFLAGS += --sysroot="$(SYSROOT)" + +# If we're building LTO, enable it. +ifeq ($(LTO),yes) +override WASM_CFLAGS += -flto +endif + +# By default, build the sysroot. +default: sysroot + +# In an LTO build, we disable LTO for select source files. +ifeq ($(LTO),yes) +$(LIBC_NONLTO_OBJS): override WASM_CFLAGS += -fno-lto +endif + +# Configure wasi-libc for building printf with and without long double support. +$(MUSL_PRINTSCAN_OBJS): override WASM_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): override WASM_CFLAGS += \ + -D__wasilibc_printscan_no_floating_point \ + -D__wasilibc_printscan_floating_point_support_option="\"remove -lc-printscan-no-floating-point from the link command\"" + +# Add internal include directories. +$(DLMALLOC_OBJS): override WASM_CFLAGS += \ + -I$(DLMALLOC_INC) + +# Add internal include directories. +crt $(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \ + -I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \ + -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \ + -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) + +# Add internal include directories and suppression flags for harmless warnings. +$(LIBC_TOP_HALF_ALL_OBJS) \ + $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) \ + $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS) \ + $(LIBC_NONLTO_OBJS) \ +: override WASM_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 # Files from musl's include directory that we don't want to install in the # sysroot's include directory. @@ -317,72 +376,8 @@ ifeq ($(THREAD_MODEL), single) override MUSL_OMIT_HEADERS += "aio.h" "pthread.h" endif -default: check - -$(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) - -%.a: - @mkdir -p "$(@D)" - # On Windows, the commandline for the ar invocation got too long, so it needs to be split up. - $(WASM_AR) crs $@ $(wordlist 1, 199, $^) - $(WASM_AR) crs $@ $(wordlist 200, 399, $^) - $(WASM_AR) crs $@ $(wordlist 400, 599, $^) - $(WASM_AR) crs $@ $(wordlist 600, 799, $^) - # This might eventually overflow again, but at least it'll do so in a loud way instead of - # silently dropping the tail. - $(WASM_AR) crs $@ $(wordlist 800, 100000, $^) - -$(MUSL_PRINTSCAN_OBJS): override WASM_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): override WASM_CFLAGS += \ - -D__wasilibc_printscan_no_floating_point \ - -D__wasilibc_printscan_floating_point_support_option="\"remove -lc-printscan-no-floating-point from the link command\"" - -$(OBJDIR)/%.long-double.o: $(CURDIR)/%.c include_dirs - @mkdir -p "$(@D)" - "$(WASM_CC)" $(WASM_CFLAGS) -MD -MP -o $@ -c $< - -$(OBJDIR)/%.no-floating-point.o: $(CURDIR)/%.c include_dirs - @mkdir -p "$(@D)" - "$(WASM_CC)" $(WASM_CFLAGS) -MD -MP -o $@ -c $< - -$(OBJDIR)/%.o: $(CURDIR)/%.c include_dirs - @mkdir -p "$(@D)" - "$(WASM_CC)" $(WASM_CFLAGS) -MD -MP -o $@ -c $< - --include $(shell find $(OBJDIR) -name \*.d) - -$(DLMALLOC_OBJS): override WASM_CFLAGS += \ - -I$(DLMALLOC_INC) - -startup_files $(LIBC_BOTTOM_HALF_ALL_OBJS): override WASM_CFLAGS += \ - -I$(LIBC_BOTTOM_HALF_HEADERS_PRIVATE) \ - -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC_INC) \ - -I$(LIBC_BOTTOM_HALF_CLOUDLIBC_SRC) - -$(LIBC_TOP_HALF_ALL_OBJS) $(MUSL_PRINTSCAN_LONG_DOUBLE_OBJS) $(MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS): override WASM_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 - -include_dirs: +# Build the sysroot and perform basic sanity checks. +sysroot: $(RM) -r "$(SYSROOT)" # @@ -408,29 +403,18 @@ include_dirs: # Remove selected header files. $(RM) $(patsubst %,$(SYSROOT_INC)/%,$(MUSL_OMIT_HEADERS)) -ifeq ($(BUILD_LIBC_BOTTOM_HALF),no) -override CRT_SOURCES = $(BASICS_CRT_SOURCES) -else -override CRT_SOURCES = $(LIBC_BOTTOM_HALF_CRT_SOURCES) -endif - -startup_files: include_dirs # # Build the startup files. # - @mkdir -p "$(OBJDIR)" - cd "$(OBJDIR)" && \ - "$(WASM_CC)" $(WASM_CFLAGS) -c $(CRT_SOURCES) -MD -MP && \ - mkdir -p "$(SYSROOT_LIB)" && \ - mv *.o "$(SYSROOT_LIB)" + $(MAKE) crt + $(MAKE) crt LTO=yes -libc: include_dirs \ - $(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 + # + # Build the libc files. + # + $(MAKE) libc + $(MAKE) libc LTO=yes -finish: startup_files libc # # Create empty placeholder libraries. # @@ -441,13 +425,15 @@ finish: startup_files libc # # Collect metadata on the sysroot and perform sanity checks. # - mkdir -p "$(SYSROOT_SHARE)" + @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. + # + @# 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. "$(WASM_NM)" --defined-only "$(SYSROOT_LIB)"/libc.a "$(SYSROOT_LIB)"/*.o \ |grep ' [[:upper:]] ' |sed 's/.* [[:upper:]] //' |LC_ALL=C sort > "$(SYSROOT_SHARE)/defined-symbols.txt" for undef_sym in $$("$(WASM_NM)" --undefined-only "$(SYSROOT_LIB)"/*.a "$(SYSROOT_LIB)"/*.o \ @@ -456,28 +442,36 @@ finish: startup_files libc done | grep -v "^__mul" > "$(SYSROOT_SHARE)/undefined-symbols.txt" grep '^_*wasi_' "$(SYSROOT_SHARE)/undefined-symbols.txt" \ > "$(SYSROOT_LIB)/libc.imports" + cp "$(SYSROOT_LIB)/libc.imports" "$(SYSROOT_LIB)/llvm-lto/$(CLANG_VERSION)/libc.imports" + # # Generate a test file that includes all public header files. + # cd "$(SYSROOT)" && \ - for header in $$(find include -type f -not -name mman.h |grep -v /bits/); do \ - echo '#include <'$$header'>' | sed 's/include\///' ; \ + for header in $$(find include -type f -not -name mman.h |grep -v /bits/); do \ + echo '#include <'$$header'>' | sed 's/include\///' ; \ done |LC_ALL=C sort >share/$(MULTIARCH_TRIPLE)/include-all.c ; \ cd - >/dev/null + # # Test that it compiles. + # "$(WASM_CC)" $(WASM_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. + # Collect all the predefined macros, except for compiler version macros + # which we don't need to track here. # - # TODO: Undefine __FLOAT128__ for now since it's not in clang 8.0. - # TODO: Filter out __FLT16_* for now, as not all versions of clang have these. + @# + @# 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: Undefine __FLOAT128__ for now since it's not in clang 8.0. + @# TODO: Filter out __FLT16_* for now, as not all versions of clang have these. "$(WASM_CC)" $(WASM_CFLAGS) "$(SYSROOT_SHARE)/include-all.c" \ -isystem $(SYSROOT_INC) \ -E -dM -Wno-\#warnings \ @@ -497,17 +491,65 @@ finish: startup_files libc | grep -v '^#define __FLT16_' \ > "$(SYSROOT_SHARE)/predefined-macros.txt" + # Check that the computed metadata matches the expected metadata. + diff -ur "$(CURDIR)/expected/$(MULTIARCH_TRIPLE)" "$(SYSROOT_SHARE)" + # # The build succeeded! The generated sysroot is in $(SYSROOT). # -check: finish - # Check that the computed metadata matches the expected metadata. - # This ignores whitespace because on Windows the output has CRLF line endings. - diff -wur "$(CURDIR)/expected/$(MULTIARCH_TRIPLE)" "$(SYSROOT_SHARE)" - -install: finish - mkdir -p "$(INSTALL_DIR)" +# Build the sysroot and install it into $(INSTALL_DIR). +install: sysroot + @mkdir -p "$(INSTALL_DIR)" cp -r "$(SYSROOT)/lib" "$(SYSROOT)/share" "$(SYSROOT)/include" "$(INSTALL_DIR)" -.PHONY: default startup_files libc finish check install include_dirs +crt: + @mkdir -p "$(OBJDIR)" + @mkdir -p "$(SYSROOT_LIB)" + cd "$(OBJDIR)" && \ + "$(WASM_CC)" $(WASM_CFLAGS) -c $(CRT_SOURCES) -MD -MP && \ + mv *.o "$(SYSROOT_LIB)" + +libc: \ + $(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 +ifeq ($(LTO),yes) +libc: $(SYSROOT_LIB)/libc-nonlto.a +endif + +$(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) +ifeq ($(LTO),yes) +$(SYSROOT_LIB)/libc-nonlto.a: $(LIBC_NONLTO_OBJS) +endif + +%.a: + @mkdir -p "$(@D)" + # On Windows, the commandline for the ar invocation got too long, so it needs to be split up. + $(WASM_AR) crs $@ $(wordlist 1, 199, $^) + $(WASM_AR) crs $@ $(wordlist 200, 399, $^) + $(WASM_AR) crs $@ $(wordlist 400, 599, $^) + $(WASM_AR) crs $@ $(wordlist 600, 799, $^) + # This might eventually overflow again, but at least it'll do so in a loud way instead of + # silently dropping the tail. + $(WASM_AR) crs $@ $(wordlist 800, 100000, $^) + +$(OBJDIR)/%.o: $(CURDIR)/%.c + @mkdir -p "$(@D)" + "$(WASM_CC)" $(WASM_CFLAGS) -MD -MP -o $@ -c $< + +$(OBJDIR)/%.long-double.o: $(CURDIR)/%.c + @mkdir -p "$(@D)" + "$(WASM_CC)" $(WASM_CFLAGS) -MD -MP -o $@ -c $< + +$(OBJDIR)/%.no-floating-point.o: $(CURDIR)/%.c + @mkdir -p "$(@D)" + "$(WASM_CC)" $(WASM_CFLAGS) -MD -MP -o $@ -c $< + +-include $(shell find $(OBJDIR) -name \*.d) + +.PHONY: default sysroot install crt libc