Commit 39c7bd24e4

Andrew Kelley <superjoe30@gmail.com>
2017-12-23 06:29:39
port most of main.cpp to self hosted compiler
1 parent 760b307
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;
+}
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;
+
+    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;
+
+    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 test_filters = ArrayList([]const u8).init(allocator);
+    defer test_filters.deinit();
+
+    var lib_dirs = ArrayList([]const u8).init(allocator);
+    defer lib_dirs.deinit();
+
+    var clang_argv = ArrayList([]const u8).init(allocator);
+    defer clang_argv.deinit();
+
+    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();
 
-    const target_file = args[1];
+    var asm_files = ArrayList([]const u8).init(allocator);
+    defer asm_files.deinit();
 
-    const target_file_buf = %return io.readFileAlloc(target_file, allocator);
-    defer allocator.free(target_file_buf);
+    var rpath_list = ArrayList([]const u8).init(allocator);
+    defer rpath_list.deinit();
 
-    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 ver_major: u32 = 0;
+    var ver_minor: u32 = 0;
+    var ver_patch: u32 = 0;
 
-    warn("====input:====\n");
+    var arg_i: usize = 1;
+    while (arg_i < args.len) : (arg_i += 1) {
+        const arg = args[arg_i];
 
-    warn("{}", target_file_buf);
+        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]);
 
-    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;
+                    %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();
+
+    // 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);
+//            }
+//        }
+//    }
+
+    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");
+            }
+
+            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,
+            };
+
+            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"),
+    }
+}
+
+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
+        \\
+    );
+}
 
-    var tokenizer = Tokenizer.init(target_file_buf);
-    var parser = Parser.init(&tokenizer, allocator, target_file);
-    defer parser.deinit();
+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;
+        };
+    }
+}
 
-    const root_node = %return parser.parse();
-    defer parser.freeAst(root_node);
+/// 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);
 
-    %return parser.renderAst(out_stream, root_node);
+    const test_index_file = %return os.path.join(allocator, test_zig_dir, "std", "index.zig");
+    defer allocator.free(test_index_file);
 
-    warn("====fmt:====\n");
-    %return parser.renderSource(out_stream, root_node);
+    var file = %return io.File.openRead(test_index_file, allocator);
+    file.close();
+
+    return test_zig_dir;
 }
 
-test "import other tests" {
-    _ = @import("parser.zig");
-    _ = @import("tokenizer.zig");
+/// 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;
 }
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);
+}
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();
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;
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);
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" {
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;
     }
 }
 
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);
+    }
+}
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