zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob bf2dbcf6 (27653B) - Raw


      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 #include "ast_render.hpp"
      9 #include "buffer.hpp"
     10 #include "codegen.hpp"
     11 #include "config.h"
     12 #include "error.hpp"
     13 #include "link.hpp"
     14 #include "os.hpp"
     15 #include "target.hpp"
     16 
     17 #include <stdio.h>
     18 
     19 static int usage(const char *arg0) {
     20     fprintf(stderr, "Usage: %s [command] [options]\n"
     21         "Commands:\n"
     22         "  asm [source]                 create object from assembly\n"
     23         "  build                        build project from build.zig\n"
     24         "  build_exe [source]           create executable from source\n"
     25         "  build_lib [source]           create library from source\n"
     26         "  build_obj [source]           create object from source\n"
     27         "  link_exe [objects]           create executable from objects\n"
     28         "  link_lib [objects]           create library from objects\n"
     29         "  parseh [source]              convert a c header file to zig extern declarations\n"
     30         "  targets                      list available compilation targets\n"
     31         "  test [source]                create and run a test build\n"
     32         "  version                      print version number and exit\n"
     33         "Options:\n"
     34         "  --ar-path [path]             set the path to ar\n"
     35         "  --color [auto|off|on]        enable or disable colored error messages\n"
     36         "  --dynamic-linker [path]      set the path to ld.so\n"
     37         "  --each-lib-rpath             add rpath for each used dynamic library\n"
     38         "  --ld-path [path]             set the path to the linker\n"
     39         "  --libc-include-dir [path]    directory where libc stdlib.h resides\n"
     40         "  --libc-lib-dir [path]        directory where libc crt1.o resides\n"
     41         "  --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n"
     42         "  --library [lib]              link against lib\n"
     43         "  --library-path [dir]         add a directory to the library search path\n"
     44         "  --linker-script [path]       use a custom linker script\n"
     45         "  --name [name]                override output name\n"
     46         "  --output [file]              override destination path\n"
     47         "  --release                    build with optimizations on and debug protection off\n"
     48         "  --static                     output will be statically linked\n"
     49         "  --strip                      exclude debug symbols\n"
     50         "  --target-arch [name]         specify target architecture\n"
     51         "  --target-environ [name]      specify target environment\n"
     52         "  --target-os [name]           specify target operating system\n"
     53         "  --verbose                    turn on compiler debug output\n"
     54         "  --zig-std-dir [path]         directory where zig standard library resides\n"
     55         "  -L[dir]                      alias for --library-path\n"
     56         "  -dirafter [dir]              same as -isystem but do it last\n"
     57         "  -framework [name]            (darwin only) link against framework\n"
     58         "  -isystem [dir]               add additional search path for other .h files\n"
     59         "  -mconsole                    (windows only) --subsystem console to the linker\n"
     60         "  -mios-version-min [ver]      (darwin only) set iOS deployment target\n"
     61         "  -mlinker-version [ver]       (darwin only) override linker version\n"
     62         "  -mmacosx-version-min [ver]   (darwin only) set Mac OS X deployment target\n"
     63         "  -municode                    (windows only) link with unicode\n"
     64         "  -mwindows                    (windows only) --subsystem windows to the linker\n"
     65         "  -rdynamic                    add all symbols to the dynamic symbol table\n"
     66         "  -rpath [path]                add directory to the runtime library search path\n"
     67         "Test Options:\n"
     68         "  --test-filter [text]         skip tests that do not match filter\n"
     69         "  --test-name-prefix [text]    add prefix to all tests\n"
     70         "Dynamic Library Options:\n"
     71         "  --ver-major [ver]            semver major version\n"
     72         "  --ver-minor [ver]            semver minor version\n"
     73         "  --ver-patch [ver]            semver patch version\n"
     74     , arg0);
     75     return EXIT_FAILURE;
     76 }
     77 
     78 static int print_target_list(FILE *f) {
     79     ZigTarget native;
     80     get_native_target(&native);
     81 
     82     fprintf(f, "Architectures:\n");
     83     size_t arch_count = target_arch_count();
     84     for (size_t arch_i = 0; arch_i < arch_count; arch_i += 1) {
     85         const ArchType *arch = get_target_arch(arch_i);
     86         char arch_name[50];
     87         get_arch_name(arch_name, arch);
     88         const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?
     89             " (native)" : "";
     90         fprintf(f, "  %s%s\n", arch_name, native_str);
     91     }
     92 
     93     fprintf(f, "\nOperating Systems:\n");
     94     size_t os_count = target_os_count();
     95     for (size_t i = 0; i < os_count; i += 1) {
     96         ZigLLVM_OSType os_type = get_target_os(i);
     97         const char *native_str = (native.os == os_type) ? " (native)" : "";
     98         fprintf(f, "  %s%s\n", get_target_os_name(os_type), native_str);
     99     }
    100 
    101     fprintf(f, "\nEnvironments:\n");
    102     size_t environ_count = target_environ_count();
    103     for (size_t i = 0; i < environ_count; i += 1) {
    104         ZigLLVM_EnvironmentType environ_type = get_target_environ(i);
    105         const char *native_str = (native.env_type == environ_type) ? " (native)" : "";
    106         fprintf(f, "  %s%s\n", ZigLLVMGetEnvironmentTypeName(environ_type), native_str);
    107     }
    108 
    109     return EXIT_SUCCESS;
    110 }
    111 
    112 enum Cmd {
    113     CmdInvalid,
    114     CmdBuild,
    115     CmdTest,
    116     CmdVersion,
    117     CmdParseH,
    118     CmdTargets,
    119     CmdAsm,
    120     CmdLink,
    121 };
    122 
    123 int main(int argc, char **argv) {
    124     os_init();
    125 
    126     char *arg0 = argv[0];
    127     Cmd cmd = CmdInvalid;
    128     const char *in_file = nullptr;
    129     const char *out_file = nullptr;
    130     bool is_release_build = false;
    131     bool strip = false;
    132     bool is_static = false;
    133     OutType out_type = OutTypeUnknown;
    134     const char *out_name = nullptr;
    135     bool verbose = false;
    136     ErrColor color = ErrColorAuto;
    137     const char *libc_lib_dir = nullptr;
    138     const char *libc_static_lib_dir = nullptr;
    139     const char *libc_include_dir = nullptr;
    140     const char *zig_std_dir = nullptr;
    141     const char *dynamic_linker = nullptr;
    142     ZigList<const char *> clang_argv = {0};
    143     ZigList<const char *> lib_dirs = {0};
    144     ZigList<const char *> link_libs = {0};
    145     ZigList<const char *> frameworks = {0};
    146     int err;
    147     const char *target_arch = nullptr;
    148     const char *target_os = nullptr;
    149     const char *target_environ = nullptr;
    150     bool mwindows = false;
    151     bool mconsole = false;
    152     bool municode = false;
    153     const char *mlinker_version = nullptr;
    154     bool rdynamic = false;
    155     const char *mmacosx_version_min = nullptr;
    156     const char *mios_version_min = nullptr;
    157     const char *linker_script = nullptr;
    158     ZigList<const char *> rpath_list = {0};
    159     bool each_lib_rpath = false;
    160     ZigList<const char *> objects = {0};
    161     const char *test_filter = nullptr;
    162     const char *test_name_prefix = nullptr;
    163     size_t ver_major = 0;
    164     size_t ver_minor = 0;
    165     size_t ver_patch = 0;
    166 
    167     if (argc >= 2 && strcmp(argv[1], "build") == 0) {
    168         const char *zig_exe_path = arg0;
    169         const char *build_file = "build.zig";
    170         bool asked_for_help = false;
    171 
    172         init_all_targets();
    173 
    174         Buf *zig_std_dir = buf_create_from_str(ZIG_STD_DIR);
    175         Buf *special_dir = buf_alloc();
    176         os_path_join(zig_std_dir, buf_sprintf("special"), special_dir);
    177 
    178         Buf *build_runner_path = buf_alloc();
    179         os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path);
    180 
    181         ZigList<const char *> args = {0};
    182         args.append(zig_exe_path);
    183         args.append(NULL); // placeholder
    184         for (int i = 2; i < argc; i += 1) {
    185             if (strcmp(argv[i], "--debug-build-verbose") == 0) {
    186                 verbose = true;
    187             } else if (strcmp(argv[i], "--help") == 0) {
    188                 asked_for_help = true;
    189                 args.append(argv[i]);
    190             } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) {
    191                 build_file = argv[i + 1];
    192                 i += 1;
    193             } else {
    194                 args.append(argv[i]);
    195             }
    196         }
    197 
    198 
    199         Buf root_source_dir = BUF_INIT;
    200         Buf root_source_code = BUF_INIT;
    201         Buf root_source_name = BUF_INIT;
    202         os_path_split(build_runner_path, &root_source_dir, &root_source_name);
    203         if ((err = os_fetch_file_path(build_runner_path, &root_source_code))) {
    204             fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(build_runner_path), err_str(err));
    205             return 1;
    206         }
    207         CodeGen *g = codegen_create(&root_source_dir, nullptr);
    208         codegen_set_out_name(g, buf_create_from_str("build"));
    209         codegen_set_out_type(g, OutTypeExe);
    210         codegen_set_verbose(g, verbose);
    211 
    212         Buf build_file_abs = BUF_INIT;
    213         os_path_resolve(buf_create_from_str("."), buf_create_from_str(build_file), &build_file_abs);
    214         Buf build_file_basename = BUF_INIT;
    215         Buf build_file_dirname = BUF_INIT;
    216         os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
    217 
    218         args.items[1] = buf_ptr(&build_file_dirname);
    219 
    220         bool build_file_exists;
    221         if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {
    222             fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err));
    223             return 1;
    224         }
    225         if (!build_file_exists) {
    226             if (asked_for_help) {
    227                 // This usage text has to be synchronized with std/special/build_runner.zig
    228                 fprintf(stdout,
    229                         "Usage: %s build [options]\n"
    230                         "\n"
    231                         "General Options:\n"
    232                         "  --help                 Print this help and exit\n"
    233                         "  --build-file [file]    Override path to build.zig\n"
    234                         "  --verbose              Print commands before executing them\n"
    235                         "  --debug-build-verbose  Print verbose debugging information for the build system itself\n"
    236                         "  --prefix [prefix]      Override default install prefix\n"
    237                         "\n"
    238                         "More options become available when the build file is found.\n"
    239                         "Run this command with no options to generate a build.zig template.\n"
    240                 , zig_exe_path);
    241                 return 0;
    242             }
    243             Buf *build_template_path = buf_alloc();
    244             os_path_join(special_dir, buf_create_from_str("build_file_template.zig"), build_template_path);
    245 
    246             if ((err = os_copy_file(build_template_path, &build_file_abs))) {
    247                 fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));
    248             } else {
    249                 fprintf(stderr, "Wrote build.zig template\n");
    250             }
    251             return 1;
    252         }
    253 
    254         PackageTableEntry *build_pkg = new_package(buf_ptr(&build_file_dirname), buf_ptr(&build_file_basename));
    255         build_pkg->package_table.put(buf_create_from_str("std"), g->std_package);
    256         g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
    257         codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
    258         codegen_link(g, "build");
    259 
    260         Termination term;
    261         os_spawn_process("./build", args, &term);
    262         if (term.how != TerminationIdClean || term.code != 0) {
    263             fprintf(stderr, "\nBuild failed. Use the following command to reproduce the failure:\n");
    264             fprintf(stderr, "./build");
    265             for (size_t i = 0; i < args.length; i += 1) {
    266                 fprintf(stderr, " %s", args.at(i));
    267             }
    268             fprintf(stderr, "\n");
    269         }
    270         return (term.how == TerminationIdClean) ? term.code : -1;
    271     }
    272 
    273     for (int i = 1; i < argc; i += 1) {
    274         char *arg = argv[i];
    275 
    276         if (arg[0] == '-') {
    277             if (strcmp(arg, "--release") == 0) {
    278                 is_release_build = true;
    279             } else if (strcmp(arg, "--strip") == 0) {
    280                 strip = true;
    281             } else if (strcmp(arg, "--static") == 0) {
    282                 is_static = true;
    283             } else if (strcmp(arg, "--verbose") == 0) {
    284                 verbose = true;
    285             } else if (strcmp(arg, "-mwindows") == 0) {
    286                 mwindows = true;
    287             } else if (strcmp(arg, "-mconsole") == 0) {
    288                 mconsole = true;
    289             } else if (strcmp(arg, "-municode") == 0) {
    290                 municode = true;
    291             } else if (strcmp(arg, "-rdynamic") == 0) {
    292                 rdynamic = true;
    293             } else if (strcmp(arg, "--each-lib-rpath") == 0) {
    294                 each_lib_rpath = true;
    295             } else if (arg[1] == 'L' && arg[2] != 0) {
    296                 // alias for --library-path
    297                 lib_dirs.append(&arg[2]);
    298             } else if (i + 1 >= argc) {
    299                 return usage(arg0);
    300             } else {
    301                 i += 1;
    302                 if (i >= argc) {
    303                     return usage(arg0);
    304                 } else if (strcmp(arg, "--output") == 0) {
    305                     out_file = argv[i];
    306                 } else if (strcmp(arg, "--color") == 0) {
    307                     if (strcmp(argv[i], "auto") == 0) {
    308                         color = ErrColorAuto;
    309                     } else if (strcmp(argv[i], "on") == 0) {
    310                         color = ErrColorOn;
    311                     } else if (strcmp(argv[i], "off") == 0) {
    312                         color = ErrColorOff;
    313                     } else {
    314                         return usage(arg0);
    315                     }
    316                 } else if (strcmp(arg, "--name") == 0) {
    317                     out_name = argv[i];
    318                 } else if (strcmp(arg, "--libc-lib-dir") == 0) {
    319                     libc_lib_dir = argv[i];
    320                 } else if (strcmp(arg, "--libc-static-lib-dir") == 0) {
    321                     libc_static_lib_dir = argv[i];
    322                 } else if (strcmp(arg, "--libc-include-dir") == 0) {
    323                     libc_include_dir = argv[i];
    324                 } else if (strcmp(arg, "--zig-std-dir") == 0) {
    325                     zig_std_dir = argv[i];
    326                 } else if (strcmp(arg, "--dynamic-linker") == 0) {
    327                     dynamic_linker = argv[i];
    328                 } else if (strcmp(arg, "-isystem") == 0) {
    329                     clang_argv.append("-isystem");
    330                     clang_argv.append(argv[i]);
    331                 } else if (strcmp(arg, "-dirafter") == 0) {
    332                     clang_argv.append("-dirafter");
    333                     clang_argv.append(argv[i]);
    334                 } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
    335                     lib_dirs.append(argv[i]);
    336                 } else if (strcmp(arg, "--library") == 0) {
    337                     link_libs.append(argv[i]);
    338                 } else if (strcmp(arg, "--target-arch") == 0) {
    339                     target_arch = argv[i];
    340                 } else if (strcmp(arg, "--target-os") == 0) {
    341                     target_os = argv[i];
    342                 } else if (strcmp(arg, "--target-environ") == 0) {
    343                     target_environ = argv[i];
    344                 } else if (strcmp(arg, "-mlinker-version") == 0) {
    345                     mlinker_version = argv[i];
    346                 } else if (strcmp(arg, "-mmacosx-version-min") == 0) {
    347                     mmacosx_version_min = argv[i];
    348                 } else if (strcmp(arg, "-mios-version-min") == 0) {
    349                     mios_version_min = argv[i];
    350                 } else if (strcmp(arg, "-framework") == 0) {
    351                     frameworks.append(argv[i]);
    352                 } else if (strcmp(arg, "--linker-script") == 0) {
    353                     linker_script = argv[i];
    354                 } else if (strcmp(arg, "-rpath") == 0) {
    355                     rpath_list.append(argv[i]);
    356                 } else if (strcmp(arg, "--test-filter") == 0) {
    357                     test_filter = argv[i];
    358                 } else if (strcmp(arg, "--test-name-prefix") == 0) {
    359                     test_name_prefix = argv[i];
    360                 } else if (strcmp(arg, "--ver-major") == 0) {
    361                     ver_major = atoi(argv[i]);
    362                 } else if (strcmp(arg, "--ver-minor") == 0) {
    363                     ver_minor = atoi(argv[i]);
    364                 } else if (strcmp(arg, "--ver-patch") == 0) {
    365                     ver_patch = atoi(argv[i]);
    366                 } else {
    367                     fprintf(stderr, "Invalid argument: %s\n", arg);
    368                     return usage(arg0);
    369                 }
    370             }
    371         } else if (cmd == CmdInvalid) {
    372             if (strcmp(arg, "build_exe") == 0) {
    373                 cmd = CmdBuild;
    374                 out_type = OutTypeExe;
    375             } else if (strcmp(arg, "build_obj") == 0) {
    376                 cmd = CmdBuild;
    377                 out_type = OutTypeObj;
    378             } else if (strcmp(arg, "build_lib") == 0) {
    379                 cmd = CmdBuild;
    380                 out_type = OutTypeLib;
    381             } else if (strcmp(arg, "link_lib") == 0) {
    382                 cmd = CmdLink;
    383                 out_type = OutTypeLib;
    384             } else if (strcmp(arg, "link_exe") == 0) {
    385                 cmd = CmdLink;
    386                 out_type = OutTypeExe;
    387             } else if (strcmp(arg, "version") == 0) {
    388                 cmd = CmdVersion;
    389             } else if (strcmp(arg, "parseh") == 0) {
    390                 cmd = CmdParseH;
    391             } else if (strcmp(arg, "test") == 0) {
    392                 cmd = CmdTest;
    393             } else if (strcmp(arg, "targets") == 0) {
    394                 cmd = CmdTargets;
    395             } else if (strcmp(arg, "asm") == 0) {
    396                 cmd = CmdAsm;
    397             } else {
    398                 fprintf(stderr, "Unrecognized command: %s\n", arg);
    399                 return usage(arg0);
    400             }
    401         } else {
    402             switch (cmd) {
    403                 case CmdBuild:
    404                 case CmdParseH:
    405                 case CmdTest:
    406                 case CmdAsm:
    407                     if (!in_file) {
    408                         in_file = arg;
    409                     } else {
    410                         return usage(arg0);
    411                     }
    412                     break;
    413                 case CmdLink:
    414                     objects.append(arg);
    415                     break;
    416                 case CmdVersion:
    417                 case CmdTargets:
    418                     return usage(arg0);
    419                 case CmdInvalid:
    420                     zig_unreachable();
    421             }
    422         }
    423     }
    424 
    425     switch (cmd) {
    426     case CmdBuild:
    427     case CmdParseH:
    428     case CmdTest:
    429     case CmdAsm:
    430     case CmdLink:
    431         {
    432             bool one_source_input = (cmd == CmdBuild || cmd == CmdParseH || cmd == CmdTest || cmd == CmdAsm);
    433             if (one_source_input) {
    434                 if (!in_file) {
    435                     fprintf(stderr, "Expected source file argument.\n");
    436                     return usage(arg0);
    437                 }
    438             } else if (cmd == CmdLink) {
    439                 if (objects.length == 0) {
    440                     fprintf(stderr, "Expected one or more object arguments.\n");
    441                     return usage(arg0);
    442                 }
    443             } else {
    444                 zig_unreachable();
    445             }
    446 
    447             assert((cmd != CmdBuild && cmd != CmdLink) || out_type != OutTypeUnknown);
    448 
    449             init_all_targets();
    450 
    451             ZigTarget alloc_target;
    452             ZigTarget *target;
    453             if (!target_arch && !target_os && !target_environ) {
    454                 target = nullptr;
    455             } else {
    456                 target = &alloc_target;
    457                 get_unknown_target(target);
    458                 if (target_arch) {
    459                     if (parse_target_arch(target_arch, &target->arch)) {
    460                         fprintf(stderr, "invalid --target-arch argument\n");
    461                         return usage(arg0);
    462                     }
    463                 }
    464                 if (target_os) {
    465                     if (parse_target_os(target_os, &target->os)) {
    466                         fprintf(stderr, "invalid --target-os argument\n");
    467                         return usage(arg0);
    468                     }
    469                 }
    470                 if (target_environ) {
    471                     if (parse_target_environ(target_environ, &target->env_type)) {
    472                         fprintf(stderr, "invalid --target-environ argument\n");
    473                         return usage(arg0);
    474                     }
    475                 }
    476             }
    477 
    478             bool need_name = (cmd == CmdBuild || cmd == CmdAsm || cmd == CmdLink);
    479 
    480             Buf in_file_buf = BUF_INIT;
    481 
    482             Buf root_source_dir = BUF_INIT;
    483             Buf root_source_code = BUF_INIT;
    484             Buf root_source_name = BUF_INIT;
    485 
    486             Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
    487                 (out_name == nullptr) ? nullptr : buf_create_from_str(out_name);
    488 
    489             if (one_source_input) {
    490                 buf_init_from_str(&in_file_buf, in_file);
    491 
    492                 if (buf_eql_str(&in_file_buf, "-")) {
    493                     os_get_cwd(&root_source_dir);
    494                     if ((err = os_fetch_file(stdin, &root_source_code))) {
    495                         fprintf(stderr, "unable to read stdin: %s\n", err_str(err));
    496                         return 1;
    497                     }
    498                     buf_init_from_str(&root_source_name, "");
    499 
    500                 } else {
    501                     os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
    502                     if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) {
    503                         fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err));
    504                         return 1;
    505                     }
    506 
    507                     if (need_name && buf_out_name == nullptr) {
    508                         buf_out_name = buf_alloc();
    509                         Buf ext_name = BUF_INIT;
    510                         os_path_extname(&root_source_name, buf_out_name, &ext_name);
    511                     }
    512                 }
    513             } else if (cmd == CmdLink) {
    514                 os_get_cwd(&root_source_dir);
    515             } else {
    516                 zig_unreachable();
    517             }
    518 
    519             if (need_name && buf_out_name == nullptr) {
    520                 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
    521                 return usage(arg0);
    522             }
    523 
    524             CodeGen *g = codegen_create(&root_source_dir, target);
    525             codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
    526             codegen_set_is_release(g, is_release_build);
    527             codegen_set_is_test(g, cmd == CmdTest);
    528             codegen_set_linker_script(g, linker_script);
    529             if (each_lib_rpath)
    530                 codegen_set_each_lib_rpath(g, each_lib_rpath);
    531 
    532             codegen_set_clang_argv(g, clang_argv.items, clang_argv.length);
    533             codegen_set_strip(g, strip);
    534             codegen_set_is_static(g, is_static);
    535             if (cmd == CmdAsm) {
    536                 codegen_set_out_type(g, OutTypeObj);
    537             } else if (out_type != OutTypeUnknown) {
    538                 codegen_set_out_type(g, out_type);
    539             } else if (cmd == CmdTest) {
    540                 codegen_set_out_type(g, OutTypeExe);
    541             }
    542             codegen_set_out_name(g, buf_out_name);
    543             if (libc_lib_dir)
    544                 codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir));
    545             if (libc_static_lib_dir)
    546                 codegen_set_libc_static_lib_dir(g, buf_create_from_str(libc_static_lib_dir));
    547             if (libc_include_dir)
    548                 codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir));
    549             if (zig_std_dir)
    550                 codegen_set_zig_std_dir(g, buf_create_from_str(zig_std_dir));
    551             if (dynamic_linker)
    552                 codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker));
    553             codegen_set_verbose(g, verbose);
    554             codegen_set_errmsg_color(g, color);
    555 
    556             for (size_t i = 0; i < lib_dirs.length; i += 1) {
    557                 codegen_add_lib_dir(g, lib_dirs.at(i));
    558             }
    559             for (size_t i = 0; i < link_libs.length; i += 1) {
    560                 codegen_add_link_lib(g, link_libs.at(i));
    561             }
    562             for (size_t i = 0; i < frameworks.length; i += 1) {
    563                 codegen_add_framework(g, frameworks.at(i));
    564             }
    565             for (size_t i = 0; i < rpath_list.length; i += 1) {
    566                 codegen_add_rpath(g, rpath_list.at(i));
    567             }
    568 
    569             codegen_set_windows_subsystem(g, mwindows, mconsole);
    570             codegen_set_windows_unicode(g, municode);
    571             codegen_set_rdynamic(g, rdynamic);
    572             if (mlinker_version) {
    573                 codegen_set_mlinker_version(g, buf_create_from_str(mlinker_version));
    574             }
    575             if (mmacosx_version_min && mios_version_min) {
    576                 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
    577                 return EXIT_FAILURE;
    578             }
    579 
    580             if (mmacosx_version_min) {
    581                 codegen_set_mmacosx_version_min(g, buf_create_from_str(mmacosx_version_min));
    582             }
    583 
    584             if (mios_version_min) {
    585                 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
    586             }
    587 
    588             if (test_filter) {
    589                 codegen_set_test_filter(g, buf_create_from_str(test_filter));
    590             }
    591 
    592             if (test_name_prefix) {
    593                 codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix));
    594             }
    595 
    596             if (cmd == CmdBuild) {
    597                 codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
    598                 codegen_link(g, out_file);
    599                 return EXIT_SUCCESS;
    600             } else if (cmd == CmdLink) {
    601                 for (size_t i = 0; i < objects.length; i += 1) {
    602                     codegen_add_object(g, buf_create_from_str(objects.at(i)));
    603                 }
    604                 codegen_link(g, out_file);
    605                 return EXIT_SUCCESS;
    606             } else if (cmd == CmdAsm) {
    607                 codegen_add_root_assembly(g, &root_source_dir, &root_source_name, &root_source_code);
    608                 codegen_link(g, out_file);
    609                 return EXIT_SUCCESS;
    610             } else if (cmd == CmdParseH) {
    611                 codegen_parseh(g, &root_source_dir, &root_source_name, &root_source_code);
    612                 ast_render_decls(stdout, 4, g->root_import);
    613                 return EXIT_SUCCESS;
    614             } else if (cmd == CmdTest) {
    615                 codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
    616                 codegen_link(g, "./test");
    617                 ZigList<const char *> args = {0};
    618                 Termination term;
    619                 os_spawn_process("./test", args, &term);
    620                 if (term.how != TerminationIdClean || term.code != 0) {
    621                     fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
    622                     fprintf(stderr, "./test\n");
    623                 }
    624                 return (term.how == TerminationIdClean) ? term.code : -1;
    625             } else {
    626                 zig_unreachable();
    627             }
    628         }
    629     case CmdVersion:
    630         printf("%s\n", ZIG_VERSION_STRING);
    631         return EXIT_SUCCESS;
    632     case CmdTargets:
    633         return print_target_list(stdout);
    634     case CmdInvalid:
    635         return usage(arg0);
    636     }
    637 }