#include #include #include #include static const char *get_c_compiler(void) { const char *cc = getenv("CC"); return (cc == NULL) ? "cc" : cc; } static void panic(const char *reason) { fprintf(stderr, "%s\n", reason); abort(); } #if defined(__GNUC__) && !defined(__clang__) #define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) // GCC versions 10.0--15.1 have a miscompilation where some bytes of a union may get clobbered // depending on the union layout and the order in which types are defined. This miscompilation // affects the output of the C backend, and thus can affect the bootstrap process. Specifically, // we observe that using the self-hosted x86_64 backend in 'zig2' will cause all function calls // to be relocated incorrectly, causing immediate crashes on any binary produced by it. // // The only reliable workaround for this bug is to disable the optimization pass containing it, // so here we detect whether the compiler being used requires that workaround. // // The upstream bug is fixed in GCC version 15.2 onwards (and was also backported to the 13 and // 14 branches, however there are no 13.x and 14.x releases that contains the fix as of now). // Once this bug is no longer widespread, we can remove this workaround. // // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119085 #if (GCC_VERSION >= 160000) || \ (GCC_VERSION >= 150200 && GCC_VERSION < 160000) || \ (GCC_VERSION > 140300 && GCC_VERSION < 150000) || \ (GCC_VERSION > 130400 && GCC_VERSION < 140000) || \ (GCC_VERSION <= 100000) #define GCC_BUG_119085_PRESENT 0 #else #define GCC_BUG_119085_PRESENT 1 #endif // GCC doesn't take into account alignment annotations when --Waddress-of-packed-member is // evaluated, which causes false positive warnings when the C backend generates code that takes // the address of a field in a packed struct. // // There is no fix for this as now, so the only way to get rid of the false positive warnings // is to disable the flag altogether. // // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94081 #define GCC_BUG_94081_PRESENT 1 #else #define GCC_BUG_94081_PRESENT 0 #define GCC_BUG_119085_PRESENT 0 #endif #if defined(__WIN32__) #error TODO write the functionality for executing child process into this build script #else #include #include #include static void run(char **argv) { pid_t pid = fork(); if (pid == -1) panic("fork failed"); if (pid == 0) { // child execvp(argv[0], argv); exit(1); } // parent int status; waitpid(pid, &status, 0); if (!WIFEXITED(status)) panic("child process crashed"); if (WEXITSTATUS(status) != 0) panic("child process failed"); } #endif static void print_and_run(const char **argv) { fprintf(stderr, "%s", argv[0]); for (const char **arg = argv + 1; *arg; arg += 1) { fprintf(stderr, " %s", *arg); } fprintf(stderr, "\n"); run((char **)argv); } static const char *get_host_os(void) { const char *host_os = getenv("ZIG_HOST_TARGET_OS"); if (host_os != NULL) return host_os; #if defined(__WIN32__) return "windows"; #elif defined(__APPLE__) return "macos"; #elif defined(__linux__) return "linux"; #elif defined(__FreeBSD__) return "freebsd"; #elif defined(__DragonFly__) return "dragonfly"; #elif defined(__HAIKU__) return "haiku"; #else panic("unknown host os, specify with ZIG_HOST_TARGET_OS"); #endif } static const char *get_host_arch(void) { const char *host_arch = getenv("ZIG_HOST_TARGET_ARCH"); if (host_arch != NULL) return host_arch; #if defined(__x86_64__ ) return "x86_64"; #elif defined(__aarch64__) return "aarch64"; #else panic("unknown host arch, specify with ZIG_HOST_TARGET_ARCH"); #endif } static const char *get_host_abi(void) { const char *host_abi = getenv("ZIG_HOST_TARGET_ABI"); return (host_abi == NULL) ? "" : host_abi; } static const char *get_host_triple(void) { const char *host_triple = getenv("ZIG_HOST_TARGET_TRIPLE"); if (host_triple != NULL) return host_triple; static char global_buffer[100]; sprintf(global_buffer, "%s-%s%s", get_host_arch(), get_host_os(), get_host_abi()); return global_buffer; } int main(int argc, char **argv) { const char *cc = get_c_compiler(); const char *host_triple = get_host_triple(); { const char *child_argv[] = { cc, "-o", "zig-wasm2c", "stage1/wasm2c.c", "-O2", "-std=c99", NULL, }; print_and_run(child_argv); } { const char *child_argv[] = { "./zig-wasm2c", "stage1/zig1.wasm", "zig1.c", NULL, }; print_and_run(child_argv); } { const char *child_argv[] = { cc, "-o", "zig1", "zig1.c", "stage1/wasi.c", "-std=c99", "-Os", "-fno-strict-aliasing", "-lm", NULL, }; print_and_run(child_argv); } { FILE *f = fopen("config.zig", "wb"); if (f == NULL) panic("unable to open config.zig for writing"); const char *zig_version = "0.17.0-dev.bootstrap"; int written = fprintf(f, "pub const have_llvm = false;\n" "pub const llvm_has_m68k = false;\n" "pub const llvm_has_csky = false;\n" "pub const llvm_has_arc = false;\n" "pub const llvm_has_xtensa = false;\n" "pub const version: [:0]const u8 = \"%s\";\n" "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n" "pub const enable_debug_extensions = false;\n" "pub const enable_logging = false;\n" "pub const enable_link_snapshots = false;\n" "pub const enable_tracy = false;\n" "pub const value_tracing = false;\n" "pub const skip_non_native = false;\n" "pub const debug_gpa = false;\n" "pub const dev = .core;\n" "pub const io_mode: enum { threaded, evented } = .threaded;\n" "pub const value_interpret_mode = .direct;\n" , zig_version); if (written < 100) panic("unable to write to config.zig file"); if (fclose(f) != 0) panic("unable to finish writing to config.zig file"); } { const char *child_argv[] = { "./zig1", "lib", "build-exe", "-ofmt=c", "-lc", "-OReleaseSmall", "--name", "zig2", "-femit-bin=zig2.c", "-target", host_triple, "--dep", "build_options", "--dep", "aro", "-Mroot=src/main.zig", "-Mbuild_options=config.zig", "-Maro=lib/compiler/aro/aro.zig", NULL, }; print_and_run(child_argv); } { const char *child_argv[] = { "./zig1", "lib", "build-obj", "-ofmt=c", "-OReleaseSmall", "--name", "compiler_rt", "-femit-bin=compiler_rt.c", "-target", host_triple, "-Mroot=lib/compiler_rt.zig", NULL, }; print_and_run(child_argv); } { const char *child_argv[] = { cc, "-o", "zig2", "zig2.c", "compiler_rt.c", "-std=c99", "-O2", "-fno-stack-protector", "-Istage1", #if defined(__APPLE__) "-Wl,-stack_size,0x10000000", #else "-Wl,-z,stack-size=0x10000000", #endif #if defined(__GNUC__) "-pthread", #endif "-fno-strict-aliasing", #if GCC_BUG_119085_PRESENT "-fno-tree-sra", #endif #if GCC_BUG_94081_PRESENT "-Wno-address-of-packed-member", #endif NULL, }; print_and_run(child_argv); } }