1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stdbool.h>
5
6static const char *get_c_compiler(void) {
7 const char *cc = getenv("CC");
8 return (cc == NULL) ? "cc" : cc;
9}
10
11static void panic(const char *reason) {
12 fprintf(stderr, "%s\n", reason);
13 abort();
14}
15
16#if defined(__GNUC__) && !defined(__clang__)
17 #define GCC_VERSION (__GNUC__ * 10000 \
18 + __GNUC_MINOR__ * 100 \
19 + __GNUC_PATCHLEVEL__)
20 // GCC versions 10.0--15.1 have a miscompilation where some bytes of a union may get clobbered
21 // depending on the union layout and the order in which types are defined. This miscompilation
22 // affects the output of the C backend, and thus can affect the bootstrap process. Specifically,
23 // we observe that using the self-hosted x86_64 backend in 'zig2' will cause all function calls
24 // to be relocated incorrectly, causing immediate crashes on any binary produced by it.
25 //
26 // The only reliable workaround for this bug is to disable the optimization pass containing it,
27 // so here we detect whether the compiler being used requires that workaround.
28 //
29 // The upstream bug is fixed in GCC version 15.2 onwards (and was also backported to the 13 and
30 // 14 branches, however there are no 13.x and 14.x releases that contains the fix as of now).
31 // Once this bug is no longer widespread, we can remove this workaround.
32 //
33 // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119085
34 #if (GCC_VERSION >= 160000) || \
35 (GCC_VERSION >= 150200 && GCC_VERSION < 160000) || \
36 (GCC_VERSION > 140300 && GCC_VERSION < 150000) || \
37 (GCC_VERSION > 130400 && GCC_VERSION < 140000) || \
38 (GCC_VERSION <= 100000)
39 #define GCC_BUG_119085_PRESENT 0
40 #else
41 #define GCC_BUG_119085_PRESENT 1
42 #endif
43
44
45 // GCC doesn't take into account alignment annotations when --Waddress-of-packed-member is
46 // evaluated, which causes false positive warnings when the C backend generates code that takes
47 // the address of a field in a packed struct.
48 //
49 // There is no fix for this as now, so the only way to get rid of the false positive warnings
50 // is to disable the flag altogether.
51 //
52 // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94081
53 #define GCC_BUG_94081_PRESENT 1
54#else
55 #define GCC_BUG_94081_PRESENT 0
56 #define GCC_BUG_119085_PRESENT 0
57#endif
58
59#if defined(_WIN32)
60#error TODO write the functionality for executing child process into this build script
61#else
62
63#include <unistd.h>
64#include <errno.h>
65#include <sys/wait.h>
66
67static void run(char **argv) {
68 pid_t pid = fork();
69 if (pid == -1)
70 panic("fork failed");
71 if (pid == 0) {
72 // child
73 execvp(argv[0], argv);
74 exit(1);
75 }
76
77 // parent
78
79 int status;
80 waitpid(pid, &status, 0);
81
82 if (!WIFEXITED(status))
83 panic("child process crashed");
84
85 if (WEXITSTATUS(status) != 0)
86 panic("child process failed");
87}
88#endif
89
90static void print_and_run(const char **argv) {
91 fprintf(stderr, "%s", argv[0]);
92 for (const char **arg = argv + 1; *arg; arg += 1) {
93 fprintf(stderr, " %s", *arg);
94 }
95 fprintf(stderr, "\n");
96 run((char **)argv);
97}
98
99static const char *get_host_os(void) {
100 const char *host_os = getenv("ZIG_HOST_TARGET_OS");
101 if (host_os != NULL) return host_os;
102#if defined(_WIN32)
103 return "windows";
104#elif defined(__APPLE__)
105 return "macos";
106#elif defined(__linux__)
107 return "linux";
108#elif defined(__FreeBSD__)
109 return "freebsd";
110#elif defined(__DragonFly__)
111 return "dragonfly";
112#elif defined(__HAIKU__)
113 return "haiku";
114#else
115 panic("unknown host os, specify with ZIG_HOST_TARGET_OS");
116#endif
117}
118
119static const char *get_host_arch(void) {
120 const char *host_arch = getenv("ZIG_HOST_TARGET_ARCH");
121 if (host_arch != NULL) return host_arch;
122#if defined(__x86_64__ )
123 return "x86_64";
124#elif defined(__aarch64__)
125 return "aarch64";
126#else
127 panic("unknown host arch, specify with ZIG_HOST_TARGET_ARCH");
128#endif
129}
130
131static const char *get_host_abi(void) {
132 const char *host_abi = getenv("ZIG_HOST_TARGET_ABI");
133 return (host_abi == NULL) ? "" : host_abi;
134}
135
136static const char *get_host_triple(void) {
137 const char *host_triple = getenv("ZIG_HOST_TARGET_TRIPLE");
138 if (host_triple != NULL) return host_triple;
139 static char global_buffer[100];
140 sprintf(global_buffer, "%s-%s%s", get_host_arch(), get_host_os(), get_host_abi());
141 return global_buffer;
142}
143
144int main(int argc, char **argv) {
145 const char *cc = get_c_compiler();
146 const char *host_triple = get_host_triple();
147
148 {
149 const char *child_argv[] = {
150 cc, "-o", "zig-wasm2c", "stage1/wasm2c.c", "-O2", "-std=c99", NULL,
151 };
152 print_and_run(child_argv);
153 }
154 {
155 const char *child_argv[] = {
156 "./zig-wasm2c", "stage1/zig1.wasm", "zig1.c", NULL,
157 };
158 print_and_run(child_argv);
159 }
160 {
161 const char *child_argv[] = {
162 cc, "-o", "zig1", "zig1.c", "stage1/wasi.c", "-std=c99", "-Os", "-fno-strict-aliasing", "-lm", NULL,
163 };
164 print_and_run(child_argv);
165 }
166 {
167 FILE *f = fopen("config.zig", "wb");
168 if (f == NULL)
169 panic("unable to open config.zig for writing");
170
171 const char *zig_version = "0.17.0-dev.bootstrap";
172
173 int written = fprintf(f,
174 "pub const have_llvm = false;\n"
175 "pub const llvm_has_m68k = false;\n"
176 "pub const llvm_has_csky = false;\n"
177 "pub const llvm_has_arc = false;\n"
178 "pub const llvm_has_xtensa = false;\n"
179 "pub const version: [:0]const u8 = \"%s\";\n"
180 "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"
181 "pub const enable_debug_extensions = false;\n"
182 "pub const enable_logging = false;\n"
183 "pub const enable_link_snapshots = false;\n"
184 "pub const enable_tracy = false;\n"
185 "pub const value_tracing = false;\n"
186 "pub const skip_non_native = false;\n"
187 "pub const debug_gpa = false;\n"
188 "pub const dev = .core;\n"
189 "pub const io_mode: enum { threaded, evented } = .threaded;\n"
190 "pub const value_interpret_mode = .direct;\n"
191 , zig_version);
192 if (written < 100)
193 panic("unable to write to config.zig file");
194 if (fclose(f) != 0)
195 panic("unable to finish writing to config.zig file");
196 }
197
198 {
199 const char *child_argv[] = {
200 "./zig1", "lib", "build-exe",
201 "-ofmt=c", "-lc", "-OReleaseSmall",
202 "--name", "zig2", "-femit-bin=zig2.c",
203 "-target", host_triple,
204 "--dep", "build_options",
205 "-Mroot=src/main.zig",
206 "-Mbuild_options=config.zig",
207 NULL,
208 };
209 print_and_run(child_argv);
210 }
211
212 {
213 const char *child_argv[] = {
214 "./zig1", "lib", "build-obj",
215 "-ofmt=c", "-OReleaseSmall",
216 "--name", "compiler_rt", "-femit-bin=compiler_rt.c",
217 "-target", host_triple,
218 "-Mroot=lib/compiler_rt.zig",
219 NULL,
220 };
221 print_and_run(child_argv);
222 }
223
224 {
225 const char *child_argv[] = {
226 cc, "-o", "zig2", "zig2.c", "compiler_rt.c",
227 "-std=c99", "-O2", "-fno-stack-protector",
228 "-Istage1",
229#if defined(__APPLE__)
230 "-Wl,-stack_size,0x10000000",
231#else
232 "-Wl,-z,stack-size=0x10000000",
233#endif
234#if defined(__GNUC__)
235 "-pthread",
236#endif
237 "-fno-strict-aliasing",
238#if GCC_BUG_119085_PRESENT
239 "-fno-tree-sra",
240#endif
241#if GCC_BUG_94081_PRESENT
242 "-Wno-address-of-packed-member",
243#endif
244 NULL,
245 };
246 print_and_run(child_argv);
247 }
248}