zig

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

blob a4aa00ae (36534B) - 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         "  build                        build project from build.zig\n"
     23         "  build-exe [source]           create executable from source or object files\n"
     24         "  build-lib [source]           create library from source or object files\n"
     25         "  build-obj [source]           create object from source or assembly\n"
     26         "  parsec [source]              convert c code to zig code\n"
     27         "  targets                      list available compilation targets\n"
     28         "  test [source]                create and run a test build\n"
     29         "  version                      print version number and exit\n"
     30         "  zen                          print zen of zig and exit\n"
     31         "Compile Options:\n"
     32         "  --assembly [source]          add assembly file to build\n"
     33         "  --cache-dir [path]           override the cache directory\n"
     34         "  --color [auto|off|on]        enable or disable colored error messages\n"
     35         "  --enable-timing-info         print timing diagnostics\n"
     36         "  --libc-include-dir [path]    directory where libc stdlib.h resides\n"
     37         "  --name [name]                override output name\n"
     38         "  --output [file]              override destination path\n"
     39         "  --output-h [file]            override generated header file path\n"
     40         "  --pkg-begin [name] [path]    make package available to import and push current pkg\n"
     41         "  --pkg-end                    pop current pkg\n"
     42         "  --release-fast               build with optimizations on and safety off\n"
     43         "  --release-safe               build with optimizations on and safety on\n"
     44         "  --static                     output will be statically linked\n"
     45         "  --strip                      exclude debug symbols\n"
     46         "  --target-arch [name]         specify target architecture\n"
     47         "  --target-environ [name]      specify target environment\n"
     48         "  --target-os [name]           specify target operating system\n"
     49         "  --verbose                    turn on compiler debug output\n"
     50         "  --verbose-link               turn on compiler debug output for linking only\n"
     51         "  --verbose-ir                 turn on compiler debug output for IR only\n"
     52         "  --zig-install-prefix [path]  override directory where zig thinks it is installed\n"
     53         "  -dirafter [dir]              same as -isystem but do it last\n"
     54         "  -isystem [dir]               add additional search path for other .h files\n"
     55         "  -mllvm [arg]                 additional arguments to forward to LLVM's option processing\n"
     56         "Link Options:\n"
     57         "  --ar-path [path]             set the path to ar\n"
     58         "  --dynamic-linker [path]      set the path to ld.so\n"
     59         "  --each-lib-rpath             add rpath for each used dynamic library\n"
     60         "  --libc-lib-dir [path]        directory where libc crt1.o resides\n"
     61         "  --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n"
     62         "  --msvc-lib-dir [path]        (windows) directory where vcruntime.lib resides\n"
     63         "  --kernel32-lib-dir [path]    (windows) directory where kernel32.lib resides\n"
     64         "  --library [lib]              link against lib\n"
     65         "  --library-path [dir]         add a directory to the library search path\n"
     66         "  --linker-script [path]       use a custom linker script\n"
     67         "  --object [obj]               add object file to build\n"
     68         "  -L[dir]                      alias for --library-path\n"
     69         "  -rdynamic                    add all symbols to the dynamic symbol table\n"
     70         "  -rpath [path]                add directory to the runtime library search path\n"
     71         "  -mconsole                    (windows) --subsystem console to the linker\n"
     72         "  -mwindows                    (windows) --subsystem windows to the linker\n"
     73         "  -framework [name]            (darwin) link against framework\n"
     74         "  -mios-version-min [ver]      (darwin) set iOS deployment target\n"
     75         "  -mmacosx-version-min [ver]   (darwin) set Mac OS X deployment target\n"
     76         "  --ver-major [ver]            dynamic library semver major version\n"
     77         "  --ver-minor [ver]            dynamic library semver minor version\n"
     78         "  --ver-patch [ver]            dynamic library semver patch version\n"
     79         "Test Options:\n"
     80         "  --test-filter [text]         skip tests that do not match filter\n"
     81         "  --test-name-prefix [text]    add prefix to all tests\n"
     82         "  --test-cmd [arg]             specify test execution command one arg at a time\n"
     83         "  --test-cmd-bin               appends test binary path to test cmd args\n"
     84     , arg0);
     85     return EXIT_FAILURE;
     86 }
     87 
     88 static const char *ZIG_ZEN = "\n"
     89 " * Communicate intent precisely.\n"
     90 " * Edge cases matter.\n"
     91 " * Favor reading code over writing code.\n"
     92 " * Only one obvious way to do things.\n"
     93 " * Runtime crashes are better than bugs.\n"
     94 " * Compile errors are better than runtime crashes.\n"
     95 " * Incremental improvements.\n"
     96 " * Avoid local maximums.\n"
     97 " * Reduce the amount one must remember.\n"
     98 " * Minimize energy spent on coding style.\n"
     99 " * Together we serve end users.\n";
    100 
    101 static int print_target_list(FILE *f) {
    102     ZigTarget native;
    103     get_native_target(&native);
    104 
    105     fprintf(f, "Architectures:\n");
    106     size_t arch_count = target_arch_count();
    107     for (size_t arch_i = 0; arch_i < arch_count; arch_i += 1) {
    108         const ArchType *arch = get_target_arch(arch_i);
    109         char arch_name[50];
    110         get_arch_name(arch_name, arch);
    111         const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?
    112             " (native)" : "";
    113         fprintf(f, "  %s%s\n", arch_name, native_str);
    114     }
    115 
    116     fprintf(f, "\nOperating Systems:\n");
    117     size_t os_count = target_os_count();
    118     for (size_t i = 0; i < os_count; i += 1) {
    119         ZigLLVM_OSType os_type = get_target_os(i);
    120         const char *native_str = (native.os == os_type) ? " (native)" : "";
    121         fprintf(f, "  %s%s\n", get_target_os_name(os_type), native_str);
    122     }
    123 
    124     fprintf(f, "\nEnvironments:\n");
    125     size_t environ_count = target_environ_count();
    126     for (size_t i = 0; i < environ_count; i += 1) {
    127         ZigLLVM_EnvironmentType environ_type = get_target_environ(i);
    128         const char *native_str = (native.env_type == environ_type) ? " (native)" : "";
    129         fprintf(f, "  %s%s\n", ZigLLVMGetEnvironmentTypeName(environ_type), native_str);
    130     }
    131 
    132     return EXIT_SUCCESS;
    133 }
    134 
    135 static bool test_zig_install_prefix(Buf *test_path, Buf *out_zig_lib_dir) {
    136     Buf lib_buf = BUF_INIT;
    137     buf_init_from_str(&lib_buf, "lib");
    138 
    139     Buf zig_buf = BUF_INIT;
    140     buf_init_from_str(&zig_buf, "zig");
    141 
    142     Buf std_buf = BUF_INIT;
    143     buf_init_from_str(&std_buf, "std");
    144 
    145     Buf index_zig_buf = BUF_INIT;
    146     buf_init_from_str(&index_zig_buf, "index.zig");
    147 
    148     Buf test_lib_dir = BUF_INIT;
    149     Buf test_zig_dir = BUF_INIT;
    150     Buf test_std_dir = BUF_INIT;
    151     Buf test_index_file = BUF_INIT;
    152 
    153     os_path_join(test_path, &lib_buf, &test_lib_dir);
    154     os_path_join(&test_lib_dir, &zig_buf, &test_zig_dir);
    155     os_path_join(&test_zig_dir, &std_buf, &test_std_dir);
    156     os_path_join(&test_std_dir, &index_zig_buf, &test_index_file);
    157 
    158     int err;
    159     bool exists;
    160     if ((err = os_file_exists(&test_index_file, &exists))) {
    161         exists = false;
    162     }
    163     if (exists) {
    164         buf_init_from_buf(out_zig_lib_dir, &test_zig_dir);
    165         return true;
    166     }
    167     return false;
    168 }
    169 
    170 static int find_zig_lib_dir(Buf *out_path) {
    171     int err;
    172 
    173     Buf self_exe_path = BUF_INIT;
    174     if (!(err = os_self_exe_path(&self_exe_path))) {
    175         Buf *cur_path = &self_exe_path;
    176 
    177         for (;;) {
    178             Buf *test_dir = buf_alloc();
    179             os_path_dirname(cur_path, test_dir);
    180 
    181             if (buf_eql_buf(test_dir, cur_path)) {
    182                 break;
    183             }
    184 
    185             if (test_zig_install_prefix(test_dir, out_path)) {
    186                 return 0;
    187             }
    188 
    189             cur_path = test_dir;
    190         }
    191     }
    192 
    193     if (ZIG_INSTALL_PREFIX != nullptr) {
    194         if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
    195             return 0;
    196         }
    197     }
    198 
    199 
    200     return ErrorFileNotFound;
    201 }
    202 
    203 static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
    204     int err;
    205     Buf *result = buf_alloc();
    206     if (zig_install_prefix_arg == nullptr) {
    207         if ((err = find_zig_lib_dir(result))) {
    208             fprintf(stderr, "Unable to find zig lib directory. Reinstall Zig or use --zig-install-prefix.\n");
    209             exit(EXIT_FAILURE);
    210         }
    211         return result;
    212     }
    213     Buf *zig_lib_dir_buf = buf_create_from_str(zig_install_prefix_arg);
    214     if (test_zig_install_prefix(zig_lib_dir_buf, result)) {
    215         return result;
    216     }
    217 
    218     fprintf(stderr, "No Zig installation found at prefix: %s\n", zig_install_prefix_arg);
    219     exit(EXIT_FAILURE);
    220 }
    221 
    222 enum Cmd {
    223     CmdInvalid,
    224     CmdBuild,
    225     CmdTest,
    226     CmdVersion,
    227     CmdZen,
    228     CmdParseC,
    229     CmdTargets,
    230 };
    231 
    232 static const char *default_zig_cache_name = "zig-cache";
    233 
    234 struct CliPkg {
    235     const char *name;
    236     const char *path;
    237     ZigList<CliPkg *> children;
    238     CliPkg *parent;
    239 };
    240 
    241 static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
    242     for (size_t i = 0; i < cli_pkg->children.length; i += 1) {
    243         CliPkg *child_cli_pkg = cli_pkg->children.at(i);
    244 
    245         Buf *dirname = buf_alloc();
    246         Buf *basename = buf_alloc();
    247         os_path_split(buf_create_from_str(child_cli_pkg->path), dirname, basename);
    248 
    249         PackageTableEntry *child_pkg = codegen_create_package(g, buf_ptr(dirname), buf_ptr(basename));
    250         auto entry = pkg->package_table.put_unique(buf_create_from_str(child_cli_pkg->name), child_pkg);
    251         if (entry) {
    252             PackageTableEntry *existing_pkg = entry->value;
    253             Buf *full_path = buf_alloc();
    254             os_path_join(&existing_pkg->root_src_dir, &existing_pkg->root_src_path, full_path);
    255             fprintf(stderr, "Unable to add package '%s'->'%s': already exists as '%s'\n",
    256                     child_cli_pkg->name, child_cli_pkg->path, buf_ptr(full_path));
    257             exit(EXIT_FAILURE);
    258         }
    259 
    260         add_package(g, child_cli_pkg, child_pkg);
    261     }
    262 }
    263 
    264 int main(int argc, char **argv) {
    265     os_init();
    266 
    267     char *arg0 = argv[0];
    268     Cmd cmd = CmdInvalid;
    269     const char *in_file = nullptr;
    270     const char *out_file = nullptr;
    271     const char *out_file_h = nullptr;
    272     bool strip = false;
    273     bool is_static = false;
    274     OutType out_type = OutTypeUnknown;
    275     const char *out_name = nullptr;
    276     bool verbose = false;
    277     bool verbose_link = false;
    278     bool verbose_ir = false;
    279     ErrColor color = ErrColorAuto;
    280     const char *libc_lib_dir = nullptr;
    281     const char *libc_static_lib_dir = nullptr;
    282     const char *libc_include_dir = nullptr;
    283     const char *msvc_lib_dir = nullptr;
    284     const char *kernel32_lib_dir = nullptr;
    285     const char *zig_install_prefix = nullptr;
    286     const char *dynamic_linker = nullptr;
    287     ZigList<const char *> clang_argv = {0};
    288     ZigList<const char *> llvm_argv = {0};
    289     ZigList<const char *> lib_dirs = {0};
    290     ZigList<const char *> link_libs = {0};
    291     ZigList<const char *> frameworks = {0};
    292     int err;
    293     const char *target_arch = nullptr;
    294     const char *target_os = nullptr;
    295     const char *target_environ = nullptr;
    296     bool mwindows = false;
    297     bool mconsole = false;
    298     bool rdynamic = false;
    299     const char *mmacosx_version_min = nullptr;
    300     const char *mios_version_min = nullptr;
    301     const char *linker_script = nullptr;
    302     ZigList<const char *> rpath_list = {0};
    303     bool each_lib_rpath = false;
    304     ZigList<const char *> objects = {0};
    305     ZigList<const char *> asm_files = {0};
    306     const char *test_filter = nullptr;
    307     const char *test_name_prefix = nullptr;
    308     size_t ver_major = 0;
    309     size_t ver_minor = 0;
    310     size_t ver_patch = 0;
    311     bool timing_info = false;
    312     const char *cache_dir = nullptr;
    313     CliPkg *cur_pkg = allocate<CliPkg>(1);
    314     BuildMode build_mode = BuildModeDebug;
    315     ZigList<const char *> test_exec_args = {0};
    316 
    317     if (argc >= 2 && strcmp(argv[1], "build") == 0) {
    318         const char *zig_exe_path = arg0;
    319         const char *build_file = "build.zig";
    320         bool asked_for_help = false;
    321 
    322         init_all_targets();
    323 
    324         ZigList<const char *> args = {0};
    325         args.append(zig_exe_path);
    326         args.append(NULL); // placeholder
    327         args.append(NULL); // placeholder
    328         for (int i = 2; i < argc; i += 1) {
    329             if (strcmp(argv[i], "--debug-build-verbose") == 0) {
    330                 verbose = true;
    331             } else if (strcmp(argv[i], "--help") == 0) {
    332                 asked_for_help = true;
    333                 args.append(argv[i]);
    334             } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) {
    335                 build_file = argv[i + 1];
    336                 i += 1;
    337             } else if (i + 1 < argc && strcmp(argv[i], "--cache-dir") == 0) {
    338                 cache_dir = argv[i + 1];
    339                 i += 1;
    340             } else if (i + 1 < argc && strcmp(argv[i], "--zig-install-prefix") == 0) {
    341                 args.append(argv[i]);
    342                 i += 1;
    343                 zig_install_prefix = argv[i];
    344                 args.append(zig_install_prefix);
    345             } else {
    346                 args.append(argv[i]);
    347             }
    348         }
    349 
    350         Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
    351 
    352         Buf *zig_std_dir = buf_alloc();
    353         os_path_join(zig_lib_dir_buf, buf_create_from_str("std"), zig_std_dir);
    354 
    355         Buf *special_dir = buf_alloc();
    356         os_path_join(zig_std_dir, buf_sprintf("special"), special_dir);
    357 
    358         Buf *build_runner_path = buf_alloc();
    359         os_path_join(special_dir, buf_create_from_str("build_runner.zig"), build_runner_path);
    360 
    361 
    362         CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, zig_lib_dir_buf);
    363         codegen_set_out_name(g, buf_create_from_str("build"));
    364         codegen_set_verbose(g, verbose);
    365 
    366         Buf build_file_abs = BUF_INIT;
    367         os_path_resolve(buf_create_from_str("."), buf_create_from_str(build_file), &build_file_abs);
    368         Buf build_file_basename = BUF_INIT;
    369         Buf build_file_dirname = BUF_INIT;
    370         os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
    371 
    372         Buf *full_cache_dir = buf_alloc();
    373         if (cache_dir == nullptr) {
    374             os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), full_cache_dir);
    375         } else {
    376             os_path_resolve(buf_create_from_str("."), buf_create_from_str(cache_dir), full_cache_dir);
    377         }
    378 
    379         Buf *path_to_build_exe = buf_alloc();
    380         os_path_join(full_cache_dir, buf_create_from_str("build"), path_to_build_exe);
    381         codegen_set_cache_dir(g, full_cache_dir);
    382 
    383         args.items[1] = buf_ptr(&build_file_dirname);
    384         args.items[2] = buf_ptr(full_cache_dir);
    385 
    386         bool build_file_exists;
    387         if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {
    388             fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err));
    389             return 1;
    390         }
    391         if (!build_file_exists) {
    392             if (asked_for_help) {
    393                 // This usage text has to be synchronized with std/special/build_runner.zig
    394                 fprintf(stdout,
    395                         "Usage: %s build [options]\n"
    396                         "\n"
    397                         "General Options:\n"
    398                         "  --help                 Print this help and exit\n"
    399                         "  --build-file [file]    Override path to build.zig\n"
    400                         "  --cache-dir [path]     Override path to cache directory\n"
    401                         "  --verbose              Print commands before executing them\n"
    402                         "  --debug-build-verbose  Print verbose debugging information for the build system itself\n"
    403                         "  --prefix [prefix]      Override default install prefix\n"
    404                         "\n"
    405                         "More options become available when the build file is found.\n"
    406                         "Run this command with no options to generate a build.zig template.\n"
    407                 , zig_exe_path);
    408                 return 0;
    409             }
    410             Buf *build_template_path = buf_alloc();
    411             os_path_join(special_dir, buf_create_from_str("build_file_template.zig"), build_template_path);
    412 
    413             if ((err = os_copy_file(build_template_path, &build_file_abs))) {
    414                 fprintf(stderr, "Unable to write build.zig template: %s\n", err_str(err));
    415             } else {
    416                 fprintf(stderr, "Wrote build.zig template\n");
    417             }
    418             return 1;
    419         }
    420 
    421         PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
    422                 buf_ptr(&build_file_basename));
    423         g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
    424         codegen_build(g);
    425         codegen_link(g, buf_ptr(path_to_build_exe));
    426         codegen_destroy(g);
    427 
    428         Termination term;
    429         os_spawn_process(buf_ptr(path_to_build_exe), args, &term);
    430         if (term.how != TerminationIdClean || term.code != 0) {
    431             fprintf(stderr, "\nBuild failed. Use the following command to reproduce the failure:\n");
    432             fprintf(stderr, "%s", buf_ptr(path_to_build_exe));
    433             for (size_t i = 0; i < args.length; i += 1) {
    434                 fprintf(stderr, " %s", args.at(i));
    435             }
    436             fprintf(stderr, "\n");
    437         }
    438         return (term.how == TerminationIdClean) ? term.code : -1;
    439     }
    440 
    441     for (int i = 1; i < argc; i += 1) {
    442         char *arg = argv[i];
    443 
    444         if (arg[0] == '-') {
    445             if (strcmp(arg, "--release-fast") == 0) {
    446                 build_mode = BuildModeFastRelease;
    447             } else if (strcmp(arg, "--release-safe") == 0) {
    448                 build_mode = BuildModeSafeRelease;
    449             } else if (strcmp(arg, "--strip") == 0) {
    450                 strip = true;
    451             } else if (strcmp(arg, "--static") == 0) {
    452                 is_static = true;
    453             } else if (strcmp(arg, "--verbose") == 0) {
    454                 verbose = true;
    455             } else if (strcmp(arg, "--verbose-link") == 0) {
    456                 verbose_link = true;
    457             } else if (strcmp(arg, "--verbose-ir") == 0) {
    458                 verbose_ir = true;
    459             } else if (strcmp(arg, "-mwindows") == 0) {
    460                 mwindows = true;
    461             } else if (strcmp(arg, "-mconsole") == 0) {
    462                 mconsole = true;
    463             } else if (strcmp(arg, "-rdynamic") == 0) {
    464                 rdynamic = true;
    465             } else if (strcmp(arg, "--each-lib-rpath") == 0) {
    466                 each_lib_rpath = true;
    467             } else if (strcmp(arg, "--enable-timing-info") == 0) {
    468                 timing_info = true;
    469             } else if (strcmp(arg, "--test-cmd-bin") == 0) {
    470                 test_exec_args.append(nullptr);
    471             } else if (arg[1] == 'L' && arg[2] != 0) {
    472                 // alias for --library-path
    473                 lib_dirs.append(&arg[2]);
    474             } else if (strcmp(arg, "--pkg-begin") == 0) {
    475                 if (i + 2 >= argc) {
    476                     fprintf(stderr, "Expected 2 arguments after --pkg-begin\n");
    477                     return usage(arg0);
    478                 }
    479                 CliPkg *new_cur_pkg = allocate<CliPkg>(1);
    480                 i += 1;
    481                 new_cur_pkg->name = argv[i];
    482                 i += 1;
    483                 new_cur_pkg->path = argv[i];
    484                 new_cur_pkg->parent = cur_pkg;
    485                 cur_pkg->children.append(new_cur_pkg);
    486                 cur_pkg = new_cur_pkg;
    487             } else if (strcmp(arg, "--pkg-end") == 0) {
    488                 if (cur_pkg->parent == nullptr) {
    489                     fprintf(stderr, "Encountered --pkg-end with no matching --pkg-begin\n");
    490                     return EXIT_FAILURE;
    491                 }
    492                 cur_pkg = cur_pkg->parent;
    493             } else if (i + 1 >= argc) {
    494                 fprintf(stderr, "Expected another argument after %s\n", arg);
    495                 return usage(arg0);
    496             } else {
    497                 i += 1;
    498                 if (strcmp(arg, "--output") == 0) {
    499                     out_file = argv[i];
    500                 } else if (strcmp(arg, "--output-h") == 0) {
    501                     out_file_h = argv[i];
    502                 } else if (strcmp(arg, "--color") == 0) {
    503                     if (strcmp(argv[i], "auto") == 0) {
    504                         color = ErrColorAuto;
    505                     } else if (strcmp(argv[i], "on") == 0) {
    506                         color = ErrColorOn;
    507                     } else if (strcmp(argv[i], "off") == 0) {
    508                         color = ErrColorOff;
    509                     } else {
    510                         fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
    511                         return usage(arg0);
    512                     }
    513                 } else if (strcmp(arg, "--name") == 0) {
    514                     out_name = argv[i];
    515                 } else if (strcmp(arg, "--libc-lib-dir") == 0) {
    516                     libc_lib_dir = argv[i];
    517                 } else if (strcmp(arg, "--libc-static-lib-dir") == 0) {
    518                     libc_static_lib_dir = argv[i];
    519                 } else if (strcmp(arg, "--libc-include-dir") == 0) {
    520                     libc_include_dir = argv[i];
    521                 } else if (strcmp(arg, "--msvc-lib-dir") == 0) {
    522                     msvc_lib_dir = argv[i];
    523                 } else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
    524                     kernel32_lib_dir = argv[i];
    525                 } else if (strcmp(arg, "--zig-install-prefix") == 0) {
    526                     zig_install_prefix = argv[i];
    527                 } else if (strcmp(arg, "--dynamic-linker") == 0) {
    528                     dynamic_linker = argv[i];
    529                 } else if (strcmp(arg, "-isystem") == 0) {
    530                     clang_argv.append("-isystem");
    531                     clang_argv.append(argv[i]);
    532                 } else if (strcmp(arg, "-dirafter") == 0) {
    533                     clang_argv.append("-dirafter");
    534                     clang_argv.append(argv[i]);
    535                 } else if (strcmp(arg, "-mllvm") == 0) {
    536                     clang_argv.append("-mllvm");
    537                     clang_argv.append(argv[i]);
    538 
    539                     llvm_argv.append(argv[i]);
    540                 } else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
    541                     lib_dirs.append(argv[i]);
    542                 } else if (strcmp(arg, "--library") == 0) {
    543                     link_libs.append(argv[i]);
    544                 } else if (strcmp(arg, "--object") == 0) {
    545                     objects.append(argv[i]);
    546                 } else if (strcmp(arg, "--assembly") == 0) {
    547                     asm_files.append(argv[i]);
    548                 } else if (strcmp(arg, "--cache-dir") == 0) {
    549                     cache_dir = argv[i];
    550                 } else if (strcmp(arg, "--target-arch") == 0) {
    551                     target_arch = argv[i];
    552                 } else if (strcmp(arg, "--target-os") == 0) {
    553                     target_os = argv[i];
    554                 } else if (strcmp(arg, "--target-environ") == 0) {
    555                     target_environ = argv[i];
    556                 } else if (strcmp(arg, "-mmacosx-version-min") == 0) {
    557                     mmacosx_version_min = argv[i];
    558                 } else if (strcmp(arg, "-mios-version-min") == 0) {
    559                     mios_version_min = argv[i];
    560                 } else if (strcmp(arg, "-framework") == 0) {
    561                     frameworks.append(argv[i]);
    562                 } else if (strcmp(arg, "--linker-script") == 0) {
    563                     linker_script = argv[i];
    564                 } else if (strcmp(arg, "-rpath") == 0) {
    565                     rpath_list.append(argv[i]);
    566                 } else if (strcmp(arg, "--test-filter") == 0) {
    567                     test_filter = argv[i];
    568                 } else if (strcmp(arg, "--test-name-prefix") == 0) {
    569                     test_name_prefix = argv[i];
    570                 } else if (strcmp(arg, "--ver-major") == 0) {
    571                     ver_major = atoi(argv[i]);
    572                 } else if (strcmp(arg, "--ver-minor") == 0) {
    573                     ver_minor = atoi(argv[i]);
    574                 } else if (strcmp(arg, "--ver-patch") == 0) {
    575                     ver_patch = atoi(argv[i]);
    576                 } else if (strcmp(arg, "--test-cmd") == 0) {
    577                     test_exec_args.append(argv[i]);
    578                 } else {
    579                     fprintf(stderr, "Invalid argument: %s\n", arg);
    580                     return usage(arg0);
    581                 }
    582             }
    583         } else if (cmd == CmdInvalid) {
    584             if (strcmp(arg, "build-exe") == 0) {
    585                 cmd = CmdBuild;
    586                 out_type = OutTypeExe;
    587             } else if (strcmp(arg, "build-obj") == 0) {
    588                 cmd = CmdBuild;
    589                 out_type = OutTypeObj;
    590             } else if (strcmp(arg, "build-lib") == 0) {
    591                 cmd = CmdBuild;
    592                 out_type = OutTypeLib;
    593             } else if (strcmp(arg, "version") == 0) {
    594                 cmd = CmdVersion;
    595             } else if (strcmp(arg, "zen") == 0) {
    596                 cmd = CmdZen;
    597             } else if (strcmp(arg, "parsec") == 0) {
    598                 cmd = CmdParseC;
    599             } else if (strcmp(arg, "test") == 0) {
    600                 cmd = CmdTest;
    601                 out_type = OutTypeExe;
    602             } else if (strcmp(arg, "targets") == 0) {
    603                 cmd = CmdTargets;
    604             } else {
    605                 fprintf(stderr, "Unrecognized command: %s\n", arg);
    606                 return usage(arg0);
    607             }
    608         } else {
    609             switch (cmd) {
    610                 case CmdBuild:
    611                 case CmdParseC:
    612                 case CmdTest:
    613                     if (!in_file) {
    614                         in_file = arg;
    615                     } else {
    616                         fprintf(stderr, "Unexpected extra parameter: %s\n", arg);
    617                         return usage(arg0);
    618                     }
    619                     break;
    620                 case CmdVersion:
    621                 case CmdZen:
    622                 case CmdTargets:
    623                     fprintf(stderr, "Unexpected extra parameter: %s\n", arg);
    624                     return usage(arg0);
    625                 case CmdInvalid:
    626                     zig_unreachable();
    627             }
    628         }
    629     }
    630 
    631     if (cur_pkg->parent != nullptr) {
    632         fprintf(stderr, "Unmatched --pkg-begin\n");
    633         return EXIT_FAILURE;
    634     }
    635 
    636     init_all_targets();
    637 
    638     ZigTarget alloc_target;
    639     ZigTarget *target;
    640     if (!target_arch && !target_os && !target_environ) {
    641         target = nullptr;
    642     } else {
    643         target = &alloc_target;
    644         get_unknown_target(target);
    645         if (target_arch) {
    646             if (parse_target_arch(target_arch, &target->arch)) {
    647                 fprintf(stderr, "invalid --target-arch argument\n");
    648                 return usage(arg0);
    649             }
    650         }
    651         if (target_os) {
    652             if (parse_target_os(target_os, &target->os)) {
    653                 fprintf(stderr, "invalid --target-os argument\n");
    654                 return usage(arg0);
    655             }
    656         }
    657         if (target_environ) {
    658             if (parse_target_environ(target_environ, &target->env_type)) {
    659                 fprintf(stderr, "invalid --target-environ argument\n");
    660                 return usage(arg0);
    661             }
    662         }
    663     }
    664 
    665 
    666     switch (cmd) {
    667     case CmdBuild:
    668     case CmdParseC:
    669     case CmdTest:
    670         {
    671             if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
    672                 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
    673                 return usage(arg0);
    674             } else if ((cmd == CmdParseC || cmd == CmdTest) && !in_file) {
    675                 fprintf(stderr, "Expected source file argument.\n");
    676                 return usage(arg0);
    677             } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
    678                 fprintf(stderr, "When building an object file, --object arguments are invalid.\n");
    679                 return usage(arg0);
    680             }
    681 
    682             assert(cmd != CmdBuild || out_type != OutTypeUnknown);
    683 
    684             bool need_name = (cmd == CmdBuild || cmd == CmdParseC);
    685 
    686             Buf *in_file_buf = nullptr;
    687 
    688             Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
    689                 (out_name == nullptr) ? nullptr : buf_create_from_str(out_name);
    690 
    691             if (in_file) {
    692                 in_file_buf = buf_create_from_str(in_file);
    693 
    694                 if (need_name && buf_out_name == nullptr) {
    695                     Buf basename = BUF_INIT;
    696                     os_path_split(in_file_buf, nullptr, &basename);
    697                     buf_out_name = buf_alloc();
    698                     os_path_extname(&basename, buf_out_name, nullptr);
    699                 }
    700             }
    701 
    702             if (need_name && buf_out_name == nullptr) {
    703                 fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
    704                 return usage(arg0);
    705             }
    706 
    707             Buf *zig_root_source_file = (cmd == CmdParseC) ? nullptr : in_file_buf;
    708 
    709             Buf *full_cache_dir = buf_alloc();
    710             os_path_resolve(buf_create_from_str("."),
    711                     buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
    712                     full_cache_dir);
    713 
    714             Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
    715 
    716             CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, zig_lib_dir_buf);
    717             codegen_set_out_name(g, buf_out_name);
    718             codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
    719             codegen_set_is_test(g, cmd == CmdTest);
    720             codegen_set_linker_script(g, linker_script);
    721             codegen_set_cache_dir(g, full_cache_dir);
    722             if (each_lib_rpath)
    723                 codegen_set_each_lib_rpath(g, each_lib_rpath);
    724 
    725             codegen_set_clang_argv(g, clang_argv.items, clang_argv.length);
    726             codegen_set_llvm_argv(g, llvm_argv.items, llvm_argv.length);
    727             codegen_set_strip(g, strip);
    728             codegen_set_is_static(g, is_static);
    729             if (libc_lib_dir)
    730                 codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir));
    731             if (libc_static_lib_dir)
    732                 codegen_set_libc_static_lib_dir(g, buf_create_from_str(libc_static_lib_dir));
    733             if (libc_include_dir)
    734                 codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir));
    735             if (msvc_lib_dir)
    736                 codegen_set_msvc_lib_dir(g, buf_create_from_str(msvc_lib_dir));
    737             if (kernel32_lib_dir)
    738                 codegen_set_kernel32_lib_dir(g, buf_create_from_str(kernel32_lib_dir));
    739             if (dynamic_linker)
    740                 codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker));
    741             codegen_set_verbose(g, verbose);
    742             g->verbose_link = verbose_link;
    743             g->verbose_ir = verbose_ir;
    744             codegen_set_errmsg_color(g, color);
    745 
    746             for (size_t i = 0; i < lib_dirs.length; i += 1) {
    747                 codegen_add_lib_dir(g, lib_dirs.at(i));
    748             }
    749             for (size_t i = 0; i < link_libs.length; i += 1) {
    750                 LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
    751                 link_lib->provided_explicitly = true;
    752             }
    753             for (size_t i = 0; i < frameworks.length; i += 1) {
    754                 codegen_add_framework(g, frameworks.at(i));
    755             }
    756             for (size_t i = 0; i < rpath_list.length; i += 1) {
    757                 codegen_add_rpath(g, rpath_list.at(i));
    758             }
    759 
    760             codegen_set_windows_subsystem(g, mwindows, mconsole);
    761             codegen_set_rdynamic(g, rdynamic);
    762             if (mmacosx_version_min && mios_version_min) {
    763                 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
    764                 return EXIT_FAILURE;
    765             }
    766 
    767             if (mmacosx_version_min) {
    768                 codegen_set_mmacosx_version_min(g, buf_create_from_str(mmacosx_version_min));
    769             }
    770 
    771             if (mios_version_min) {
    772                 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
    773             }
    774 
    775             if (test_filter) {
    776                 codegen_set_test_filter(g, buf_create_from_str(test_filter));
    777             }
    778 
    779             if (test_name_prefix) {
    780                 codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix));
    781             }
    782 
    783             if (out_file_h)
    784                 codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
    785 
    786 
    787             add_package(g, cur_pkg, g->root_package);
    788 
    789             if (cmd == CmdBuild) {
    790                 for (size_t i = 0; i < objects.length; i += 1) {
    791                     codegen_add_object(g, buf_create_from_str(objects.at(i)));
    792                 }
    793                 for (size_t i = 0; i < asm_files.length; i += 1) {
    794                     codegen_add_assembly(g, buf_create_from_str(asm_files.at(i)));
    795                 }
    796                 codegen_build(g);
    797                 codegen_link(g, out_file);
    798                 if (timing_info)
    799                     codegen_print_timing_report(g, stdout);
    800                 return EXIT_SUCCESS;
    801             } else if (cmd == CmdParseC) {
    802                 codegen_parsec(g, in_file_buf);
    803                 ast_render(g, stdout, g->root_import->root, 4);
    804                 if (timing_info)
    805                     codegen_print_timing_report(g, stdout);
    806                 return EXIT_SUCCESS;
    807             } else if (cmd == CmdTest) {
    808                 ZigTarget native;
    809                 get_native_target(&native);
    810 
    811                 ZigTarget *non_null_target = target ? target : &native;
    812 
    813                 Buf *test_exe_name = buf_sprintf("." OS_SEP "test%s", target_exe_file_ext(non_null_target));
    814 
    815                 for (size_t i = 0; i < test_exec_args.length; i += 1) {
    816                     if (test_exec_args.items[i] == nullptr) {
    817                         test_exec_args.items[i] = buf_ptr(test_exe_name);
    818                     }
    819                 }
    820 
    821                 codegen_build(g);
    822                 codegen_link(g, buf_ptr(test_exe_name));
    823 
    824                 if (!target_can_exec(&native, target)) {
    825                     fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
    826                             buf_ptr(test_exe_name));
    827                     return 0;
    828                 }
    829 
    830                 Termination term;
    831                 if (test_exec_args.length > 0) {
    832                     ZigList<const char *> rest_args = {0};
    833                     for (size_t i = 1; i < test_exec_args.length; i += 1) {
    834                         rest_args.append(test_exec_args.at(i));
    835                     }
    836                     os_spawn_process(test_exec_args.items[0], rest_args, &term);
    837                 } else {
    838                     ZigList<const char *> no_args = {0};
    839                     os_spawn_process(buf_ptr(test_exe_name), no_args, &term);
    840                 }
    841 
    842                 if (term.how != TerminationIdClean || term.code != 0) {
    843                     fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
    844                     fprintf(stderr, "%s\n", buf_ptr(test_exe_name));
    845                 } else if (timing_info) {
    846                     codegen_print_timing_report(g, stdout);
    847                 }
    848                 return (term.how == TerminationIdClean) ? term.code : -1;
    849             } else {
    850                 zig_unreachable();
    851             }
    852         }
    853     case CmdVersion:
    854         printf("%s\n", ZIG_VERSION_STRING);
    855         return EXIT_SUCCESS;
    856     case CmdZen:
    857         printf("%s\n", ZIG_ZEN);
    858         return EXIT_SUCCESS;
    859     case CmdTargets:
    860         return print_target_list(stdout);
    861     case CmdInvalid:
    862         return usage(arg0);
    863     }
    864 }