diff --git a/bootstrap.c b/bootstrap.c index e1684df19a..860d961a94 100644 --- a/bootstrap.c +++ b/bootstrap.c @@ -1,62 +1,129 @@ -#include -#include -#include +// Bootstrap the self-hosted Zig compiler using a C compiler. +// +// Some ways to run this program: +// +// $ tcc -run bootstrap.c +// $ cc bootstrap.c -o bootstrap && ./bootstrap +// $ clang bootstrap.c -o bootstrap && CC=clang ./bootstrap +// $ cl.exe bootstrap.c /link /out:bootstrap.exe && .\bootstrap.exe +// +// This program will try its best to invoke the same C compiler that it was +// built with. To override this behavior, set the CC environment variable. +// +// The following environment variables can be set to override the target +// triple detection for the system this program runs on (the host): +// +// * ZIG_HOST_TARGET_ARCH +// * ZIG_HOST_TARGET_OS +// * ZIG_HOST_TARGET_ABI +// * ZIG_HOST_TARGET_TRIPLE (overrides all of the above) + +#include #include +#include +#include +#include + +#if defined(_WIN32) +#include +#else +#include +#include +#include +#endif static const char *get_c_compiler(void) { const char *cc = getenv("CC"); - return (cc == NULL) ? "cc" : cc; + if (cc != NULL) return cc; +#if defined(_MSC_VER) + return "cl"; +#else + return "cc"; +#endif } -static void panic(const char *reason) { - fprintf(stderr, "%s\n", reason); +static void panic(const char *format, ...) { + fputs("panic: ", stderr); + va_list vargs; + va_start(vargs, format); + vfprintf(stderr, format, vargs); + va_end(vargs); + fputs("\n", stderr); abort(); } -#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"); +static void error(const char *format, ...) { + fputs("error: ", stderr); + va_list vargs; + va_start(vargs, format); + vfprintf(stderr, format, vargs); + va_end(vargs); + fprintf(stderr, " = %d (%s)\n", errno, strerror(errno)); + exit(1); } -#endif -static void print_and_run(const char **argv) { +static void fatal(const char *format, ...) { + fputs("fatal: ", stderr); + va_list vargs; + va_start(vargs, format); + vfprintf(stderr, format, vargs); + va_end(vargs); + fputs("\n", stderr); + exit(1); +} + +static void usage(const char *message) { + fprintf(stderr, "%s\n", message); + exit(2); +} + +static void run(const char *const *argv) { +#if defined(_WIN32) + intptr_t status = _spawnvp(_P_WAIT, argv[0], argv); + switch (status) { + case -1: error("_spawnvp(_P_WAIT, %s, ...)", argv[0]); break; + case 0: break; + default: fatal("child process failed: %d", status); break; + } +#else + pid_t pid = fork(); + switch (pid) { + case -1: error("fork()"); break; + case 0: { + // child + execvp(argv[0], (char *const *)argv); + panic("execve(%s, ...) returned", argv[0]); + + break; + } + default: { + // parent + int wstatus; + if (waitpid(pid, &wstatus, 0) == -1) error("waitpid(%d, ..., 0)", pid); + if (!WIFEXITED(wstatus)) fatal("child process crashed"); + + int status = WEXITSTATUS(wstatus); + if (status != 0) fatal("child process failed: %d", status); + + break; + } + } +#endif +} + +static void print_and_run(const char *const *argv) { fprintf(stderr, "%s", argv[0]); - for (const char **arg = argv + 1; *arg; arg += 1) { + for (const char *const *arg = argv + 1; *arg; arg++) { fprintf(stderr, " %s", *arg); } fprintf(stderr, "\n"); - run((char **)argv); + run(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__) +#if defined(_WIN32) return "windows"; #elif defined(__APPLE__) return "macos"; @@ -67,25 +134,30 @@ static const char *get_host_os(void) { #elif defined(__HAIKU__) return "haiku"; #else - panic("unknown host os, specify with ZIG_HOST_TARGET_OS"); + usage("unknown host OS; specify with environment variable 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__ ) +#if defined(__x86_64__) || defined(_M_X64) return "x86_64"; -#elif defined(__aarch64__) +#elif defined(__aarch64__) || defined(_M_ARM64) return "aarch64"; #else - panic("unknown host arch, specify with ZIG_HOST_TARGET_ARCH"); + usage("unknown host architecture; specify with environment variable 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; + if (host_abi != NULL) return host_abi; +#if defined(_MSC_VER) + return "-msvc"; +#else + return ""; +#endif } static const char *get_host_triple(void) { @@ -100,28 +172,58 @@ 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", "-lm", NULL, - }; - print_and_run(child_argv); - } + print_and_run((const char *[]) { + cc, +#if defined(_MSC_VER) + "/nologo", + "stage1/wasm2c.c", + "/O2", + "/link", + "/OUT:zig-wasm2c.exe", +#else + "stage1/wasm2c.c", + "-std=c99", + "-O2", + "-o", "zig-wasm2c", +#endif + NULL, + }); + + print_and_run((const char *[]) { + "./zig-wasm2c", "stage1/zig1.wasm", "zig1.c", + NULL, + }); + + print_and_run((const char *[]) { + cc, +#if defined(_MSC_VER) + "/nologo", + "zig1.c", + "stage1/wasi.c", + "/O1", + "/link", + "/STACK:0x4000000,0x4000000", + "/OUT:zig1.exe", +#else + "zig1.c", + "stage1/wasi.c", + "-std=c99", + "-Os", + "-lm", +#if defined(__APPLE__) + "-Wl,-stack_size,0x1000000", +#else + "-Wl,-z,stack-size=0x1000000", +#endif + "-o", "zig1", +#endif + NULL, + }); + { FILE *f = fopen("config.zig", "wb"); if (f == NULL) - panic("unable to open config.zig for writing"); + error("fopen(\"config.zig\", \"wb\")"); const char *zig_version = "0.14.0-dev.bootstrap"; @@ -145,52 +247,65 @@ int main(int argc, char **argv) { if (written < 100) panic("unable to write to config.zig file"); if (fclose(f) != 0) - panic("unable to finish writing to config.zig file"); + error("fclose(\"config.zig\")"); } - { - 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); - } + print_and_run((const char *[]) { + "./zig1", "lib", "build-exe", + "-OReleaseSmall", + "-target", host_triple, + "-lc", + "-ofmt=c", + "-femit-bin=zig2.c", + "--name", "zig2", + "--dep", "build_options", + "--dep", "aro", + "-Mroot=src/main.zig", + "-Mbuild_options=config.zig", + "-Maro=lib/compiler/aro/aro.zig", + NULL, + }); - { - 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); - } + print_and_run((const char *[]) { + "./zig1", "lib", "build-obj", + "-OReleaseSmall", + "-target", host_triple, + "-ofmt=c", + "-femit-bin=compiler_rt.c", + "--name", "compiler_rt", + "-Mroot=lib/compiler_rt.zig", + NULL, + }); - { - 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", + print_and_run((const char *[]) { + cc, +#if defined(_MSC_VER) + "/nologo", + "zig2.c", + "compiler_rt.c", + "/Istage1", + "/O2", + "/GS-", + "/link", + "/STACK:0x10000000,0x10000000", + "/OUT:zig2.exe", #else - "-Wl,-z,stack-size=0x10000000", -#endif + "zig2.c", + "compiler_rt.c", + "-Istage1", + "-std=c99", #if defined(__GNUC__) - "-pthread", + "-pthread", #endif - NULL, - }; - print_and_run(child_argv); - } + "-O2", + "-fno-stack-protector", +#if defined(__APPLE__) + "-Wl,-stack_size,0x10000000", +#else + "-Wl,-z,stack-size=0x10000000", +#endif + "-o", "zig2", +#endif + NULL, + }); } diff --git a/ci/x86_64-windows-debug.ps1 b/ci/x86_64-windows-debug.ps1 index 8fd4db222c..e5ea962425 100644 --- a/ci/x86_64-windows-debug.ps1 +++ b/ci/x86_64-windows-debug.ps1 @@ -30,6 +30,26 @@ if ((git rev-parse --is-shallow-repository) -eq "true") { git fetch --unshallow # `git describe` won't work on a shallow repo } +Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" +CheckLastExitCode + +Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" ` + -DevCmdArguments '-arch=x64 -no_logo' ` + -StartInPath $(Get-Location) +CheckLastExitCode + +# Test building from source without LLVM. +git clean -fd +Remove-Item -Path 'zig-out' -Recurse -Force -ErrorAction Ignore +cl -nologo bootstrap.c /link /OUT:bootstrap.exe +CheckLastExitCode +.\bootstrap +CheckLastExitCode +.\zig2 build -Dno-lib +CheckLastExitCode +.\zig-out\bin\zig test test\behavior.zig +CheckLastExitCode + Write-Output "Building from source..." Remove-Item -Path 'build-debug' -Recurse -Force -ErrorAction Ignore New-Item -Path 'build-debug' -ItemType Directory @@ -94,14 +114,6 @@ CheckLastExitCode -Mbuild_options="config.zig" CheckLastExitCode -Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" -CheckLastExitCode - -Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" ` - -DevCmdArguments '-arch=x64 -no_logo' ` - -StartInPath $(Get-Location) -CheckLastExitCode - Write-Output "Build and run behavior tests with msvc..." & cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib CheckLastExitCode diff --git a/ci/x86_64-windows-release.ps1 b/ci/x86_64-windows-release.ps1 index 432d0649be..820c3bcb31 100644 --- a/ci/x86_64-windows-release.ps1 +++ b/ci/x86_64-windows-release.ps1 @@ -30,6 +30,26 @@ if ((git rev-parse --is-shallow-repository) -eq "true") { git fetch --unshallow # `git describe` won't work on a shallow repo } +Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" +CheckLastExitCode + +Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" ` + -DevCmdArguments '-arch=x64 -no_logo' ` + -StartInPath $(Get-Location) +CheckLastExitCode + +# Test building from source without LLVM. +git clean -fd +Remove-Item -Path 'zig-out' -Recurse -Force -ErrorAction Ignore +cl -nologo bootstrap.c /link /OUT:bootstrap.exe +CheckLastExitCode +.\bootstrap +CheckLastExitCode +.\zig2 build -Dno-lib +CheckLastExitCode +.\zig-out\bin\zig test test\behavior.zig +CheckLastExitCode + Write-Output "Building from source..." Remove-Item -Path 'build-release' -Recurse -Force -ErrorAction Ignore New-Item -Path 'build-release' -ItemType Directory @@ -112,14 +132,6 @@ CheckLastExitCode -Mbuild_options="config.zig" CheckLastExitCode -Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" -CheckLastExitCode - -Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" ` - -DevCmdArguments '-arch=x64 -no_logo' ` - -StartInPath $(Get-Location) -CheckLastExitCode - Write-Output "Build and run behavior tests with msvc..." & cl.exe -I..\lib test-x86_64-windows-msvc.c compiler_rt-x86_64-windows-msvc.c /W3 /Z7 -link -nologo -debug -subsystem:console kernel32.lib ntdll.lib libcmt.lib CheckLastExitCode