From 39c7bd24e4f768b23074b8634ac637b175b7639f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Dec 2017 00:29:39 -0500 Subject: [PATCH] port most of main.cpp to self hosted compiler --- README.md | 53 ++-- build.zig | 145 ++++++++- src-self-hosted/llvm.zig | 13 + src-self-hosted/main.zig | 623 ++++++++++++++++++++++++++++++++++--- src-self-hosted/module.zig | 295 ++++++++++++++++++ src-self-hosted/target.zig | 51 +++ std/buffer.zig | 5 + std/c/index.zig | 1 + std/heap.zig | 15 +- std/os/index.zig | 33 ++ 10 files changed, 1156 insertions(+), 78 deletions(-) create mode 100644 src-self-hosted/llvm.zig create mode 100644 src-self-hosted/module.zig diff --git a/README.md b/README.md index 42783fab85..987197289c 100644 --- a/README.md +++ b/README.md @@ -119,31 +119,22 @@ libc. Create demo games using Zig. [![Build Status](https://travis-ci.org/zig-lang/zig.svg?branch=master)](https://travis-ci.org/zig-lang/zig) [![Build status](https://ci.appveyor.com/api/projects/status/4t80mk2dmucrc38i/branch/master?svg=true)](https://ci.appveyor.com/project/andrewrk/zig-d3l86/branch/master) -### Dependencies +### Stage 1: Build Zig from C++ Source Code -#### Build Dependencies - -These compile tools must be available on your system and are used to build -the Zig compiler itself: +#### Dependencies ##### POSIX * gcc >= 5.0.0 or clang >= 3.6.0 * cmake >= 2.8.5 + * LLVM, Clang, LLD libraries == 5.x, compiled with the same gcc or clang version above ##### Windows * Microsoft Visual Studio 2015 + * LLVM, Clang, LLD libraries == 5.x, compiled with the same MSVC version above -#### Library Dependencies - -These libraries must be installed on your system, with the development files -available. The Zig compiler links against them. You have to use the same -compiler for these libraries as you do to compile Zig. - - * LLVM, Clang, and LLD libraries == 5.x - -### Debug / Development Build +#### Instructions If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`, `ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to @@ -158,7 +149,7 @@ make install ./zig build --build-file ../build.zig test ``` -#### MacOS +##### MacOS `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused. @@ -172,21 +163,35 @@ make install ./zig build --build-file ../build.zig test ``` -#### Windows +##### Windows See https://github.com/zig-lang/zig/wiki/Building-Zig-on-Windows -### Release / Install Build +### Stage 2: Build Self-Hosted Zig from Zig Source Code -Once installed, `ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_INCLUDE_DIR` can be overridden -by the `--libc-lib-dir` and `--libc-include-dir` parameters to the zig binary. +*Note: Stage 2 compiler is not complete. Beta users of Zig should use the +Stage 1 compiler for now.* + +Dependencies are the same as Stage 1, except now you have a working zig compiler. ``` -mkdir build -cd build -cmake .. -DCMAKE_BUILD_TYPE=Release -DZIG_LIBC_LIB_DIR=/some/path -DZIG_LIBC_INCLUDE_DIR=/some/path -DZIG_LIBC_STATIC_INCLUDE_DIR=/some/path -make -sudo make install +bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install +``` + +### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler + +This is the actual compiler binary that we will install to the system. + +#### Debug / Development Build + +``` +./stage2/bin/zig build --build-file ../build.zig --prefix $(pwd)/stage3 install +``` + +#### Release / Install Build + +``` +./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast ``` ### Test Coverage diff --git a/build.zig b/build.zig index 45953cc4af..96638659be 100644 --- a/build.zig +++ b/build.zig @@ -32,15 +32,18 @@ pub fn build(b: &Builder) { docs_step.dependOn(&docgen_cmd.step); docs_step.dependOn(&docgen_home_cmd.step); - var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); - exe.setBuildMode(mode); - exe.linkSystemLibrary("c"); - dependOnLib(exe, findLLVM(b)); + if (findLLVM(b)) |llvm| { + var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); + exe.setBuildMode(mode); + exe.linkSystemLibrary("c"); + dependOnLib(exe, llvm); - b.default_step.dependOn(&exe.step); - b.default_step.dependOn(docs_step); + b.default_step.dependOn(&exe.step); + b.default_step.dependOn(docs_step); - b.installArtifact(exe); + b.installArtifact(exe); + installStdLib(b); + } const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); @@ -91,7 +94,7 @@ const LibraryDep = struct { includes: ArrayList([]const u8), }; -fn findLLVM(b: &Builder) -> LibraryDep { +fn findLLVM(b: &Builder) -> ?LibraryDep { const llvm_config_exe = b.findProgram( [][]const u8{"llvm-config-5.0", "llvm-config"}, [][]const u8{ @@ -102,7 +105,8 @@ fn findLLVM(b: &Builder) -> LibraryDep { "C:/Libraries/llvm-5.0.0/bin", }) %% |err| { - std.debug.panic("unable to find llvm-config: {}\n", err); + warn("unable to find llvm-config: {}\n", err); + return null; }; const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"}); const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"}); @@ -143,3 +147,126 @@ fn findLLVM(b: &Builder) -> LibraryDep { } return result; } + +pub fn installStdLib(b: &Builder) { + const stdlib_files = []const []const u8 { + "array_list.zig", + "base64.zig", + "buf_map.zig", + "buf_set.zig", + "buffer.zig", + "build.zig", + "c/darwin.zig", + "c/index.zig", + "c/linux.zig", + "c/windows.zig", + "cstr.zig", + "debug.zig", + "dwarf.zig", + "elf.zig", + "empty.zig", + "endian.zig", + "fmt/errol/enum3.zig", + "fmt/errol/index.zig", + "fmt/errol/lookup.zig", + "fmt/index.zig", + "hash_map.zig", + "heap.zig", + "index.zig", + "io.zig", + "linked_list.zig", + "math/acos.zig", + "math/acosh.zig", + "math/asin.zig", + "math/asinh.zig", + "math/atan.zig", + "math/atan2.zig", + "math/atanh.zig", + "math/cbrt.zig", + "math/ceil.zig", + "math/copysign.zig", + "math/cos.zig", + "math/cosh.zig", + "math/exp.zig", + "math/exp2.zig", + "math/expm1.zig", + "math/expo2.zig", + "math/fabs.zig", + "math/floor.zig", + "math/fma.zig", + "math/frexp.zig", + "math/hypot.zig", + "math/ilogb.zig", + "math/index.zig", + "math/inf.zig", + "math/isfinite.zig", + "math/isinf.zig", + "math/isnan.zig", + "math/isnormal.zig", + "math/ln.zig", + "math/log.zig", + "math/log10.zig", + "math/log1p.zig", + "math/log2.zig", + "math/modf.zig", + "math/nan.zig", + "math/pow.zig", + "math/round.zig", + "math/scalbn.zig", + "math/signbit.zig", + "math/sin.zig", + "math/sinh.zig", + "math/sqrt.zig", + "math/tan.zig", + "math/tanh.zig", + "math/trunc.zig", + "mem.zig", + "net.zig", + "os/child_process.zig", + "os/darwin.zig", + "os/darwin_errno.zig", + "os/get_user_id.zig", + "os/index.zig", + "os/linux.zig", + "os/linux_errno.zig", + "os/linux_i386.zig", + "os/linux_x86_64.zig", + "os/path.zig", + "os/windows/error.zig", + "os/windows/index.zig", + "os/windows/util.zig", + "rand.zig", + "sort.zig", + "special/bootstrap.zig", + "special/bootstrap_lib.zig", + "special/build_file_template.zig", + "special/build_runner.zig", + "special/builtin.zig", + "special/compiler_rt/aulldiv.zig", + "special/compiler_rt/aullrem.zig", + "special/compiler_rt/comparetf2.zig", + "special/compiler_rt/fixuint.zig", + "special/compiler_rt/fixunsdfdi.zig", + "special/compiler_rt/fixunsdfsi.zig", + "special/compiler_rt/fixunsdfti.zig", + "special/compiler_rt/fixunssfdi.zig", + "special/compiler_rt/fixunssfsi.zig", + "special/compiler_rt/fixunssfti.zig", + "special/compiler_rt/fixunstfdi.zig", + "special/compiler_rt/fixunstfsi.zig", + "special/compiler_rt/fixunstfti.zig", + "special/compiler_rt/index.zig", + "special/compiler_rt/udivmod.zig", + "special/compiler_rt/udivmoddi4.zig", + "special/compiler_rt/udivmodti4.zig", + "special/compiler_rt/udivti3.zig", + "special/compiler_rt/umodti3.zig", + "special/panic.zig", + "special/test_runner.zig", + }; + for (stdlib_files) |stdlib_file| { + const src_path = %%os.path.join(b.allocator, "std", stdlib_file); + const dest_path = %%os.path.join(b.allocator, "lib", "zig", "std", stdlib_file); + b.installFile(src_path, dest_path); + } +} diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig new file mode 100644 index 0000000000..6a1439291b --- /dev/null +++ b/src-self-hosted/llvm.zig @@ -0,0 +1,13 @@ +const builtin = @import("builtin"); +const c = @import("c.zig"); +const assert = @import("std").debug.assert; + +pub const ValueRef = removeNullability(c.LLVMValueRef); +pub const ModuleRef = removeNullability(c.LLVMModuleRef); +pub const ContextRef = removeNullability(c.LLVMContextRef); +pub const BuilderRef = removeNullability(c.LLVMBuilderRef); + +fn removeNullability(comptime T: type) -> type { + comptime assert(@typeId(T) == builtin.TypeId.Nullable); + return T.Child; +} diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 6c40d2216f..6fdacda4b2 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -4,71 +4,620 @@ const io = std.io; const os = std.os; const heap = std.heap; const warn = std.debug.warn; -const Tokenizer = @import("tokenizer.zig").Tokenizer; -const Token = @import("tokenizer.zig").Token; -const Parser = @import("parser.zig").Parser; const assert = std.debug.assert; const target = @import("target.zig"); +const Target = target.Target; +const Module = @import("module.zig").Module; +const ErrColor = Module.ErrColor; +const Emit = Module.Emit; +const builtin = @import("builtin"); +const ArrayList = std.ArrayList; + +error InvalidCommandLineArguments; +error ZigLibDirNotFound; +error ZigInstallationNotFound; + +const default_zig_cache_name = "zig-cache"; pub fn main() -> %void { main2() %% |err| { - warn("{}\n", @errorName(err)); + if (err != error.InvalidCommandLineArguments) { + warn("{}\n", @errorName(err)); + } return err; }; } -pub fn main2() -> %void { - var incrementing_allocator = %return heap.IncrementingAllocator.init(10 * 1024 * 1024); - defer incrementing_allocator.deinit(); +const Cmd = enum { + None, + Build, + Test, + Version, + Zen, + TranslateC, + Targets, +}; - const allocator = &incrementing_allocator.allocator; +fn badArgs(comptime format: []const u8, args: ...) -> error { + var stderr = %return io.getStdErr(); + var stderr_stream_adapter = io.FileOutStream.init(&stderr); + const stderr_stream = &stderr_stream_adapter.stream; + %return stderr_stream.print(format ++ "\n\n", args); + %return printUsage(&stderr_stream_adapter.stream); + return error.InvalidCommandLineArguments; +} + +pub fn main2() -> %void { + const allocator = std.heap.c_allocator; const args = %return os.argsAlloc(allocator); defer os.argsFree(allocator, args); - target.initializeAll(); + var cmd = Cmd.None; + var build_kind: Module.Kind = undefined; + var build_mode: builtin.Mode = builtin.Mode.Debug; + var color = ErrColor.Auto; + var emit_file_type = Emit.Binary; - const target_file = args[1]; + var strip = false; + var is_static = false; + var verbose_tokenize = false; + var verbose_ast_tree = false; + var verbose_ast_fmt = false; + var verbose_link = false; + var verbose_ir = false; + var verbose_llvm_ir = false; + var verbose_cimport = false; + var mwindows = false; + var mconsole = false; + var rdynamic = false; + var each_lib_rpath = false; + var timing_info = false; - const target_file_buf = %return io.readFileAlloc(target_file, allocator); - defer allocator.free(target_file_buf); + var in_file_arg: ?[]u8 = null; + var out_file: ?[]u8 = null; + var out_file_h: ?[]u8 = null; + var out_name_arg: ?[]u8 = null; + var libc_lib_dir_arg: ?[]u8 = null; + var libc_static_lib_dir_arg: ?[]u8 = null; + var libc_include_dir_arg: ?[]u8 = null; + var msvc_lib_dir_arg: ?[]u8 = null; + var kernel32_lib_dir_arg: ?[]u8 = null; + var zig_install_prefix: ?[]u8 = null; + var dynamic_linker_arg: ?[]u8 = null; + var cache_dir_arg: ?[]const u8 = null; + var target_arch: ?[]u8 = null; + var target_os: ?[]u8 = null; + var target_environ: ?[]u8 = null; + var mmacosx_version_min: ?[]u8 = null; + var mios_version_min: ?[]u8 = null; + var linker_script_arg: ?[]u8 = null; + var test_name_prefix_arg: ?[]u8 = null; - var stderr_file = %return std.io.getStdErr(); - var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); - const out_stream = &stderr_file_out_stream.stream; + var test_filters = ArrayList([]const u8).init(allocator); + defer test_filters.deinit(); - warn("====input:====\n"); + var lib_dirs = ArrayList([]const u8).init(allocator); + defer lib_dirs.deinit(); - warn("{}", target_file_buf); + var clang_argv = ArrayList([]const u8).init(allocator); + defer clang_argv.deinit(); - warn("====tokenization:====\n"); - { - var tokenizer = Tokenizer.init(target_file_buf); - while (true) { - const token = tokenizer.next(); - tokenizer.dump(token); - if (token.id == Token.Id.Eof) { - break; + var llvm_argv = ArrayList([]const u8).init(allocator); + defer llvm_argv.deinit(); + + var link_libs = ArrayList([]const u8).init(allocator); + defer link_libs.deinit(); + + var frameworks = ArrayList([]const u8).init(allocator); + defer frameworks.deinit(); + + var objects = ArrayList([]const u8).init(allocator); + defer objects.deinit(); + + var asm_files = ArrayList([]const u8).init(allocator); + defer asm_files.deinit(); + + var rpath_list = ArrayList([]const u8).init(allocator); + defer rpath_list.deinit(); + + var ver_major: u32 = 0; + var ver_minor: u32 = 0; + var ver_patch: u32 = 0; + + var arg_i: usize = 1; + while (arg_i < args.len) : (arg_i += 1) { + const arg = args[arg_i]; + + if (arg.len != 0 and arg[0] == '-') { + if (mem.eql(u8, arg, "--release-fast")) { + build_mode = builtin.Mode.ReleaseFast; + } else if (mem.eql(u8, arg, "--release-safe")) { + build_mode = builtin.Mode.ReleaseSafe; + } else if (mem.eql(u8, arg, "--strip")) { + strip = true; + } else if (mem.eql(u8, arg, "--static")) { + is_static = true; + } else if (mem.eql(u8, arg, "--verbose-tokenize")) { + verbose_tokenize = true; + } else if (mem.eql(u8, arg, "--verbose-ast-tree")) { + verbose_ast_tree = true; + } else if (mem.eql(u8, arg, "--verbose-ast-fmt")) { + verbose_ast_fmt = true; + } else if (mem.eql(u8, arg, "--verbose-link")) { + verbose_link = true; + } else if (mem.eql(u8, arg, "--verbose-ir")) { + verbose_ir = true; + } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { + verbose_llvm_ir = true; + } else if (mem.eql(u8, arg, "--verbose-cimport")) { + verbose_cimport = true; + } else if (mem.eql(u8, arg, "-mwindows")) { + mwindows = true; + } else if (mem.eql(u8, arg, "-mconsole")) { + mconsole = true; + } else if (mem.eql(u8, arg, "-rdynamic")) { + rdynamic = true; + } else if (mem.eql(u8, arg, "--each-lib-rpath")) { + each_lib_rpath = true; + } else if (mem.eql(u8, arg, "--enable-timing-info")) { + timing_info = true; + } else if (mem.eql(u8, arg, "--test-cmd-bin")) { + @panic("TODO --test-cmd-bin"); + } else if (arg[1] == 'L' and arg.len > 2) { + // alias for --library-path + %return lib_dirs.append(arg[1..]); + } else if (mem.eql(u8, arg, "--pkg-begin")) { + @panic("TODO --pkg-begin"); + } else if (mem.eql(u8, arg, "--pkg-end")) { + @panic("TODO --pkg-end"); + } else if (arg_i + 1 >= args.len) { + return badArgs("expected another argument after {}", arg); + } else { + arg_i += 1; + if (mem.eql(u8, arg, "--output")) { + out_file = args[arg_i]; + } else if (mem.eql(u8, arg, "--output-h")) { + out_file_h = args[arg_i]; + } else if (mem.eql(u8, arg, "--color")) { + if (mem.eql(u8, args[arg_i], "auto")) { + color = ErrColor.Auto; + } else if (mem.eql(u8, args[arg_i], "on")) { + color = ErrColor.On; + } else if (mem.eql(u8, args[arg_i], "off")) { + color = ErrColor.Off; + } else { + return badArgs("--color options are 'auto', 'on', or 'off'"); + } + } else if (mem.eql(u8, arg, "--emit")) { + if (mem.eql(u8, args[arg_i], "asm")) { + emit_file_type = Emit.Assembly; + } else if (mem.eql(u8, args[arg_i], "bin")) { + emit_file_type = Emit.Binary; + } else if (mem.eql(u8, args[arg_i], "llvm-ir")) { + emit_file_type = Emit.LlvmIr; + } else { + return badArgs("--emit options are 'asm', 'bin', or 'llvm-ir'"); + } + } else if (mem.eql(u8, arg, "--name")) { + out_name_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--libc-lib-dir")) { + libc_lib_dir_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--libc-static-lib-dir")) { + libc_static_lib_dir_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--libc-include-dir")) { + libc_include_dir_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--msvc-lib-dir")) { + msvc_lib_dir_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--kernel32-lib-dir")) { + kernel32_lib_dir_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--zig-install-prefix")) { + zig_install_prefix = args[arg_i]; + } else if (mem.eql(u8, arg, "--dynamic-linker")) { + dynamic_linker_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "-isystem")) { + %return clang_argv.append("-isystem"); + %return clang_argv.append(args[arg_i]); + } else if (mem.eql(u8, arg, "-dirafter")) { + %return clang_argv.append("-dirafter"); + %return clang_argv.append(args[arg_i]); + } else if (mem.eql(u8, arg, "-mllvm")) { + %return clang_argv.append("-mllvm"); + %return clang_argv.append(args[arg_i]); + + %return llvm_argv.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--library-path") or mem.eql(u8, arg, "-L")) { + %return lib_dirs.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--library")) { + %return link_libs.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--object")) { + %return objects.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--assembly")) { + %return asm_files.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--cache-dir")) { + cache_dir_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--target-arch")) { + target_arch = args[arg_i]; + } else if (mem.eql(u8, arg, "--target-os")) { + target_os = args[arg_i]; + } else if (mem.eql(u8, arg, "--target-environ")) { + target_environ = args[arg_i]; + } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { + mmacosx_version_min = args[arg_i]; + } else if (mem.eql(u8, arg, "-mios-version-min")) { + mios_version_min = args[arg_i]; + } else if (mem.eql(u8, arg, "-framework")) { + %return frameworks.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--linker-script")) { + linker_script_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "-rpath")) { + %return rpath_list.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--test-filter")) { + %return test_filters.append(args[arg_i]); + } else if (mem.eql(u8, arg, "--test-name-prefix")) { + test_name_prefix_arg = args[arg_i]; + } else if (mem.eql(u8, arg, "--ver-major")) { + ver_major = %return std.fmt.parseUnsigned(u32, args[arg_i], 10); + } else if (mem.eql(u8, arg, "--ver-minor")) { + ver_minor = %return std.fmt.parseUnsigned(u32, args[arg_i], 10); + } else if (mem.eql(u8, arg, "--ver-patch")) { + ver_patch = %return std.fmt.parseUnsigned(u32, args[arg_i], 10); + } else if (mem.eql(u8, arg, "--test-cmd")) { + @panic("TODO --test-cmd"); + } else { + return badArgs("invalid argument: {}", arg); + } } + } else if (cmd == Cmd.None) { + if (mem.eql(u8, arg, "build-obj")) { + cmd = Cmd.Build; + build_kind = Module.Kind.Obj; + } else if (mem.eql(u8, arg, "build-exe")) { + cmd = Cmd.Build; + build_kind = Module.Kind.Exe; + } else if (mem.eql(u8, arg, "build-lib")) { + cmd = Cmd.Build; + build_kind = Module.Kind.Lib; + } else if (mem.eql(u8, arg, "version")) { + cmd = Cmd.Version; + } else if (mem.eql(u8, arg, "zen")) { + cmd = Cmd.Zen; + } else if (mem.eql(u8, arg, "translate-c")) { + cmd = Cmd.TranslateC; + } else if (mem.eql(u8, arg, "test")) { + cmd = Cmd.Test; + build_kind = Module.Kind.Exe; + } else { + return badArgs("unrecognized command: {}", arg); + } + } else switch (cmd) { + Cmd.Build, Cmd.TranslateC, Cmd.Test => { + if (in_file_arg == null) { + in_file_arg = arg; + } else { + return badArgs("unexpected extra parameter: {}", arg); + } + }, + Cmd.Version, Cmd.Zen, Cmd.Targets => { + return badArgs("unexpected extra parameter: {}", arg); + }, + Cmd.None => unreachable, } } - warn("====parse:====\n"); + target.initializeAll(); - var tokenizer = Tokenizer.init(target_file_buf); - var parser = Parser.init(&tokenizer, allocator, target_file); - defer parser.deinit(); + // TODO +// ZigTarget alloc_target; +// ZigTarget *target; +// if (!target_arch && !target_os && !target_environ) { +// target = nullptr; +// } else { +// target = &alloc_target; +// get_unknown_target(target); +// if (target_arch) { +// if (parse_target_arch(target_arch, &target->arch)) { +// fprintf(stderr, "invalid --target-arch argument\n"); +// return usage(arg0); +// } +// } +// if (target_os) { +// if (parse_target_os(target_os, &target->os)) { +// fprintf(stderr, "invalid --target-os argument\n"); +// return usage(arg0); +// } +// } +// if (target_environ) { +// if (parse_target_environ(target_environ, &target->env_type)) { +// fprintf(stderr, "invalid --target-environ argument\n"); +// return usage(arg0); +// } +// } +// } - const root_node = %return parser.parse(); - defer parser.freeAst(root_node); + switch (cmd) { + Cmd.None => return badArgs("expected command"), + Cmd.Zen => return printZen(), + Cmd.Build, Cmd.Test, Cmd.TranslateC => { + if (cmd == Cmd.Build and in_file_arg == null and objects.len == 0 and asm_files.len == 0) { + return badArgs("expected source file argument or at least one --object or --assembly argument"); + } else if ((cmd == Cmd.TranslateC or cmd == Cmd.Test) and in_file_arg == null) { + return badArgs("expected source file argument"); + } else if (cmd == Cmd.Build and build_kind == Module.Kind.Obj and objects.len != 0) { + return badArgs("When building an object file, --object arguments are invalid"); + } - %return parser.renderAst(out_stream, root_node); + const root_name = switch (cmd) { + Cmd.Build, Cmd.TranslateC => x: { + if (out_name_arg) |out_name| { + break :x out_name; + } else if (in_file_arg) |in_file_path| { + const basename = os.path.basename(in_file_path); + var it = mem.split(basename, "."); + break :x it.next() ?? return badArgs("file name cannot be empty"); + } else { + return badArgs("--name [name] not provided and unable to infer"); + } + }, + Cmd.Test => "test", + else => unreachable, + }; - warn("====fmt:====\n"); - %return parser.renderSource(out_stream, root_node); + const zig_root_source_file = if (cmd == Cmd.TranslateC) null else in_file_arg; + + const chosen_cache_dir = cache_dir_arg ?? default_zig_cache_name; + const full_cache_dir = %return os.path.resolve(allocator, ".", chosen_cache_dir); + defer allocator.free(full_cache_dir); + + const zig_lib_dir = %return resolveZigLibDir(allocator, zig_install_prefix); + %defer allocator.free(zig_lib_dir); + + const module = %return Module.create(allocator, root_name, zig_root_source_file, + Target.Native, build_kind, build_mode, zig_lib_dir, full_cache_dir); + defer module.destroy(); + + module.version_major = ver_major; + module.version_minor = ver_minor; + module.version_patch = ver_patch; + + module.is_test = cmd == Cmd.Test; + if (linker_script_arg) |linker_script| { + module.linker_script = linker_script; + } + module.each_lib_rpath = each_lib_rpath; + module.clang_argv = clang_argv.toSliceConst(); + module.llvm_argv = llvm_argv.toSliceConst(); + module.strip = strip; + module.is_static = is_static; + + if (libc_lib_dir_arg) |libc_lib_dir| { + module.libc_lib_dir = libc_lib_dir; + } + if (libc_static_lib_dir_arg) |libc_static_lib_dir| { + module.libc_static_lib_dir = libc_static_lib_dir; + } + if (libc_include_dir_arg) |libc_include_dir| { + module.libc_include_dir = libc_include_dir; + } + if (msvc_lib_dir_arg) |msvc_lib_dir| { + module.msvc_lib_dir = msvc_lib_dir; + } + if (kernel32_lib_dir_arg) |kernel32_lib_dir| { + module.kernel32_lib_dir = kernel32_lib_dir; + } + if (dynamic_linker_arg) |dynamic_linker| { + module.dynamic_linker = dynamic_linker; + } + module.verbose_tokenize = verbose_tokenize; + module.verbose_ast_tree = verbose_ast_tree; + module.verbose_ast_fmt = verbose_ast_fmt; + module.verbose_link = verbose_link; + module.verbose_ir = verbose_ir; + module.verbose_llvm_ir = verbose_llvm_ir; + module.verbose_cimport = verbose_cimport; + + module.err_color = color; + + module.lib_dirs = lib_dirs.toSliceConst(); + module.darwin_frameworks = frameworks.toSliceConst(); + module.rpath_list = rpath_list.toSliceConst(); + + for (link_libs.toSliceConst()) |name| { + _ = %return module.addLinkLib(name, true); + } + + module.windows_subsystem_windows = mwindows; + module.windows_subsystem_console = mconsole; + module.linker_rdynamic = rdynamic; + + if (mmacosx_version_min != null and mios_version_min != null) { + return badArgs("-mmacosx-version-min and -mios-version-min options not allowed together"); + } + + if (mmacosx_version_min) |ver| { + module.darwin_version_min = Module.DarwinVersionMin { .MacOS = ver }; + } else if (mios_version_min) |ver| { + module.darwin_version_min = Module.DarwinVersionMin { .Ios = ver }; + } + + module.test_filters = test_filters.toSliceConst(); + module.test_name_prefix = test_name_prefix_arg; + module.out_h_path = out_file_h; + + // TODO + //add_package(g, cur_pkg, g->root_package); + + switch (cmd) { + Cmd.Build => { + module.emit_file_type = emit_file_type; + + module.link_objects = objects.toSliceConst(); + module.assembly_files = asm_files.toSliceConst(); + + %return module.build(); + %return module.link(out_file); + }, + Cmd.TranslateC => @panic("TODO translate-c"), + Cmd.Test => @panic("TODO test cmd"), + else => unreachable, + } + }, + Cmd.Version => @panic("TODO zig version"), + Cmd.Targets => @panic("TODO zig targets"), + } } -test "import other tests" { - _ = @import("parser.zig"); - _ = @import("tokenizer.zig"); +fn printUsage(stream: &io.OutStream) -> %void { + %return stream.write( + \\Usage: zig [command] [options] + \\ + \\Commands: + \\ build build project from build.zig + \\ build-exe [source] create executable from source or object files + \\ build-lib [source] create library from source or object files + \\ build-obj [source] create object from source or assembly + \\ translate-c [source] convert c code to zig code + \\ targets list available compilation targets + \\ test [source] create and run a test build + \\ version print version number and exit + \\ zen print zen of zig and exit + \\Compile Options: + \\ --assembly [source] add assembly file to build + \\ --cache-dir [path] override the cache directory + \\ --color [auto|off|on] enable or disable colored error messages + \\ --emit [filetype] emit a specific file format as compilation output + \\ --enable-timing-info print timing diagnostics + \\ --libc-include-dir [path] directory where libc stdlib.h resides + \\ --name [name] override output name + \\ --output [file] override destination path + \\ --output-h [file] override generated header file path + \\ --pkg-begin [name] [path] make package available to import and push current pkg + \\ --pkg-end pop current pkg + \\ --release-fast build with optimizations on and safety off + \\ --release-safe build with optimizations on and safety on + \\ --static output will be statically linked + \\ --strip exclude debug symbols + \\ --target-arch [name] specify target architecture + \\ --target-environ [name] specify target environment + \\ --target-os [name] specify target operating system + \\ --verbose-tokenize enable compiler debug info: tokenization + \\ --verbose-ast-tree enable compiler debug info: parsing into an AST (treeview) + \\ --verbose-ast-fmt enable compiler debug info: parsing into an AST (render source) + \\ --verbose-cimport enable compiler debug info: C imports + \\ --verbose-ir enable compiler debug info: Zig IR + \\ --verbose-llvm-ir enable compiler debug info: LLVM IR + \\ --verbose-link enable compiler debug info: linking + \\ --zig-install-prefix [path] override directory where zig thinks it is installed + \\ -dirafter [dir] same as -isystem but do it last + \\ -isystem [dir] add additional search path for other .h files + \\ -mllvm [arg] additional arguments to forward to LLVM's option processing + \\Link Options: + \\ --ar-path [path] set the path to ar + \\ --dynamic-linker [path] set the path to ld.so + \\ --each-lib-rpath add rpath for each used dynamic library + \\ --libc-lib-dir [path] directory where libc crt1.o resides + \\ --libc-static-lib-dir [path] directory where libc crtbegin.o resides + \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides + \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides + \\ --library [lib] link against lib + \\ --library-path [dir] add a directory to the library search path + \\ --linker-script [path] use a custom linker script + \\ --object [obj] add object file to build + \\ -L[dir] alias for --library-path + \\ -rdynamic add all symbols to the dynamic symbol table + \\ -rpath [path] add directory to the runtime library search path + \\ -mconsole (windows) --subsystem console to the linker + \\ -mwindows (windows) --subsystem windows to the linker + \\ -framework [name] (darwin) link against framework + \\ -mios-version-min [ver] (darwin) set iOS deployment target + \\ -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target + \\ --ver-major [ver] dynamic library semver major version + \\ --ver-minor [ver] dynamic library semver minor version + \\ --ver-patch [ver] dynamic library semver patch version + \\Test Options: + \\ --test-filter [text] skip tests that do not match filter + \\ --test-name-prefix [text] add prefix to all tests + \\ --test-cmd [arg] specify test execution command one arg at a time + \\ --test-cmd-bin appends test binary path to test cmd args + \\ + ); +} + +fn printZen() -> %void { + var stdout_file = %return io.getStdErr(); + %return stdout_file.write( + \\ + \\ * Communicate intent precisely. + \\ * Edge cases matter. + \\ * Favor reading code over writing code. + \\ * Only one obvious way to do things. + \\ * Runtime crashes are better than bugs. + \\ * Compile errors are better than runtime crashes. + \\ * Incremental improvements. + \\ * Avoid local maximums. + \\ * Reduce the amount one must remember. + \\ * Minimize energy spent on coding style. + \\ * Together we serve end users. + \\ + \\ + ); +} + +/// Caller must free result +fn resolveZigLibDir(allocator: &mem.Allocator, zig_install_prefix_arg: ?[]const u8) -> %[]u8 { + if (zig_install_prefix_arg) |zig_install_prefix| { + return testZigInstallPrefix(allocator, zig_install_prefix) %% |err| { + warn("No Zig installation found at prefix {}: {}\n", zig_install_prefix_arg, @errorName(err)); + return error.ZigInstallationNotFound; + }; + } else { + return findZigLibDir(allocator) %% |err| { + warn("Unable to find zig lib directory: {}.\nReinstall Zig or use --zig-install-prefix.\n", + @errorName(err)); + return error.ZigLibDirNotFound; + }; + } +} + +/// Caller must free result +fn testZigInstallPrefix(allocator: &mem.Allocator, test_path: []const u8) -> %[]u8 { + const test_zig_dir = %return os.path.join(allocator, test_path, "lib", "zig"); + %defer allocator.free(test_zig_dir); + + const test_index_file = %return os.path.join(allocator, test_zig_dir, "std", "index.zig"); + defer allocator.free(test_index_file); + + var file = %return io.File.openRead(test_index_file, allocator); + file.close(); + + return test_zig_dir; +} + +/// Caller must free result +fn findZigLibDir(allocator: &mem.Allocator) -> %[]u8 { + const self_exe_path = %return os.selfExeDirPath(allocator); + defer allocator.free(self_exe_path); + + var cur_path: []const u8 = self_exe_path; + while (true) { + const test_dir = os.path.dirname(cur_path); + + if (mem.eql(u8, test_dir, cur_path)) { + break; + } + + return testZigInstallPrefix(allocator, test_dir) %% |err| { + cur_path = test_dir; + continue; + }; + } + + // TODO look in hard coded installation path from configuration + //if (ZIG_INSTALL_PREFIX != nullptr) { + // if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) { + // return 0; + // } + //} + + return error.FileNotFound; } diff --git a/src-self-hosted/module.zig b/src-self-hosted/module.zig new file mode 100644 index 0000000000..700ccf0176 --- /dev/null +++ b/src-self-hosted/module.zig @@ -0,0 +1,295 @@ +const std = @import("std"); +const os = std.os; +const io = std.io; +const mem = std.mem; +const Buffer = std.Buffer; +const llvm = @import("llvm.zig"); +const c = @import("c.zig"); +const builtin = @import("builtin"); +const Target = @import("target.zig").Target; +const warn = std.debug.warn; +const Tokenizer = @import("tokenizer.zig").Tokenizer; +const Token = @import("tokenizer.zig").Token; +const Parser = @import("parser.zig").Parser; +const ArrayList = std.ArrayList; + +pub const Module = struct { + allocator: &mem.Allocator, + name: Buffer, + root_src_path: ?[]const u8, + module: llvm.ModuleRef, + context: llvm.ContextRef, + builder: llvm.BuilderRef, + target: Target, + build_mode: builtin.Mode, + zig_lib_dir: []const u8, + + version_major: u32, + version_minor: u32, + version_patch: u32, + + linker_script: ?[]const u8, + cache_dir: []const u8, + libc_lib_dir: ?[]const u8, + libc_static_lib_dir: ?[]const u8, + libc_include_dir: ?[]const u8, + msvc_lib_dir: ?[]const u8, + kernel32_lib_dir: ?[]const u8, + dynamic_linker: ?[]const u8, + out_h_path: ?[]const u8, + + is_test: bool, + each_lib_rpath: bool, + strip: bool, + is_static: bool, + linker_rdynamic: bool, + + clang_argv: []const []const u8, + llvm_argv: []const []const u8, + lib_dirs: []const []const u8, + rpath_list: []const []const u8, + assembly_files: []const []const u8, + link_objects: []const []const u8, + + windows_subsystem_windows: bool, + windows_subsystem_console: bool, + + link_libs_list: ArrayList(&LinkLib), + libc_link_lib: ?&LinkLib, + + err_color: ErrColor, + + verbose_tokenize: bool, + verbose_ast_tree: bool, + verbose_ast_fmt: bool, + verbose_cimport: bool, + verbose_ir: bool, + verbose_llvm_ir: bool, + verbose_link: bool, + + darwin_frameworks: []const []const u8, + darwin_version_min: DarwinVersionMin, + + test_filters: []const []const u8, + test_name_prefix: ?[]const u8, + + emit_file_type: Emit, + + kind: Kind, + + pub const DarwinVersionMin = union(enum) { + None, + MacOS: []const u8, + Ios: []const u8, + }; + + pub const Kind = enum { + Exe, + Lib, + Obj, + }; + + pub const ErrColor = enum { + Auto, + Off, + On, + }; + + pub const LinkLib = struct { + name: []const u8, + path: ?[]const u8, + /// the list of symbols we depend on from this lib + symbols: ArrayList([]u8), + provided_explicitly: bool, + }; + + pub const Emit = enum { + Binary, + Assembly, + LlvmIr, + }; + + pub fn create(allocator: &mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: &const Target, + kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) -> %&Module + { + var name_buffer = %return Buffer.init(allocator, name); + %defer name_buffer.deinit(); + + const context = c.LLVMContextCreate() ?? return error.OutOfMemory; + %defer c.LLVMContextDispose(context); + + const module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) ?? return error.OutOfMemory; + %defer c.LLVMDisposeModule(module); + + const builder = c.LLVMCreateBuilderInContext(context) ?? return error.OutOfMemory; + %defer c.LLVMDisposeBuilder(builder); + + const module_ptr = %return allocator.create(Module); + %defer allocator.destroy(module_ptr); + + *module_ptr = Module { + .allocator = allocator, + .name = name_buffer, + .root_src_path = root_src_path, + .module = module, + .context = context, + .builder = builder, + .target = *target, + .kind = kind, + .build_mode = build_mode, + .zig_lib_dir = zig_lib_dir, + .cache_dir = cache_dir, + + .version_major = 0, + .version_minor = 0, + .version_patch = 0, + + .verbose_tokenize = false, + .verbose_ast_tree = false, + .verbose_ast_fmt = false, + .verbose_cimport = false, + .verbose_ir = false, + .verbose_llvm_ir = false, + .verbose_link = false, + + .linker_script = null, + .libc_lib_dir = null, + .libc_static_lib_dir = null, + .libc_include_dir = null, + .msvc_lib_dir = null, + .kernel32_lib_dir = null, + .dynamic_linker = null, + .out_h_path = null, + .is_test = false, + .each_lib_rpath = false, + .strip = false, + .is_static = false, + .linker_rdynamic = false, + .clang_argv = [][]const u8{}, + .llvm_argv = [][]const u8{}, + .lib_dirs = [][]const u8{}, + .rpath_list = [][]const u8{}, + .assembly_files = [][]const u8{}, + .link_objects = [][]const u8{}, + .windows_subsystem_windows = false, + .windows_subsystem_console = false, + .link_libs_list = ArrayList(&LinkLib).init(allocator), + .libc_link_lib = null, + .err_color = ErrColor.Auto, + .darwin_frameworks = [][]const u8{}, + .darwin_version_min = DarwinVersionMin.None, + .test_filters = [][]const u8{}, + .test_name_prefix = null, + .emit_file_type = Emit.Binary, + }; + return module_ptr; + } + + fn dump(self: &Module) { + c.LLVMDumpModule(self.module); + } + + pub fn destroy(self: &Module) { + c.LLVMDisposeBuilder(self.builder); + c.LLVMDisposeModule(self.module); + c.LLVMContextDispose(self.context); + self.name.deinit(); + + self.allocator.destroy(self); + } + + pub fn build(self: &Module) -> %void { + const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path"); + const root_src_real_path = os.path.real(self.allocator, root_src_path) %% |err| { + %return printError("unable to open '{}': {}", root_src_path, err); + return err; + }; + %defer self.allocator.free(root_src_real_path); + + const source_code = io.readFileAlloc(root_src_real_path, self.allocator) %% |err| { + %return printError("unable to open '{}': {}", root_src_real_path, err); + return err; + }; + %defer self.allocator.free(source_code); + + warn("====input:====\n"); + + warn("{}", source_code); + + warn("====tokenization:====\n"); + { + var tokenizer = Tokenizer.init(source_code); + while (true) { + const token = tokenizer.next(); + tokenizer.dump(token); + if (token.id == Token.Id.Eof) { + break; + } + } + } + + warn("====parse:====\n"); + + var tokenizer = Tokenizer.init(source_code); + var parser = Parser.init(&tokenizer, self.allocator, root_src_real_path); + defer parser.deinit(); + + const root_node = %return parser.parse(); + defer parser.freeAst(root_node); + + var stderr_file = %return std.io.getStdErr(); + var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); + const out_stream = &stderr_file_out_stream.stream; + %return parser.renderAst(out_stream, root_node); + + warn("====fmt:====\n"); + %return parser.renderSource(out_stream, root_node); + + warn("====ir:====\n"); + warn("TODO\n\n"); + + warn("====llvm ir:====\n"); + self.dump(); + + } + + pub fn link(self: &Module, out_file: ?[]const u8) -> %void { + warn("TODO link"); + } + + pub fn addLinkLib(self: &Module, name: []const u8, provided_explicitly: bool) -> %&LinkLib { + const is_libc = mem.eql(u8, name, "c"); + + if (is_libc) { + if (self.libc_link_lib) |libc_link_lib| { + return libc_link_lib; + } + } + + for (self.link_libs_list.toSliceConst()) |existing_lib| { + if (mem.eql(u8, name, existing_lib.name)) { + return existing_lib; + } + } + + const link_lib = %return self.allocator.create(LinkLib); + *link_lib = LinkLib { + .name = name, + .path = null, + .provided_explicitly = provided_explicitly, + .symbols = ArrayList([]u8).init(self.allocator), + }; + %return self.link_libs_list.append(link_lib); + if (is_libc) { + self.libc_link_lib = link_lib; + } + return link_lib; + } +}; + +fn printError(comptime format: []const u8, args: ...) -> %void { + var stderr_file = %return std.io.getStdErr(); + var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file); + const out_stream = &stderr_file_out_stream.stream; + %return out_stream.print(format, args); +} diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 90e2132ac5..0d077690dd 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -1,5 +1,56 @@ +const builtin = @import("builtin"); const c = @import("c.zig"); +pub const CrossTarget = struct { + arch: builtin.Arch, + os: builtin.Os, + environ: builtin.Environ, +}; + +pub const Target = union(enum) { + Native, + Cross: CrossTarget, + + pub fn oFileExt(self: &const Target) -> []const u8 { + const environ = switch (*self) { + Target.Native => builtin.environ, + Target.Cross => |t| t.environ, + }; + return switch (environ) { + builtin.Environ.msvc => ".obj", + else => ".o", + }; + } + + pub fn exeFileExt(self: &const Target) -> []const u8 { + return switch (self.getOs()) { + builtin.Os.windows => ".exe", + else => "", + }; + } + + pub fn getOs(self: &const Target) -> builtin.Os { + return switch (*self) { + Target.Native => builtin.os, + Target.Cross => |t| t.os, + }; + } + + pub fn isDarwin(self: &const Target) -> bool { + return switch (self.getOs()) { + builtin.Os.darwin, builtin.Os.ios, builtin.Os.macosx => true, + else => false, + }; + } + + pub fn isWindows(self: &const Target) -> bool { + return switch (self.getOs()) { + builtin.Os.windows => true, + else => false, + }; + } +}; + pub fn initializeAll() { c.LLVMInitializeAllTargets(); c.LLVMInitializeAllTargetInfos(); diff --git a/std/buffer.zig b/std/buffer.zig index 267d9b6353..4f5d281f48 100644 --- a/std/buffer.zig +++ b/std/buffer.zig @@ -139,6 +139,11 @@ pub const Buffer = struct { %return self.resize(m.len); mem.copy(u8, self.list.toSlice(), m); } + + /// For passing to C functions. + pub fn ptr(self: &const Buffer) -> &u8 { + return self.list.items.ptr; + } }; test "simple Buffer" { diff --git a/std/c/index.zig b/std/c/index.zig index 2ac867ee71..e04b990633 100644 --- a/std/c/index.zig +++ b/std/c/index.zig @@ -48,3 +48,4 @@ pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) -> c_int; pub extern "c" fn malloc(usize) -> ?&c_void; pub extern "c" fn realloc(&c_void, usize) -> ?&c_void; pub extern "c" fn free(&c_void); +pub extern "c" fn posix_memalign(memptr: &&c_void, alignment: usize, size: usize) -> c_int; diff --git a/std/heap.zig b/std/heap.zig index 605eddb40b..ec447c1aa8 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -10,7 +10,8 @@ const Allocator = mem.Allocator; error OutOfMemory; -pub var c_allocator = Allocator { +pub const c_allocator = &c_allocator_state; +var c_allocator_state = Allocator { .allocFn = cAlloc, .reallocFn = cRealloc, .freeFn = cFree, @@ -24,15 +25,13 @@ fn cAlloc(self: &Allocator, n: usize, alignment: u29) -> %[]u8 { } fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 { - if (new_size <= old_mem.len) { + const old_ptr = @ptrCast(&c_void, old_mem.ptr); + if (c.realloc(old_ptr, new_size)) |buf| { + return @ptrCast(&u8, buf)[0..new_size]; + } else if (new_size <= old_mem.len) { return old_mem[0..new_size]; } else { - const old_ptr = @ptrCast(&c_void, old_mem.ptr); - if (c.realloc(old_ptr, usize(new_size))) |buf| { - return @ptrCast(&u8, buf)[0..new_size]; - } else { - return error.OutOfMemory; - } + return error.OutOfMemory; } } diff --git a/std/os/index.zig b/std/os/index.zig index 09109c3242..8e79eda40b 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -1543,6 +1543,39 @@ pub fn openSelfExe() -> %io.File { } } +/// Get the directory path that contains the current executable. +/// Caller owns returned memory. +pub fn selfExeDirPath(allocator: &mem.Allocator) -> %[]u8 { + switch (builtin.os) { + Os.linux => { + // If the currently executing binary has been deleted, + // the file path looks something like `/a/b/c/exe (deleted)` + // This path cannot be opened, but it's valid for determining the directory + // the executable was in when it was run. + const full_exe_path = %return readLink(allocator, "/proc/self/exe"); + %defer allocator.free(full_exe_path); + const dir = path.dirname(full_exe_path); + return allocator.shrink(u8, full_exe_path, dir.len); + }, + Os.windows => { + @panic("TODO windows std.os.selfExeDirPath"); + //buf_resize(out_path, 256); + //for (;;) { + // DWORD copied_amt = GetModuleFileName(nullptr, buf_ptr(out_path), buf_len(out_path)); + // if (copied_amt <= 0) { + // return ErrorFileNotFound; + // } + // if (copied_amt < buf_len(out_path)) { + // buf_resize(out_path, copied_amt); + // return 0; + // } + // buf_resize(out_path, buf_len(out_path) * 2); + //} + }, + else => @compileError("unimplemented: std.os.selfExeDirPath for " ++ @tagName(builtin.os)), + } +} + pub fn isTty(handle: FileHandle) -> bool { if (is_windows) { return windows_util.windowsIsTty(handle);