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 }