blob cfed6c3d (27454B) - Raw
1 const std = @import("std"); 2 const mem = std.mem; 3 const io = std.io; 4 const os = std.os; 5 const heap = std.heap; 6 const warn = std.debug.warn; 7 const assert = std.debug.assert; 8 const target = @import("target.zig"); 9 const Target = target.Target; 10 const Module = @import("module.zig").Module; 11 const ErrColor = Module.ErrColor; 12 const Emit = Module.Emit; 13 const builtin = @import("builtin"); 14 const ArrayList = std.ArrayList; 15 const c = @import("c.zig"); 16 17 const default_zig_cache_name = "zig-cache"; 18 19 const Cmd = enum { 20 None, 21 Build, 22 Test, 23 Version, 24 Zen, 25 TranslateC, 26 Targets, 27 }; 28 29 fn badArgs(comptime format: []const u8, args: ...) noreturn { 30 var stderr = io.getStdErr() catch std.os.exit(1); 31 var stderr_stream_adapter = io.FileOutStream.init(&stderr); 32 const stderr_stream = &stderr_stream_adapter.stream; 33 stderr_stream.print(format ++ "\n\n", args) catch std.os.exit(1); 34 printUsage(&stderr_stream_adapter.stream) catch std.os.exit(1); 35 std.os.exit(1); 36 } 37 38 pub fn main() !void { 39 const allocator = std.heap.c_allocator; 40 41 const args = try os.argsAlloc(allocator); 42 defer os.argsFree(allocator, args); 43 44 if (args.len >= 2 and mem.eql(u8, args[1], "fmt")) { 45 return fmtMain(allocator, args[2..]); 46 } 47 48 var cmd = Cmd.None; 49 var build_kind: Module.Kind = undefined; 50 var build_mode: builtin.Mode = builtin.Mode.Debug; 51 var color = ErrColor.Auto; 52 var emit_file_type = Emit.Binary; 53 54 var strip = false; 55 var is_static = false; 56 var verbose_tokenize = false; 57 var verbose_ast_tree = false; 58 var verbose_ast_fmt = false; 59 var verbose_link = false; 60 var verbose_ir = false; 61 var verbose_llvm_ir = false; 62 var verbose_cimport = false; 63 var mwindows = false; 64 var mconsole = false; 65 var rdynamic = false; 66 var each_lib_rpath = false; 67 var timing_info = false; 68 69 var in_file_arg: ?[]u8 = null; 70 var out_file: ?[]u8 = null; 71 var out_file_h: ?[]u8 = null; 72 var out_name_arg: ?[]u8 = null; 73 var libc_lib_dir_arg: ?[]u8 = null; 74 var libc_static_lib_dir_arg: ?[]u8 = null; 75 var libc_include_dir_arg: ?[]u8 = null; 76 var msvc_lib_dir_arg: ?[]u8 = null; 77 var kernel32_lib_dir_arg: ?[]u8 = null; 78 var zig_install_prefix: ?[]u8 = null; 79 var dynamic_linker_arg: ?[]u8 = null; 80 var cache_dir_arg: ?[]const u8 = null; 81 var target_arch: ?[]u8 = null; 82 var target_os: ?[]u8 = null; 83 var target_environ: ?[]u8 = null; 84 var mmacosx_version_min: ?[]u8 = null; 85 var mios_version_min: ?[]u8 = null; 86 var linker_script_arg: ?[]u8 = null; 87 var test_name_prefix_arg: ?[]u8 = null; 88 89 var test_filters = ArrayList([]const u8).init(allocator); 90 defer test_filters.deinit(); 91 92 var lib_dirs = ArrayList([]const u8).init(allocator); 93 defer lib_dirs.deinit(); 94 95 var clang_argv = ArrayList([]const u8).init(allocator); 96 defer clang_argv.deinit(); 97 98 var llvm_argv = ArrayList([]const u8).init(allocator); 99 defer llvm_argv.deinit(); 100 101 var link_libs = ArrayList([]const u8).init(allocator); 102 defer link_libs.deinit(); 103 104 var frameworks = ArrayList([]const u8).init(allocator); 105 defer frameworks.deinit(); 106 107 var objects = ArrayList([]const u8).init(allocator); 108 defer objects.deinit(); 109 110 var asm_files = ArrayList([]const u8).init(allocator); 111 defer asm_files.deinit(); 112 113 var rpath_list = ArrayList([]const u8).init(allocator); 114 defer rpath_list.deinit(); 115 116 var ver_major: u32 = 0; 117 var ver_minor: u32 = 0; 118 var ver_patch: u32 = 0; 119 120 var arg_i: usize = 1; 121 while (arg_i < args.len) : (arg_i += 1) { 122 const arg = args[arg_i]; 123 124 if (arg.len != 0 and arg[0] == '-') { 125 if (mem.eql(u8, arg, "--release-fast")) { 126 build_mode = builtin.Mode.ReleaseFast; 127 } else if (mem.eql(u8, arg, "--release-safe")) { 128 build_mode = builtin.Mode.ReleaseSafe; 129 } else if (mem.eql(u8, arg, "--strip")) { 130 strip = true; 131 } else if (mem.eql(u8, arg, "--static")) { 132 is_static = true; 133 } else if (mem.eql(u8, arg, "--verbose-tokenize")) { 134 verbose_tokenize = true; 135 } else if (mem.eql(u8, arg, "--verbose-ast-tree")) { 136 verbose_ast_tree = true; 137 } else if (mem.eql(u8, arg, "--verbose-ast-fmt")) { 138 verbose_ast_fmt = true; 139 } else if (mem.eql(u8, arg, "--verbose-link")) { 140 verbose_link = true; 141 } else if (mem.eql(u8, arg, "--verbose-ir")) { 142 verbose_ir = true; 143 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { 144 verbose_llvm_ir = true; 145 } else if (mem.eql(u8, arg, "--verbose-cimport")) { 146 verbose_cimport = true; 147 } else if (mem.eql(u8, arg, "-mwindows")) { 148 mwindows = true; 149 } else if (mem.eql(u8, arg, "-mconsole")) { 150 mconsole = true; 151 } else if (mem.eql(u8, arg, "-rdynamic")) { 152 rdynamic = true; 153 } else if (mem.eql(u8, arg, "--each-lib-rpath")) { 154 each_lib_rpath = true; 155 } else if (mem.eql(u8, arg, "--enable-timing-info")) { 156 timing_info = true; 157 } else if (mem.eql(u8, arg, "--test-cmd-bin")) { 158 @panic("TODO --test-cmd-bin"); 159 } else if (arg[1] == 'L' and arg.len > 2) { 160 // alias for --library-path 161 try lib_dirs.append(arg[1..]); 162 } else if (mem.eql(u8, arg, "--pkg-begin")) { 163 @panic("TODO --pkg-begin"); 164 } else if (mem.eql(u8, arg, "--pkg-end")) { 165 @panic("TODO --pkg-end"); 166 } else if (arg_i + 1 >= args.len) { 167 badArgs("expected another argument after {}", arg); 168 } else { 169 arg_i += 1; 170 if (mem.eql(u8, arg, "--output")) { 171 out_file = args[arg_i]; 172 } else if (mem.eql(u8, arg, "--output-h")) { 173 out_file_h = args[arg_i]; 174 } else if (mem.eql(u8, arg, "--color")) { 175 if (mem.eql(u8, args[arg_i], "auto")) { 176 color = ErrColor.Auto; 177 } else if (mem.eql(u8, args[arg_i], "on")) { 178 color = ErrColor.On; 179 } else if (mem.eql(u8, args[arg_i], "off")) { 180 color = ErrColor.Off; 181 } else { 182 badArgs("--color options are 'auto', 'on', or 'off'"); 183 } 184 } else if (mem.eql(u8, arg, "--emit")) { 185 if (mem.eql(u8, args[arg_i], "asm")) { 186 emit_file_type = Emit.Assembly; 187 } else if (mem.eql(u8, args[arg_i], "bin")) { 188 emit_file_type = Emit.Binary; 189 } else if (mem.eql(u8, args[arg_i], "llvm-ir")) { 190 emit_file_type = Emit.LlvmIr; 191 } else { 192 badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'"); 193 } 194 } else if (mem.eql(u8, arg, "--name")) { 195 out_name_arg = args[arg_i]; 196 } else if (mem.eql(u8, arg, "--libc-lib-dir")) { 197 libc_lib_dir_arg = args[arg_i]; 198 } else if (mem.eql(u8, arg, "--libc-static-lib-dir")) { 199 libc_static_lib_dir_arg = args[arg_i]; 200 } else if (mem.eql(u8, arg, "--libc-include-dir")) { 201 libc_include_dir_arg = args[arg_i]; 202 } else if (mem.eql(u8, arg, "--msvc-lib-dir")) { 203 msvc_lib_dir_arg = args[arg_i]; 204 } else if (mem.eql(u8, arg, "--kernel32-lib-dir")) { 205 kernel32_lib_dir_arg = args[arg_i]; 206 } else if (mem.eql(u8, arg, "--zig-install-prefix")) { 207 zig_install_prefix = args[arg_i]; 208 } else if (mem.eql(u8, arg, "--dynamic-linker")) { 209 dynamic_linker_arg = args[arg_i]; 210 } else if (mem.eql(u8, arg, "-isystem")) { 211 try clang_argv.append("-isystem"); 212 try clang_argv.append(args[arg_i]); 213 } else if (mem.eql(u8, arg, "-dirafter")) { 214 try clang_argv.append("-dirafter"); 215 try clang_argv.append(args[arg_i]); 216 } else if (mem.eql(u8, arg, "-mllvm")) { 217 try clang_argv.append("-mllvm"); 218 try clang_argv.append(args[arg_i]); 219 220 try llvm_argv.append(args[arg_i]); 221 } else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) { 222 try lib_dirs.append(args[arg_i]); 223 } else if (mem.eql(u8, arg, "--library")) { 224 try link_libs.append(args[arg_i]); 225 } else if (mem.eql(u8, arg, "--object")) { 226 try objects.append(args[arg_i]); 227 } else if (mem.eql(u8, arg, "--assembly")) { 228 try asm_files.append(args[arg_i]); 229 } else if (mem.eql(u8, arg, "--cache-dir")) { 230 cache_dir_arg = args[arg_i]; 231 } else if (mem.eql(u8, arg, "--target-arch")) { 232 target_arch = args[arg_i]; 233 } else if (mem.eql(u8, arg, "--target-os")) { 234 target_os = args[arg_i]; 235 } else if (mem.eql(u8, arg, "--target-environ")) { 236 target_environ = args[arg_i]; 237 } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { 238 mmacosx_version_min = args[arg_i]; 239 } else if (mem.eql(u8, arg, "-mios-version-min")) { 240 mios_version_min = args[arg_i]; 241 } else if (mem.eql(u8, arg, "-framework")) { 242 try frameworks.append(args[arg_i]); 243 } else if (mem.eql(u8, arg, "--linker-script")) { 244 linker_script_arg = args[arg_i]; 245 } else if (mem.eql(u8, arg, "-rpath")) { 246 try rpath_list.append(args[arg_i]); 247 } else if (mem.eql(u8, arg, "--test-filter")) { 248 try test_filters.append(args[arg_i]); 249 } else if (mem.eql(u8, arg, "--test-name-prefix")) { 250 test_name_prefix_arg = args[arg_i]; 251 } else if (mem.eql(u8, arg, "--ver-major")) { 252 ver_major = try std.fmt.parseUnsigned(u32, args[arg_i], 10); 253 } else if (mem.eql(u8, arg, "--ver-minor")) { 254 ver_minor = try std.fmt.parseUnsigned(u32, args[arg_i], 10); 255 } else if (mem.eql(u8, arg, "--ver-patch")) { 256 ver_patch = try std.fmt.parseUnsigned(u32, args[arg_i], 10); 257 } else if (mem.eql(u8, arg, "--test-cmd")) { 258 @panic("TODO --test-cmd"); 259 } else { 260 badArgs("invalid argument: {}", arg); 261 } 262 } 263 } else if (cmd == Cmd.None) { 264 if (mem.eql(u8, arg, "build-obj")) { 265 cmd = Cmd.Build; 266 build_kind = Module.Kind.Obj; 267 } else if (mem.eql(u8, arg, "build-exe")) { 268 cmd = Cmd.Build; 269 build_kind = Module.Kind.Exe; 270 } else if (mem.eql(u8, arg, "build-lib")) { 271 cmd = Cmd.Build; 272 build_kind = Module.Kind.Lib; 273 } else if (mem.eql(u8, arg, "version")) { 274 cmd = Cmd.Version; 275 } else if (mem.eql(u8, arg, "zen")) { 276 cmd = Cmd.Zen; 277 } else if (mem.eql(u8, arg, "translate-c")) { 278 cmd = Cmd.TranslateC; 279 } else if (mem.eql(u8, arg, "test")) { 280 cmd = Cmd.Test; 281 build_kind = Module.Kind.Exe; 282 } else { 283 badArgs("unrecognized command: {}", arg); 284 } 285 } else switch (cmd) { 286 Cmd.Build, Cmd.TranslateC, Cmd.Test => { 287 if (in_file_arg == null) { 288 in_file_arg = arg; 289 } else { 290 badArgs("unexpected extra parameter: {}", arg); 291 } 292 }, 293 Cmd.Version, Cmd.Zen, Cmd.Targets => { 294 badArgs("unexpected extra parameter: {}", arg); 295 }, 296 Cmd.None => unreachable, 297 } 298 } 299 300 target.initializeAll(); 301 302 // TODO 303 // ZigTarget alloc_target; 304 // ZigTarget *target; 305 // if (!target_arch && !target_os && !target_environ) { 306 // target = nullptr; 307 // } else { 308 // target = &alloc_target; 309 // get_unknown_target(target); 310 // if (target_arch) { 311 // if (parse_target_arch(target_arch, &target->arch)) { 312 // fprintf(stderr, "invalid --target-arch argument\n"); 313 // return usage(arg0); 314 // } 315 // } 316 // if (target_os) { 317 // if (parse_target_os(target_os, &target->os)) { 318 // fprintf(stderr, "invalid --target-os argument\n"); 319 // return usage(arg0); 320 // } 321 // } 322 // if (target_environ) { 323 // if (parse_target_environ(target_environ, &target->env_type)) { 324 // fprintf(stderr, "invalid --target-environ argument\n"); 325 // return usage(arg0); 326 // } 327 // } 328 // } 329 330 switch (cmd) { 331 Cmd.None => badArgs("expected command"), 332 Cmd.Zen => return printZen(), 333 Cmd.Build, Cmd.Test, Cmd.TranslateC => { 334 if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) { 335 badArgs("expected source file argument or at least one --object or --assembly argument"); 336 } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) { 337 badArgs("expected source file argument"); 338 } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) { 339 badArgs("When building an object file, --object arguments are invalid"); 340 } 341 342 const root_name = switch (cmd) { 343 Cmd.Build, Cmd.TranslateC => x: { 344 if (out_name_arg) |out_name| { 345 break :x out_name; 346 } else if (in_file_arg) |in_file_path| { 347 const basename = os.path.basename(in_file_path); 348 var it = mem.split(basename, "."); 349 break :x it.next() ?? badArgs("file name cannot be empty"); 350 } else { 351 badArgs("--name [name] not provided and unable to infer"); 352 } 353 }, 354 Cmd.Test => "test", 355 else => unreachable, 356 }; 357 358 const zig_root_source_file = if (cmd == Cmd.TranslateC) null else in_file_arg; 359 360 const chosen_cache_dir = cache_dir_arg ?? default_zig_cache_name; 361 const full_cache_dir = try os.path.resolve(allocator, ".", chosen_cache_dir); 362 defer allocator.free(full_cache_dir); 363 364 const zig_lib_dir = try resolveZigLibDir(allocator, zig_install_prefix); 365 errdefer allocator.free(zig_lib_dir); 366 367 const module = try Module.create(allocator, root_name, zig_root_source_file, 368 Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir); 369 defer module.destroy(); 370 371 module.version_major = ver_major; 372 module.version_minor = ver_minor; 373 module.version_patch = ver_patch; 374 375 module.is_test = cmd == Cmd.Test; 376 if (linker_script_arg) |linker_script| { 377 module.linker_script = linker_script; 378 } 379 module.each_lib_rpath = each_lib_rpath; 380 module.clang_argv = clang_argv.toSliceConst(); 381 module.llvm_argv = llvm_argv.toSliceConst(); 382 module.strip = strip; 383 module.is_static = is_static; 384 385 if (libc_lib_dir_arg) |libc_lib_dir| { 386 module.libc_lib_dir = libc_lib_dir; 387 } 388 if (libc_static_lib_dir_arg) |libc_static_lib_dir| { 389 module.libc_static_lib_dir = libc_static_lib_dir; 390 } 391 if (libc_include_dir_arg) |libc_include_dir| { 392 module.libc_include_dir = libc_include_dir; 393 } 394 if (msvc_lib_dir_arg) |msvc_lib_dir| { 395 module.msvc_lib_dir = msvc_lib_dir; 396 } 397 if (kernel32_lib_dir_arg) |kernel32_lib_dir| { 398 module.kernel32_lib_dir = kernel32_lib_dir; 399 } 400 if (dynamic_linker_arg) |dynamic_linker| { 401 module.dynamic_linker = dynamic_linker; 402 } 403 module.verbose_tokenize = verbose_tokenize; 404 module.verbose_ast_tree = verbose_ast_tree; 405 module.verbose_ast_fmt = verbose_ast_fmt; 406 module.verbose_link = verbose_link; 407 module.verbose_ir = verbose_ir; 408 module.verbose_llvm_ir = verbose_llvm_ir; 409 module.verbose_cimport = verbose_cimport; 410 411 module.err_color = color; 412 413 module.lib_dirs = lib_dirs.toSliceConst(); 414 module.darwin_frameworks = frameworks.toSliceConst(); 415 module.rpath_list = rpath_list.toSliceConst(); 416 417 for (link_libs.toSliceConst()) |name| { 418 _ = try module.addLinkLib(name, true); 419 } 420 421 module.windows_subsystem_windows = mwindows; 422 module.windows_subsystem_console = mconsole; 423 module.linker_rdynamic = rdynamic; 424 425 if (mmacosx_version_min != null and mios_version_min != null) { 426 badArgs("-mmacosx-version-min and -mios-version-min options not allowed together"); 427 } 428 429 if (mmacosx_version_min) |ver| { 430 module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver }; 431 } else if (mios_version_min) |ver| { 432 module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver }; 433 } 434 435 module.test_filters = test_filters.toSliceConst(); 436 module.test_name_prefix = test_name_prefix_arg; 437 module.out_h_path = out_file_h; 438 439 // TODO 440 //add_package(g, cur_pkg, g->root_package); 441 442 switch (cmd) { 443 Cmd.Build => { 444 module.emit_file_type = emit_file_type; 445 446 module.link_objects = objects.toSliceConst(); 447 module.assembly_files = asm_files.toSliceConst(); 448 449 try module.build(); 450 try module.link(out_file); 451 }, 452 Cmd.TranslateC => @panic("TODO translate-c"), 453 Cmd.Test => @panic("TODO test cmd"), 454 else => unreachable, 455 } 456 }, 457 Cmd.Version => { 458 var stdout_file = try io.getStdErr(); 459 try stdout_file.write(std.cstr.toSliceConst(c.ZIG_VERSION_STRING)); 460 try stdout_file.write("\n"); 461 }, 462 Cmd.Targets => @panic("TODO zig targets"), 463 } 464 } 465 466 fn printUsage(stream: var) !void { 467 try stream.write( 468 \\Usage: zig [command] [options] 469 \\ 470 \\Commands: 471 \\ build build project from build.zig 472 \\ build-exe [source] create executable from source or object files 473 \\ build-lib [source] create library from source or object files 474 \\ build-obj [source] create object from source or assembly 475 \\ fmt [file] parse file and render in canonical zig format 476 \\ translate-c [source] convert c code to zig code 477 \\ targets list available compilation targets 478 \\ test [source] create and run a test build 479 \\ version print version number and exit 480 \\ zen print zen of zig and exit 481 \\Compile Options: 482 \\ --assembly [source] add assembly file to build 483 \\ --cache-dir [path] override the cache directory 484 \\ --color [auto|off|on] enable or disable colored error messages 485 \\ --emit [filetype] emit a specific file format as compilation output 486 \\ --enable-timing-info print timing diagnostics 487 \\ --libc-include-dir [path] directory where libc stdlib.h resides 488 \\ --name [name] override output name 489 \\ --output [file] override destination path 490 \\ --output-h [file] override generated header file path 491 \\ --pkg-begin [name] [path] make package available to import and push current pkg 492 \\ --pkg-end pop current pkg 493 \\ --release-fast build with optimizations on and safety off 494 \\ --release-safe build with optimizations on and safety on 495 \\ --static output will be statically linked 496 \\ --strip exclude debug symbols 497 \\ --target-arch [name] specify target architecture 498 \\ --target-environ [name] specify target environment 499 \\ --target-os [name] specify target operating system 500 \\ --verbose-tokenize enable compiler debug info: tokenization 501 \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview) 502 \\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source) 503 \\ --verbose-cimport enable compiler debug info: C imports 504 \\ --verbose-ir enable compiler debug info: Zig IR 505 \\ --verbose-llvm-ir enable compiler debug info: LLVM IR 506 \\ --verbose-link enable compiler debug info: linking 507 \\ --zig-install-prefix [path] override directory where zig thinks it is installed 508 \\ -dirafter [dir] same as -isystem but do it last 509 \\ -isystem [dir] add additional search path for other .h files 510 \\ -mllvm [arg] additional arguments to forward to LLVM's option processing 511 \\Link Options: 512 \\ --ar-path [path] set the path to ar 513 \\ --dynamic-linker [path] set the path to ld.so 514 \\ --each-lib-rpath add rpath for each used dynamic library 515 \\ --libc-lib-dir [path] directory where libc crt1.o resides 516 \\ --libc-static-lib-dir [path] directory where libc crtbegin.o resides 517 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides 518 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides 519 \\ --library [lib] link against lib 520 \\ --library-path [dir] add a directory to the library search path 521 \\ --linker-script [path] use a custom linker script 522 \\ --object [obj] add object file to build 523 \\ -L[dir] alias for --library-path 524 \\ -rdynamic add all symbols to the dynamic symbol table 525 \\ -rpath [path] add directory to the runtime library search path 526 \\ -mconsole (windows) --subsystem console to the linker 527 \\ -mwindows (windows) --subsystem windows to the linker 528 \\ -framework [name] (darwin) link against framework 529 \\ -mios-version-min [ver] (darwin) set iOS deployment target 530 \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target 531 \\ --ver-major [ver] dynamic library semver major version 532 \\ --ver-minor [ver] dynamic library semver minor version 533 \\ --ver-patch [ver] dynamic library semver patch version 534 \\Test Options: 535 \\ --test-filter [text] skip tests that do not match filter 536 \\ --test-name-prefix [text] add prefix to all tests 537 \\ --test-cmd [arg] specify test execution command one arg at a time 538 \\ --test-cmd-bin appends test binary path to test cmd args 539 \\ 540 ); 541 } 542 543 fn printZen() !void { 544 var stdout_file = try io.getStdErr(); 545 try stdout_file.write( 546 \\ 547 \\ * Communicate intent precisely. 548 \\ * Edge cases matter. 549 \\ * Favor reading code over writing code. 550 \\ * Only one obvious way to do things. 551 \\ * Runtime crashes are better than bugs. 552 \\ * Compile errors are better than runtime crashes. 553 \\ * Incremental improvements. 554 \\ * Avoid local maximums. 555 \\ * Reduce the amount one must remember. 556 \\ * Minimize energy spent on coding style. 557 \\ * Together we serve end users. 558 \\ 559 \\ 560 ); 561 } 562 563 fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void { 564 for (file_paths) |file_path| { 565 var file = try io.File.openRead(allocator, file_path); 566 defer file.close(); 567 568 warn("opened {} (todo tokenize and parse and render)\n", file_path); 569 } 570 } 571 572 /// Caller must free result 573 fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) ![]u8 { 574 if (zig_install_prefix_arg) |zig_install_prefix| { 575 return testZigInstallPrefix(allocator, zig_install_prefix) catch |err| { 576 warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err)); 577 return error.ZigInstallationNotFound; 578 }; 579 } else { 580 return findZigLibDir(allocator) catch |err| { 581 warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n", 582 @errorName(err)); 583 return error.ZigLibDirNotFound; 584 }; 585 } 586 } 587 588 /// Caller must free result 589 fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) ![]u8 { 590 const test_zig_dir = try os.path.join(allocator, test_path, "lib", "zig"); 591 errdefer allocator.free(test_zig_dir); 592 593 const test_index_file = try os.path.join(allocator, test_zig_dir, "std", "index.zig"); 594 defer allocator.free(test_index_file); 595 596 var file = try io.File.openRead(allocator, test_index_file); 597 file.close(); 598 599 return test_zig_dir; 600 } 601 602 /// Caller must free result 603 fn findZigLibDir(allocator: &mem.Allocator) ![]u8 { 604 const self_exe_path = try os.selfExeDirPath(allocator); 605 defer allocator.free(self_exe_path); 606 607 var cur_path: []const u8 = self_exe_path; 608 while (true) { 609 const test_dir = os.path.dirname(cur_path); 610 611 if (mem.eql(u8, test_dir, cur_path)) { 612 break; 613 } 614 615 return testZigInstallPrefix(allocator, test_dir) catch |err| { 616 cur_path = test_dir; 617 continue; 618 }; 619 } 620 621 // TODO look in hard coded installation path from configuration 622 //if (ZIG_INSTALL_PREFIX != nullptr) { 623 // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) { 624 // return 0; 625 // } 626 //} 627 628 return error.FileNotFound; 629 }