1 /*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8 // This file is the entry point for zig0, which is *only* used to build
9 // stage2, the self-hosted compiler, into an object file, which is then
10 // linked by the same build system (cmake) that linked this binary.
11
12 #include "stage1.h"
13 #include "heap.hpp"
14 #include "stage2.h"
15 #include "target.hpp"
16 #include "error.hpp"
17 #include "util.hpp"
18 #include "buffer.hpp"
19 #include "os.hpp"
20
21 // This is the only file allowed to include config.h because config.h is
22 // only produced when building with cmake. When using the zig build system,
23 // zig0.cpp is never touched.
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28
print_error_usage(const char * arg0)29 static int print_error_usage(const char *arg0) {
30 fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0);
31 return EXIT_FAILURE;
32 }
33
print_full_usage(const char * arg0,FILE * file,int return_code)34 static int print_full_usage(const char *arg0, FILE *file, int return_code) {
35 fprintf(file,
36 "Usage: %s [options] builds an object file\n"
37 "\n"
38 "Options:\n"
39 " --color [auto|off|on] enable or disable colored error messages\n"
40 " --name [name] override output name\n"
41 " -femit-bin=[path] Output machine code\n"
42 " -fcompiler-rt Always include compiler-rt symbols in output\n"
43 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
44 " --pkg-end pop current pkg\n"
45 " -ODebug build with optimizations off and safety on\n"
46 " -OReleaseFast build with optimizations on and safety off\n"
47 " -OReleaseSafe build with optimizations on and safety on\n"
48 " -OReleaseSmall build with size optimizations on and safety off\n"
49 " --single-threaded source may assume it is only used single-threaded\n"
50 " -dynamic create a shared library (.so; .dll; .dylib)\n"
51 " --strip exclude debug symbols\n"
52 " -target [name] <arch>-<os>-<abi> see the targets command\n"
53 " -mcpu [cpu] specify target CPU and feature set\n"
54 " --verbose-tokenize enable compiler debug output for tokenization\n"
55 " --verbose-ast enable compiler debug output for AST parsing\n"
56 " --verbose-ir enable compiler debug output for Zig IR\n"
57 " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
58 " --verbose-cimport enable compiler debug output for C imports\n"
59 " --verbose-llvm-cpu-features enable compiler debug output for LLVM CPU features\n"
60 "\n"
61 , arg0);
62 return return_code;
63 }
64
get_zig_os_type(ZigLLVM_OSType os_type)65 static Os get_zig_os_type(ZigLLVM_OSType os_type) {
66 switch (os_type) {
67 case ZigLLVM_UnknownOS:
68 return OsFreestanding;
69 case ZigLLVM_Ananas:
70 return OsAnanas;
71 case ZigLLVM_CloudABI:
72 return OsCloudABI;
73 case ZigLLVM_DragonFly:
74 return OsDragonFly;
75 case ZigLLVM_FreeBSD:
76 return OsFreeBSD;
77 case ZigLLVM_Fuchsia:
78 return OsFuchsia;
79 case ZigLLVM_IOS:
80 return OsIOS;
81 case ZigLLVM_KFreeBSD:
82 return OsKFreeBSD;
83 case ZigLLVM_Linux:
84 return OsLinux;
85 case ZigLLVM_Lv2:
86 return OsLv2;
87 case ZigLLVM_Darwin:
88 case ZigLLVM_MacOSX:
89 return OsMacOSX;
90 case ZigLLVM_NetBSD:
91 return OsNetBSD;
92 case ZigLLVM_OpenBSD:
93 return OsOpenBSD;
94 case ZigLLVM_Solaris:
95 return OsSolaris;
96 case ZigLLVM_Win32:
97 return OsWindows;
98 case ZigLLVM_ZOS:
99 return OsZOS;
100 case ZigLLVM_Haiku:
101 return OsHaiku;
102 case ZigLLVM_Minix:
103 return OsMinix;
104 case ZigLLVM_RTEMS:
105 return OsRTEMS;
106 case ZigLLVM_NaCl:
107 return OsNaCl;
108 case ZigLLVM_AIX:
109 return OsAIX;
110 case ZigLLVM_CUDA:
111 return OsCUDA;
112 case ZigLLVM_NVCL:
113 return OsNVCL;
114 case ZigLLVM_AMDHSA:
115 return OsAMDHSA;
116 case ZigLLVM_PS4:
117 return OsPS4;
118 case ZigLLVM_ELFIAMCU:
119 return OsELFIAMCU;
120 case ZigLLVM_TvOS:
121 return OsTvOS;
122 case ZigLLVM_WatchOS:
123 return OsWatchOS;
124 case ZigLLVM_Mesa3D:
125 return OsMesa3D;
126 case ZigLLVM_Contiki:
127 return OsContiki;
128 case ZigLLVM_AMDPAL:
129 return OsAMDPAL;
130 case ZigLLVM_HermitCore:
131 return OsHermitCore;
132 case ZigLLVM_Hurd:
133 return OsHurd;
134 case ZigLLVM_WASI:
135 return OsWASI;
136 case ZigLLVM_Emscripten:
137 return OsEmscripten;
138 }
139 zig_unreachable();
140 }
141
get_native_target(ZigTarget * target)142 static void get_native_target(ZigTarget *target) {
143 // first zero initialize
144 *target = {};
145
146 ZigLLVM_OSType os_type;
147 ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
148 ZigLLVM_VendorType trash;
149 ZigLLVMGetNativeTarget(
150 &target->arch,
151 &trash,
152 &os_type,
153 &target->abi,
154 &oformat);
155 target->os = get_zig_os_type(os_type);
156 target->is_native_os = true;
157 target->is_native_cpu = true;
158 if (target->abi == ZigLLVM_UnknownEnvironment) {
159 target->abi = target_default_abi(target->arch, target->os);
160 }
161 }
162
target_parse_triple(struct ZigTarget * target,const char * zig_triple,const char * mcpu,const char * dynamic_linker)163 static Error target_parse_triple(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
164 const char *dynamic_linker)
165 {
166 Error err;
167
168 if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) {
169 zig_triple = nullptr;
170 }
171
172 if (zig_triple == nullptr) {
173 get_native_target(target);
174
175 if (mcpu == nullptr) {
176 target->llvm_cpu_name = ZigLLVMGetHostCPUName();
177 target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
178 } else if (strcmp(mcpu, "baseline") == 0) {
179 target->is_native_os = false;
180 target->is_native_cpu = false;
181 target->llvm_cpu_name = "";
182 target->llvm_cpu_features = "";
183 } else {
184 const char *msg = "stage0 can't handle CPU/features in the target";
185 stage2_panic(msg, strlen(msg));
186 }
187 } else {
188 // first initialize all to zero
189 *target = {};
190
191 SplitIterator it = memSplit(str(zig_triple), str("-"));
192
193 Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
194 Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it);
195 Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it);
196
197 if (!opt_archsub.is_some)
198 return ErrorMissingArchitecture;
199
200 if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) {
201 return err;
202 }
203
204 if (!opt_os.is_some)
205 return ErrorMissingOperatingSystem;
206
207 if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
208 return err;
209 }
210
211 if (opt_abi.is_some) {
212 if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) {
213 return err;
214 }
215 } else {
216 target->abi = target_default_abi(target->arch, target->os);
217 }
218
219 if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) {
220 const char *msg = "stage0 can't handle CPU/features in the target";
221 stage2_panic(msg, strlen(msg));
222 }
223 }
224
225 return ErrorNone;
226 }
227
228
str_starts_with(const char * s1,const char * s2)229 static bool str_starts_with(const char *s1, const char *s2) {
230 size_t s2_len = strlen(s2);
231 if (strlen(s1) < s2_len) {
232 return false;
233 }
234 return memcmp(s1, s2, s2_len) == 0;
235 }
236
main_exit(Stage2ProgressNode * root_progress_node,int exit_code)237 int main_exit(Stage2ProgressNode *root_progress_node, int exit_code) {
238 if (root_progress_node != nullptr) {
239 stage2_progress_end(root_progress_node);
240 }
241 return exit_code;
242 }
243
main(int argc,char ** argv)244 int main(int argc, char **argv) {
245 zig_stage1_os_init();
246
247 char *arg0 = argv[0];
248 Error err;
249
250 const char *in_file = nullptr;
251 const char *emit_bin_path = nullptr;
252 bool strip = false;
253 const char *out_name = nullptr;
254 bool verbose_ir = false;
255 bool verbose_llvm_ir = false;
256 bool verbose_cimport = false;
257 bool verbose_llvm_cpu_features = false;
258 ErrColor color = ErrColorAuto;
259 const char *dynamic_linker = nullptr;
260 bool link_libc = false;
261 bool link_libcpp = false;
262 const char *target_string = nullptr;
263 ZigStage1Pkg *cur_pkg = heap::c_allocator.create<ZigStage1Pkg>();
264 BuildMode optimize_mode = BuildModeDebug;
265 TargetSubsystem subsystem = TargetSubsystemAuto;
266 const char *override_lib_dir = nullptr;
267 const char *mcpu = nullptr;
268 bool single_threaded = false;
269 bool is_test_build = false;
270 bool include_compiler_rt = false;
271
272 for (int i = 1; i < argc; i += 1) {
273 char *arg = argv[i];
274
275 if (arg[0] == '-') {
276 if (strcmp(arg, "--") == 0) {
277 fprintf(stderr, "Unexpected end-of-parameter mark: %s\n", arg);
278 } else if (strcmp(arg, "--test") == 0) {
279 is_test_build = true;
280 } else if (strcmp(arg, "-ODebug") == 0) {
281 optimize_mode = BuildModeDebug;
282 } else if (strcmp(arg, "-OReleaseFast") == 0) {
283 optimize_mode = BuildModeFastRelease;
284 } else if (strcmp(arg, "-OReleaseSafe") == 0) {
285 optimize_mode = BuildModeSafeRelease;
286 } else if (strcmp(arg, "-OReleaseSmall") == 0) {
287 optimize_mode = BuildModeSmallRelease;
288 } else if (strcmp(arg, "--single-threaded") == 0) {
289 single_threaded = true;
290 } else if (strcmp(arg, "--help") == 0) {
291 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
292 } else if (strcmp(arg, "--strip") == 0) {
293 strip = true;
294 } else if (strcmp(arg, "--verbose-ir") == 0) {
295 verbose_ir = true;
296 } else if (strcmp(arg, "--verbose-llvm-ir") == 0) {
297 verbose_llvm_ir = true;
298 } else if (strcmp(arg, "--verbose-cimport") == 0) {
299 verbose_cimport = true;
300 } else if (strcmp(arg, "--verbose-llvm-cpu-features") == 0) {
301 verbose_llvm_cpu_features = true;
302 } else if (arg[1] == 'l' && arg[2] != 0) {
303 // alias for --library
304 const char *l = &arg[2];
305 if (strcmp(l, "c") == 0) {
306 link_libc = true;
307 } else if (strcmp(l, "c++") == 0 || strcmp(l, "stdc++") == 0) {
308 link_libcpp = true;
309 }
310 } else if (strcmp(arg, "--pkg-begin") == 0) {
311 if (i + 2 >= argc) {
312 fprintf(stderr, "Expected 2 arguments after --pkg-begin\n");
313 return print_error_usage(arg0);
314 }
315 ZigStage1Pkg *new_cur_pkg = heap::c_allocator.create<ZigStage1Pkg>();
316 i += 1;
317 new_cur_pkg->name_ptr = argv[i];
318 new_cur_pkg->name_len = strlen(argv[i]);
319 i += 1;
320 new_cur_pkg->path_ptr = argv[i];
321 new_cur_pkg->path_len = strlen(argv[i]);
322 new_cur_pkg->parent = cur_pkg;
323 cur_pkg->children_ptr = heap::c_allocator.reallocate<ZigStage1Pkg *>(cur_pkg->children_ptr,
324 cur_pkg->children_len, cur_pkg->children_len + 1);
325 cur_pkg->children_ptr[cur_pkg->children_len] = new_cur_pkg;
326 cur_pkg->children_len += 1;
327
328 cur_pkg = new_cur_pkg;
329 } else if (strcmp(arg, "--pkg-end") == 0) {
330 if (cur_pkg->parent == nullptr) {
331 fprintf(stderr, "Encountered --pkg-end with no matching --pkg-begin\n");
332 return EXIT_FAILURE;
333 }
334 cur_pkg = cur_pkg->parent;
335 } else if (str_starts_with(arg, "-mcpu=")) {
336 mcpu = arg + strlen("-mcpu=");
337 } else if (str_starts_with(arg, "-femit-bin=")) {
338 emit_bin_path = arg + strlen("-femit-bin=");
339 } else if (strcmp(arg, "-fcompiler-rt") == 0) {
340 include_compiler_rt = true;
341 } else if (i + 1 >= argc) {
342 fprintf(stderr, "Expected another argument after %s\n", arg);
343 return print_error_usage(arg0);
344 } else {
345 i += 1;
346 if (strcmp(arg, "--color") == 0) {
347 if (strcmp(argv[i], "auto") == 0) {
348 color = ErrColorAuto;
349 } else if (strcmp(argv[i], "on") == 0) {
350 color = ErrColorOn;
351 } else if (strcmp(argv[i], "off") == 0) {
352 color = ErrColorOff;
353 } else {
354 fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
355 return print_error_usage(arg0);
356 }
357 } else if (strcmp(arg, "--name") == 0) {
358 out_name = argv[i];
359 } else if (strcmp(arg, "--dynamic-linker") == 0) {
360 dynamic_linker = argv[i];
361 } else if (strcmp(arg, "--zig-lib-dir") == 0) {
362 override_lib_dir = argv[i];
363 } else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) {
364 if (strcmp(argv[i], "c") == 0) {
365 link_libc = true;
366 } else if (strcmp(argv[i], "c++") == 0 || strcmp(argv[i], "stdc++") == 0) {
367 link_libcpp = true;
368 }
369 } else if (strcmp(arg, "-target") == 0) {
370 target_string = argv[i];
371 } else if (strcmp(arg, "--subsystem") == 0) {
372 if (strcmp(argv[i], "console") == 0) {
373 subsystem = TargetSubsystemConsole;
374 } else if (strcmp(argv[i], "windows") == 0) {
375 subsystem = TargetSubsystemWindows;
376 } else if (strcmp(argv[i], "posix") == 0) {
377 subsystem = TargetSubsystemPosix;
378 } else if (strcmp(argv[i], "native") == 0) {
379 subsystem = TargetSubsystemNative;
380 } else if (strcmp(argv[i], "efi_application") == 0) {
381 subsystem = TargetSubsystemEfiApplication;
382 } else if (strcmp(argv[i], "efi_boot_service_driver") == 0) {
383 subsystem = TargetSubsystemEfiBootServiceDriver;
384 } else if (strcmp(argv[i], "efi_rom") == 0) {
385 subsystem = TargetSubsystemEfiRom;
386 } else if (strcmp(argv[i], "efi_runtime_driver") == 0) {
387 subsystem = TargetSubsystemEfiRuntimeDriver;
388 } else {
389 fprintf(stderr, "invalid: --subsystem %s\n"
390 "Options are:\n"
391 " console\n"
392 " windows\n"
393 " posix\n"
394 " native\n"
395 " efi_application\n"
396 " efi_boot_service_driver\n"
397 " efi_rom\n"
398 " efi_runtime_driver\n"
399 , argv[i]);
400 return EXIT_FAILURE;
401 }
402 } else if (strcmp(arg, "-mcpu") == 0) {
403 mcpu = argv[i];
404 } else {
405 fprintf(stderr, "Invalid argument: %s\n", arg);
406 return print_error_usage(arg0);
407 }
408 }
409 } else if (!in_file) {
410 in_file = arg;
411 } else {
412 fprintf(stderr, "Unexpected extra parameter: %s\n", arg);
413 return print_error_usage(arg0);
414 }
415 }
416
417 if (cur_pkg->parent != nullptr) {
418 fprintf(stderr, "Unmatched --pkg-begin\n");
419 return EXIT_FAILURE;
420 }
421
422 Stage2Progress *progress = stage2_progress_create();
423 Stage2ProgressNode *root_progress_node = stage2_progress_start_root(progress, "", 0, 0);
424 if (color == ErrColorOff) stage2_progress_disable_tty(progress);
425
426 ZigTarget target;
427 if ((err = target_parse_triple(&target, target_string, mcpu, dynamic_linker))) {
428 fprintf(stderr, "invalid target: %s\n", err_str(err));
429 return print_error_usage(arg0);
430 }
431
432 if (in_file == nullptr) {
433 fprintf(stderr, "missing zig file\n");
434 return print_error_usage(arg0);
435 }
436
437 if (out_name == nullptr) {
438 fprintf(stderr, "missing --name\n");
439 return print_error_usage(arg0);
440 }
441
442 if (override_lib_dir == nullptr) {
443 fprintf(stderr, "missing --zig-lib-dir\n");
444 return print_error_usage(arg0);
445 }
446
447 if (emit_bin_path == nullptr) {
448 fprintf(stderr, "missing -femit-bin=\n");
449 return print_error_usage(arg0);
450 }
451
452 ZigStage1 *stage1 = zig_stage1_create(optimize_mode,
453 nullptr, 0,
454 in_file, strlen(in_file),
455 override_lib_dir, strlen(override_lib_dir),
456 &target, is_test_build);
457
458 stage1->main_progress_node = root_progress_node;
459 stage1->root_name_ptr = out_name;
460 stage1->root_name_len = strlen(out_name);
461 stage1->strip = strip;
462 stage1->verbose_ir = verbose_ir;
463 stage1->verbose_llvm_ir = verbose_llvm_ir;
464 stage1->verbose_cimport = verbose_cimport;
465 stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features;
466 stage1->emit_o_ptr = emit_bin_path;
467 stage1->emit_o_len = strlen(emit_bin_path);
468 stage1->main_pkg = cur_pkg;
469 stage1->err_color = color;
470 stage1->link_libc = link_libc;
471 stage1->link_libcpp = link_libcpp;
472 stage1->subsystem = subsystem;
473 stage1->pic = true;
474 stage1->is_single_threaded = single_threaded;
475 stage1->include_compiler_rt = include_compiler_rt;
476
477 zig_stage1_build_object(stage1);
478
479 zig_stage1_destroy(stage1);
480
481 return main_exit(root_progress_node, EXIT_SUCCESS);
482 }
483
stage2_panic(const char * ptr,size_t len)484 void stage2_panic(const char *ptr, size_t len) {
485 fwrite(ptr, 1, len, stderr);
486 fprintf(stderr, "\n");
487 fflush(stderr);
488 abort();
489 }
490
491 struct Stage2Progress {
492 int trash;
493 };
494
495 struct Stage2ProgressNode {
496 int trash;
497 };
498
stage2_progress_create(void)499 Stage2Progress *stage2_progress_create(void) {
500 return nullptr;
501 }
502
stage2_progress_destroy(Stage2Progress * progress)503 void stage2_progress_destroy(Stage2Progress *progress) {}
504
stage2_progress_start_root(Stage2Progress * progress,const char * name_ptr,size_t name_len,size_t estimated_total_items)505 Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
506 const char *name_ptr, size_t name_len, size_t estimated_total_items)
507 {
508 return nullptr;
509 }
stage2_progress_start(Stage2ProgressNode * node,const char * name_ptr,size_t name_len,size_t estimated_total_items)510 Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
511 const char *name_ptr, size_t name_len, size_t estimated_total_items)
512 {
513 return nullptr;
514 }
stage2_progress_end(Stage2ProgressNode * node)515 void stage2_progress_end(Stage2ProgressNode *node) {}
stage2_progress_complete_one(Stage2ProgressNode * node)516 void stage2_progress_complete_one(Stage2ProgressNode *node) {}
stage2_progress_disable_tty(Stage2Progress * progress)517 void stage2_progress_disable_tty(Stage2Progress *progress) {}
stage2_progress_update_node(Stage2ProgressNode * node,size_t completed_count,size_t estimated_total_items)518 void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
519
stage2_fetch_file(struct ZigStage1 * stage1,const char * path_ptr,size_t path_len,size_t * result_len)520 const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len,
521 size_t *result_len)
522 {
523 Error err;
524 Buf contents_buf = BUF_INIT;
525 Buf path_buf = BUF_INIT;
526
527 buf_init_from_mem(&path_buf, path_ptr, path_len);
528 if ((err = os_fetch_file_path(&path_buf, &contents_buf))) {
529 return nullptr;
530 }
531 *result_len = buf_len(&contents_buf);
532 return buf_ptr(&contents_buf);
533 }
534
stage2_cimport(struct ZigStage1 * stage1,const char * c_src_ptr,size_t c_src_len,const char ** out_zig_path_ptr,size_t * out_zig_path_len,struct Stage2ErrorMsg ** out_errors_ptr,size_t * out_errors_len)535 Error stage2_cimport(struct ZigStage1 *stage1, const char *c_src_ptr, size_t c_src_len,
536 const char **out_zig_path_ptr, size_t *out_zig_path_len,
537 struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len)
538 {
539 const char *msg = "stage0 called stage2_cimport";
540 stage2_panic(msg, strlen(msg));
541 }
542
stage2_add_link_lib(struct ZigStage1 * stage1,const char * lib_name_ptr,size_t lib_name_len,const char * symbol_name_ptr,size_t symbol_name_len)543 const char *stage2_add_link_lib(struct ZigStage1 *stage1,
544 const char *lib_name_ptr, size_t lib_name_len,
545 const char *symbol_name_ptr, size_t symbol_name_len)
546 {
547 return nullptr;
548 }
549
stage2_version_string(void)550 const char *stage2_version_string(void) {
551 return ZIG_VERSION_STRING;
552 }
553
stage2_version(void)554 struct Stage2SemVer stage2_version(void) {
555 return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH};
556 }
557