Commit 2ef68631cb

Andrew Kelley <andrew@ziglang.org>
2020-09-19 07:48:28
stage2 now supports using stage1 as a backend for compiling zig code
* move stage2.cpp code into zig0.cpp for simplicity * add -ftime-report and some more CLI options to stage2 * stage2 compites the llvm cpu features string * classifyFileExt understands more file extensions * correction to generateBuiltinZigSource using the wrong allocator (thanks dbandstra!) * stage2 is now able to build hello.zig into hello.o using stage1 as a library however it fails linking due to missing compiler-rt * remove dead code * simplify zig0 builtin.zig source * fix not resolving builtin.zig source path causing duplicate imports * fix stage1.h not being valid C code * fix stage2.h not being valid C code
1 parent 333b12a
src/analyze.cpp
@@ -7987,7 +7987,7 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents_buf) {
     size_t len;
     const char *contents = stage2_fetch_file(&g->stage1, buf_ptr(resolved_path), buf_len(resolved_path), &len);
     if (contents == nullptr)
-        return ErrorNoMem;
+        return ErrorFileNotFound;
     buf_init_from_mem(contents_buf, contents, len);
     return ErrorNone;
 }
src/codegen.cpp
@@ -8809,33 +8809,18 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
     static_assert(TargetSubsystemEfiBootServiceDriver == 5, "");
     static_assert(TargetSubsystemEfiRom == 6, "");
     static_assert(TargetSubsystemEfiRuntimeDriver == 7, "");
-    {
-        const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
-        buf_appendf(contents, "pub const endian = %s;\n", endian_str);
-    }
+
+    buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch`\n");
+    buf_append_str(contents, "pub const arch = Target.current.cpu.arch;\n");
+    buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch.endian()`\n");
+    buf_append_str(contents, "pub const endian = Target.current.cpu.arch.endian();\n");
     buf_appendf(contents, "pub const output_mode = OutputMode.Obj;\n");
     buf_appendf(contents, "pub const link_mode = LinkMode.Static;\n");
     buf_appendf(contents, "pub const is_test = false;\n");
     buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
-    buf_append_str(contents, "/// Deprecated: use `std.Target.cpu.arch`\n");
-    buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
     buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
-    {
-        buf_append_str(contents, "pub const cpu: Cpu = ");
-        if (g->zig_target->cpu_builtin_str != nullptr) {
-            buf_append_str(contents, g->zig_target->cpu_builtin_str);
-        } else {
-            buf_appendf(contents, "Target.Cpu.baseline(.%s);\n", cur_arch);
-        }
-    }
-    {
-        buf_append_str(contents, "pub const os = ");
-        if (g->zig_target->os_builtin_str != nullptr) {
-            buf_append_str(contents, g->zig_target->os_builtin_str);
-        } else {
-            buf_appendf(contents, "Target.Os.Tag.defaultVersionRange(.%s);\n", cur_os);
-        }
-    }
+    buf_appendf(contents, "pub const cpu: Cpu = Target.Cpu.baseline(.%s);\n", cur_arch);
+    buf_appendf(contents, "pub const os = Target.Os.Tag.defaultVersionRange(.%s);\n", cur_os);
     buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
     buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
     buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->link_libc));
@@ -8866,6 +8851,8 @@ static Error define_builtin_compile_vars(CodeGen *g) {
     if (g->std_package == nullptr)
         return ErrorNone;
 
+    assert(g->main_pkg);
+
     const char *builtin_zig_basename = "builtin.zig";
 
     Buf *contents;
@@ -8879,17 +8866,22 @@ static Error define_builtin_compile_vars(CodeGen *g) {
             fprintf(stderr, "Unable to write file '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err));
             exit(1);
         }
+
+        g->compile_var_package = new_package(buf_ptr(g->output_dir), builtin_zig_basename, "builtin");
     } else {
+        Buf *resolve_paths[] = { g->builtin_zig_path, };
+        *g->builtin_zig_path = os_path_resolve(resolve_paths, 1);
+
         contents = buf_alloc();
         if ((err = os_fetch_file_path(g->builtin_zig_path, contents))) {
             fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(g->builtin_zig_path), err_str(err));
             exit(1);
         }
+        Buf builtin_dirname = BUF_INIT;
+        os_path_dirname(g->builtin_zig_path, &builtin_dirname);
+        g->compile_var_package = new_package(buf_ptr(&builtin_dirname), builtin_zig_basename, "builtin");
     }
 
-    assert(g->main_pkg);
-    assert(g->std_package);
-    g->compile_var_package = new_package(buf_ptr(g->output_dir), builtin_zig_basename, "builtin");
     if (g->is_test_build) {
         if (g->test_runner_package == nullptr) {
             g->test_runner_package = create_test_runner_pkg(g);
@@ -8914,6 +8906,13 @@ static void init(CodeGen *g) {
     if (g->module)
         return;
 
+    codegen_add_time_event(g, "Initialize");
+    {
+        const char *progress_name = "Initialize";
+        codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
+                progress_name, strlen(progress_name), 0));
+    }
+
     g->have_err_ret_tracing = detect_err_ret_tracing(g);
 
     assert(g->root_out_name);
@@ -9374,19 +9373,11 @@ void codegen_destroy(CodeGen *g) {
 
 CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
     BuildMode build_mode, Buf *override_lib_dir,
-    bool is_test_build, Stage2ProgressNode *progress_node)
+    bool is_test_build)
 {
     CodeGen *g = heap::c_allocator.create<CodeGen>();
     g->emit_bin = true;
     g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1");
-    g->main_progress_node = progress_node;
-
-    codegen_add_time_event(g, "Initialize");
-    {
-        const char *progress_name = "Initialize";
-        codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
-                progress_name, strlen(progress_name), 0));
-    }
 
     g->subsystem = TargetSubsystemAuto;
     g->zig_target = target;
@@ -9440,7 +9431,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
             Buf resolved_main_pkg_path = os_path_resolve(&main_pkg_path, 1);
 
             if (!buf_starts_with_buf(&resolved_root_src_path, &resolved_main_pkg_path)) {
-                fprintf(stderr, "Root source path '%s' outside main package path '%s'",
+                fprintf(stderr, "Root source path '%s' outside main package path '%s'\n",
                         buf_ptr(root_src_path), buf_ptr(main_pkg_path));
                 exit(1);
             }
src/codegen.hpp
@@ -16,8 +16,7 @@
 #include <stdio.h>
 
 CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,
-    BuildMode build_mode, Buf *zig_lib_dir,
-    bool is_test_build, Stage2ProgressNode *progress_node);
+    BuildMode build_mode, Buf *zig_lib_dir, bool is_test_build);
 
 void codegen_build_object(CodeGen *g);
 void codegen_destroy(CodeGen *);
src/stage1.cpp
@@ -20,13 +20,14 @@ struct ZigStage1 *zig_stage1_create(BuildMode optimize_mode,
     const char *main_pkg_path_ptr, size_t main_pkg_path_len,
     const char *root_src_path_ptr, size_t root_src_path_len,
     const char *zig_lib_dir_ptr, size_t zig_lib_dir_len,
-    const ZigTarget *target, bool is_test_build, Stage2ProgressNode *progress_node)
+    const ZigTarget *target, bool is_test_build)
 {
-    Buf *main_pkg_path = buf_create_from_mem(main_pkg_path_ptr, main_pkg_path_len);
+    Buf *main_pkg_path = (main_pkg_path_len == 0) ?
+        nullptr : buf_create_from_mem(main_pkg_path_ptr, main_pkg_path_len);
     Buf *root_src_path = buf_create_from_mem(root_src_path_ptr, root_src_path_len);
     Buf *zig_lib_dir = buf_create_from_mem(zig_lib_dir_ptr, zig_lib_dir_len);
     CodeGen *g = codegen_create(main_pkg_path, root_src_path, target, optimize_mode,
-            zig_lib_dir, is_test_build, progress_node);
+            zig_lib_dir, is_test_build);
     return &g->stage1;
 }
 
@@ -68,8 +69,6 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
     CodeGen *g = reinterpret_cast<CodeGen *>(stage1);
 
     g->root_out_name = buf_create_from_mem(stage1->root_name_ptr, stage1->root_name_len);
-    g->zig_lib_dir = buf_create_from_mem(stage1->zig_lib_dir_ptr, stage1->zig_lib_dir_len);
-    g->zig_std_dir = buf_create_from_mem(stage1->zig_std_dir_ptr, stage1->zig_std_dir_len);
     g->output_dir = buf_create_from_mem(stage1->output_dir_ptr, stage1->output_dir_len);
     if (stage1->builtin_zig_path_len != 0) {
         g->builtin_zig_path = buf_create_from_mem(stage1->builtin_zig_path_ptr, stage1->builtin_zig_path_len);
@@ -119,6 +118,8 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
         }
     }
 
+    g->main_progress_node = stage1->main_progress_node;
+
     add_package(g, stage1->root_pkg, g->main_pkg);
 
     codegen_build_object(g);
src/stage1.h
@@ -100,22 +100,14 @@ enum Os {
 // ABI warning
 struct ZigTarget {
     enum ZigLLVM_ArchType arch;
-    enum ZigLLVM_VendorType vendor;
-
+    enum Os os;
     enum ZigLLVM_EnvironmentType abi;
-    Os os;
 
     bool is_native_os;
     bool is_native_cpu;
 
     const char *llvm_cpu_name;
     const char *llvm_cpu_features;
-    const char *cpu_builtin_str;
-    const char *os_builtin_str;
-    const char *dynamic_linker;
-
-    const char **llvm_cpu_features_asm_ptr;
-    size_t llvm_cpu_features_asm_len;
 };
 
 // ABI warning
@@ -161,18 +153,13 @@ struct ZigStage1 {
     const char *test_name_prefix_ptr;
     size_t test_name_prefix_len;
 
-    const char *zig_lib_dir_ptr;
-    size_t zig_lib_dir_len;
-
-    const char *zig_std_dir_ptr;
-    size_t zig_std_dir_len;
-
     void *userdata;
     struct ZigStage1Pkg *root_pkg;
+    struct Stage2ProgressNode *main_progress_node;
 
-    CodeModel code_model;
-    TargetSubsystem subsystem;
-    ErrColor err_color;
+    enum CodeModel code_model;
+    enum TargetSubsystem subsystem;
+    enum ErrColor err_color;
 
     bool pic;
     bool link_libc;
@@ -206,7 +193,7 @@ ZIG_EXTERN_C struct ZigStage1 *zig_stage1_create(enum BuildMode optimize_mode,
     const char *main_pkg_path_ptr, size_t main_pkg_path_len,
     const char *root_src_path_ptr, size_t root_src_path_len,
     const char *zig_lib_dir_ptr, size_t zig_lib_dir_len,
-    const ZigTarget *target, bool is_test_build, Stage2ProgressNode *progress_node);
+    const struct ZigTarget *target, bool is_test_build);
 
 ZIG_EXTERN_C void zig_stage1_build_object(struct ZigStage1 *);
 
src/stage2.cpp
@@ -1,241 +0,0 @@
-// This file is a shim for zig1. The real implementations of these are in
-// src-self-hosted/stage1.zig
-
-#include "stage2.h"
-#include "util.hpp"
-#include "zig_llvm.h"
-#include "target.hpp"
-#include "buffer.hpp"
-#include "os.hpp"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-void stage2_panic(const char *ptr, size_t len) {
-    fwrite(ptr, 1, len, stderr);
-    fprintf(stderr, "\n");
-    fflush(stderr);
-    abort();
-}
-
-struct Stage2Progress {
-    int trash;
-};
-
-struct Stage2ProgressNode {
-    int trash;
-};
-
-Stage2Progress *stage2_progress_create(void) {
-    return nullptr;
-}
-
-void stage2_progress_destroy(Stage2Progress *progress) {}
-
-Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
-        const char *name_ptr, size_t name_len, size_t estimated_total_items)
-{
-    return nullptr;
-}
-Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
-        const char *name_ptr, size_t name_len, size_t estimated_total_items)
-{
-    return nullptr;
-}
-void stage2_progress_end(Stage2ProgressNode *node) {}
-void stage2_progress_complete_one(Stage2ProgressNode *node) {}
-void stage2_progress_disable_tty(Stage2Progress *progress) {}
-void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
-
-static Os get_zig_os_type(ZigLLVM_OSType os_type) {
-    switch (os_type) {
-        case ZigLLVM_UnknownOS:
-            return OsFreestanding;
-        case ZigLLVM_Ananas:
-            return OsAnanas;
-        case ZigLLVM_CloudABI:
-            return OsCloudABI;
-        case ZigLLVM_DragonFly:
-            return OsDragonFly;
-        case ZigLLVM_FreeBSD:
-            return OsFreeBSD;
-        case ZigLLVM_Fuchsia:
-            return OsFuchsia;
-        case ZigLLVM_IOS:
-            return OsIOS;
-        case ZigLLVM_KFreeBSD:
-            return OsKFreeBSD;
-        case ZigLLVM_Linux:
-            return OsLinux;
-        case ZigLLVM_Lv2:
-            return OsLv2;
-        case ZigLLVM_Darwin:
-        case ZigLLVM_MacOSX:
-            return OsMacOSX;
-        case ZigLLVM_NetBSD:
-            return OsNetBSD;
-        case ZigLLVM_OpenBSD:
-            return OsOpenBSD;
-        case ZigLLVM_Solaris:
-            return OsSolaris;
-        case ZigLLVM_Win32:
-            return OsWindows;
-        case ZigLLVM_Haiku:
-            return OsHaiku;
-        case ZigLLVM_Minix:
-            return OsMinix;
-        case ZigLLVM_RTEMS:
-            return OsRTEMS;
-        case ZigLLVM_NaCl:
-            return OsNaCl;
-        case ZigLLVM_CNK:
-            return OsCNK;
-        case ZigLLVM_AIX:
-            return OsAIX;
-        case ZigLLVM_CUDA:
-            return OsCUDA;
-        case ZigLLVM_NVCL:
-            return OsNVCL;
-        case ZigLLVM_AMDHSA:
-            return OsAMDHSA;
-        case ZigLLVM_PS4:
-            return OsPS4;
-        case ZigLLVM_ELFIAMCU:
-            return OsELFIAMCU;
-        case ZigLLVM_TvOS:
-            return OsTvOS;
-        case ZigLLVM_WatchOS:
-            return OsWatchOS;
-        case ZigLLVM_Mesa3D:
-            return OsMesa3D;
-        case ZigLLVM_Contiki:
-            return OsContiki;
-        case ZigLLVM_AMDPAL:
-            return OsAMDPAL;
-        case ZigLLVM_HermitCore:
-            return OsHermitCore;
-        case ZigLLVM_Hurd:
-            return OsHurd;
-        case ZigLLVM_WASI:
-            return OsWASI;
-        case ZigLLVM_Emscripten:
-            return OsEmscripten;
-    }
-    zig_unreachable();
-}
-
-static void get_native_target(ZigTarget *target) {
-    // first zero initialize
-    *target = {};
-
-    ZigLLVM_OSType os_type;
-    ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
-    ZigLLVMGetNativeTarget(
-            &target->arch,
-            &target->vendor,
-            &os_type,
-            &target->abi,
-            &oformat);
-    target->os = get_zig_os_type(os_type);
-    target->is_native_os = true;
-    target->is_native_cpu = true;
-    if (target->abi == ZigLLVM_UnknownEnvironment) {
-        target->abi = target_default_abi(target->arch, target->os);
-    }
-}
-
-Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
-        const char *dynamic_linker)
-{
-    Error err;
-
-    if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) {
-        zig_triple = nullptr;
-    }
-
-    if (zig_triple == nullptr) {
-        get_native_target(target);
-
-        if (mcpu == nullptr) {
-            target->llvm_cpu_name = ZigLLVMGetHostCPUName();
-            target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
-        } else if (strcmp(mcpu, "baseline") == 0) {
-            target->is_native_os = false;
-            target->is_native_cpu = false;
-            target->llvm_cpu_name = "";
-            target->llvm_cpu_features = "";
-        } else {
-            const char *msg = "stage0 can't handle CPU/features in the target";
-            stage2_panic(msg, strlen(msg));
-        }
-    } else {
-        // first initialize all to zero
-        *target = {};
-
-        SplitIterator it = memSplit(str(zig_triple), str("-"));
-
-        Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
-        Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it);
-        Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it);
-
-        if (!opt_archsub.is_some)
-            return ErrorMissingArchitecture;
-
-        if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) {
-            return err;
-        }
-
-        if (!opt_os.is_some)
-            return ErrorMissingOperatingSystem;
-
-        if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
-            return err;
-        }
-
-        if (opt_abi.is_some) {
-            if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) {
-                return err;
-            }
-        } else {
-            target->abi = target_default_abi(target->arch, target->os);
-        }
-
-        if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) {
-            const char *msg = "stage0 can't handle CPU/features in the target";
-            stage2_panic(msg, strlen(msg));
-        }
-    }
-
-    if (dynamic_linker != nullptr) {
-        target->dynamic_linker = dynamic_linker;
-    }
-
-    return ErrorNone;
-}
-
-const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len,
-        size_t *result_len)
-{
-    Error err;
-    Buf contents_buf = BUF_INIT;
-    Buf path_buf = BUF_INIT;
-
-    buf_init_from_mem(&path_buf, path_ptr, path_len);
-    if ((err = os_fetch_file_path(&path_buf, &contents_buf))) {
-        return nullptr;
-    }
-    *result_len = buf_len(&contents_buf);
-    return buf_ptr(&contents_buf);
-}
-
-const char *stage2_cimport(struct ZigStage1 *stage1) {
-    const char *msg = "stage0 called stage2_cimport";
-    stage2_panic(msg, strlen(msg));
-}
-
-const char *stage2_add_link_lib(struct ZigStage1 *stage1,
-        const char *lib_name_ptr, size_t lib_name_len,
-        const char *symbol_name_ptr, size_t symbol_name_len)
-{
-    return nullptr;
-}
src/stage2.h
@@ -130,23 +130,23 @@ struct Stage2ErrorMsg {
 ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len);
 
 // ABI warning
-ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void);
+ZIG_EXTERN_C struct Stage2Progress *stage2_progress_create(void);
 // ABI warning
-ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress);
+ZIG_EXTERN_C void stage2_progress_disable_tty(struct Stage2Progress *progress);
 // ABI warning
-ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress);
+ZIG_EXTERN_C void stage2_progress_destroy(struct Stage2Progress *progress);
 // ABI warning
-ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
+ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start_root(struct Stage2Progress *progress,
         const char *name_ptr, size_t name_len, size_t estimated_total_items);
 // ABI warning
-ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
+ZIG_EXTERN_C struct Stage2ProgressNode *stage2_progress_start(struct Stage2ProgressNode *node,
         const char *name_ptr, size_t name_len, size_t estimated_total_items);
 // ABI warning
-ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node);
+ZIG_EXTERN_C void stage2_progress_end(struct Stage2ProgressNode *node);
 // ABI warning
-ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node);
+ZIG_EXTERN_C void stage2_progress_complete_one(struct Stage2ProgressNode *node);
 // ABI warning
-ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node,
+ZIG_EXTERN_C void stage2_progress_update_node(struct Stage2ProgressNode *node,
         size_t completed_count, size_t estimated_total_items);
 
 // ABI warning
src/target.cpp
@@ -380,10 +380,6 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si
     return ErrorUnknownABI;
 }
 
-Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker) {
-    return stage2_target_parse(target, triple, mcpu, dynamic_linker);
-}
-
 const char *target_arch_name(ZigLLVM_ArchType arch) {
     return ZigLLVMGetArchTypeName(arch);
 }
@@ -408,7 +404,7 @@ void target_triple_llvm(Buf *triple, const ZigTarget *target) {
     buf_resize(triple, 0);
     buf_appendf(triple, "%s-%s-%s-%s",
             ZigLLVMGetArchTypeName(target->arch),
-            ZigLLVMGetVendorTypeName(target->vendor),
+            ZigLLVMGetVendorTypeName(ZigLLVM_UnknownVendor),
             ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)),
             ZigLLVMGetEnvironmentTypeName(target->abi));
 }
@@ -1149,7 +1145,6 @@ void target_libc_enum(size_t index, ZigTarget *out_target) {
     out_target->arch = libcs_available[index].arch;
     out_target->os = libcs_available[index].os;
     out_target->abi = libcs_available[index].abi;
-    out_target->vendor = ZigLLVM_UnknownVendor;
     out_target->is_native_os = false;
     out_target->is_native_cpu = false;
 }
src/target.hpp
@@ -25,7 +25,6 @@ enum CIntType {
     CIntTypeCount,
 };
 
-Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu, const char *dynamic_linker);
 Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len);
 Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
 Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);
src/zig0.cpp
@@ -14,6 +14,9 @@
 #include "stage2.h"
 #include "target.hpp"
 #include "error.hpp"
+#include "util.hpp"
+#include "buffer.hpp"
+#include "os.hpp"
 
 #include <stdio.h>
 #include <string.h>
@@ -33,7 +36,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
         "  --output-dir [dir]           override output directory (defaults to cwd)\n"
         "  --pkg-begin [name] [path]    make pkg available to import and push current pkg\n"
         "  --pkg-end                    pop current pkg\n"
-        "  --main-pkg-path              set the directory of the root package\n"
         "  --release-fast               build with optimizations on and safety off\n"
         "  --release-safe               build with optimizations on and safety on\n"
         "  --release-small              build with size optimizations on and safety off\n"
@@ -53,6 +55,170 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
     return return_code;
 }
 
+static Os get_zig_os_type(ZigLLVM_OSType os_type) {
+    switch (os_type) {
+        case ZigLLVM_UnknownOS:
+            return OsFreestanding;
+        case ZigLLVM_Ananas:
+            return OsAnanas;
+        case ZigLLVM_CloudABI:
+            return OsCloudABI;
+        case ZigLLVM_DragonFly:
+            return OsDragonFly;
+        case ZigLLVM_FreeBSD:
+            return OsFreeBSD;
+        case ZigLLVM_Fuchsia:
+            return OsFuchsia;
+        case ZigLLVM_IOS:
+            return OsIOS;
+        case ZigLLVM_KFreeBSD:
+            return OsKFreeBSD;
+        case ZigLLVM_Linux:
+            return OsLinux;
+        case ZigLLVM_Lv2:
+            return OsLv2;
+        case ZigLLVM_Darwin:
+        case ZigLLVM_MacOSX:
+            return OsMacOSX;
+        case ZigLLVM_NetBSD:
+            return OsNetBSD;
+        case ZigLLVM_OpenBSD:
+            return OsOpenBSD;
+        case ZigLLVM_Solaris:
+            return OsSolaris;
+        case ZigLLVM_Win32:
+            return OsWindows;
+        case ZigLLVM_Haiku:
+            return OsHaiku;
+        case ZigLLVM_Minix:
+            return OsMinix;
+        case ZigLLVM_RTEMS:
+            return OsRTEMS;
+        case ZigLLVM_NaCl:
+            return OsNaCl;
+        case ZigLLVM_CNK:
+            return OsCNK;
+        case ZigLLVM_AIX:
+            return OsAIX;
+        case ZigLLVM_CUDA:
+            return OsCUDA;
+        case ZigLLVM_NVCL:
+            return OsNVCL;
+        case ZigLLVM_AMDHSA:
+            return OsAMDHSA;
+        case ZigLLVM_PS4:
+            return OsPS4;
+        case ZigLLVM_ELFIAMCU:
+            return OsELFIAMCU;
+        case ZigLLVM_TvOS:
+            return OsTvOS;
+        case ZigLLVM_WatchOS:
+            return OsWatchOS;
+        case ZigLLVM_Mesa3D:
+            return OsMesa3D;
+        case ZigLLVM_Contiki:
+            return OsContiki;
+        case ZigLLVM_AMDPAL:
+            return OsAMDPAL;
+        case ZigLLVM_HermitCore:
+            return OsHermitCore;
+        case ZigLLVM_Hurd:
+            return OsHurd;
+        case ZigLLVM_WASI:
+            return OsWASI;
+        case ZigLLVM_Emscripten:
+            return OsEmscripten;
+    }
+    zig_unreachable();
+}
+
+static void get_native_target(ZigTarget *target) {
+    // first zero initialize
+    *target = {};
+
+    ZigLLVM_OSType os_type;
+    ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
+    ZigLLVM_VendorType trash;
+    ZigLLVMGetNativeTarget(
+            &target->arch,
+            &trash,
+            &os_type,
+            &target->abi,
+            &oformat);
+    target->os = get_zig_os_type(os_type);
+    target->is_native_os = true;
+    target->is_native_cpu = true;
+    if (target->abi == ZigLLVM_UnknownEnvironment) {
+        target->abi = target_default_abi(target->arch, target->os);
+    }
+}
+
+static Error target_parse_triple(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
+        const char *dynamic_linker)
+{
+    Error err;
+
+    if (zig_triple != nullptr && strcmp(zig_triple, "native") == 0) {
+        zig_triple = nullptr;
+    }
+
+    if (zig_triple == nullptr) {
+        get_native_target(target);
+
+        if (mcpu == nullptr) {
+            target->llvm_cpu_name = ZigLLVMGetHostCPUName();
+            target->llvm_cpu_features = ZigLLVMGetNativeFeatures();
+        } else if (strcmp(mcpu, "baseline") == 0) {
+            target->is_native_os = false;
+            target->is_native_cpu = false;
+            target->llvm_cpu_name = "";
+            target->llvm_cpu_features = "";
+        } else {
+            const char *msg = "stage0 can't handle CPU/features in the target";
+            stage2_panic(msg, strlen(msg));
+        }
+    } else {
+        // first initialize all to zero
+        *target = {};
+
+        SplitIterator it = memSplit(str(zig_triple), str("-"));
+
+        Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
+        Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it);
+        Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it);
+
+        if (!opt_archsub.is_some)
+            return ErrorMissingArchitecture;
+
+        if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) {
+            return err;
+        }
+
+        if (!opt_os.is_some)
+            return ErrorMissingOperatingSystem;
+
+        if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
+            return err;
+        }
+
+        if (opt_abi.is_some) {
+            if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) {
+                return err;
+            }
+        } else {
+            target->abi = target_default_abi(target->arch, target->os);
+        }
+
+        if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) {
+            const char *msg = "stage0 can't handle CPU/features in the target";
+            stage2_panic(msg, strlen(msg));
+        }
+    }
+
+    return ErrorNone;
+}
+
+
 static bool str_starts_with(const char *s1, const char *s2) {
     size_t s2_len = strlen(s2);
     if (strlen(s1) < s2_len) {
@@ -90,10 +256,9 @@ int main(int argc, char **argv) {
     bool link_libcpp = false;
     const char *target_string = nullptr;
     ZigStage1Pkg *cur_pkg = heap::c_allocator.create<ZigStage1Pkg>();
-    BuildMode build_mode = BuildModeDebug;
+    BuildMode optimize_mode = BuildModeDebug;
     TargetSubsystem subsystem = TargetSubsystemAuto;
     const char *override_lib_dir = nullptr;
-    const char *main_pkg_path = nullptr;
     const char *mcpu = nullptr;
 
     for (int i = 1; i < argc; i += 1) {
@@ -103,11 +268,11 @@ int main(int argc, char **argv) {
             if (strcmp(arg, "--") == 0) {
                 fprintf(stderr, "Unexpected end-of-parameter mark: %s\n", arg);
             } else if (strcmp(arg, "--release-fast") == 0) {
-                build_mode = BuildModeFastRelease;
+                optimize_mode = BuildModeFastRelease;
             } else if (strcmp(arg, "--release-safe") == 0) {
-                build_mode = BuildModeSafeRelease;
+                optimize_mode = BuildModeSafeRelease;
             } else if (strcmp(arg, "--release-small") == 0) {
-                build_mode = BuildModeSmallRelease;
+                optimize_mode = BuildModeSmallRelease;
             } else if (strcmp(arg, "--help") == 0) {
                 return print_full_usage(arg0, stdout, EXIT_SUCCESS);
             } else if (strcmp(arg, "--strip") == 0) {
@@ -183,8 +348,6 @@ int main(int argc, char **argv) {
                     dynamic_linker = argv[i];
                 } else if (strcmp(arg, "--override-lib-dir") == 0) {
                     override_lib_dir = argv[i];
-                } else if (strcmp(arg, "--main-pkg-path") == 0) {
-                    main_pkg_path = argv[i];
                 } else if (strcmp(arg, "--library") == 0 || strcmp(arg, "-l") == 0) {
                     if (strcmp(argv[i], "c") == 0) {
                         link_libc = true;
@@ -264,12 +427,13 @@ int main(int argc, char **argv) {
         return print_error_usage(arg0);
     }
 
-    ZigStage1 *stage1 = zig_stage1_create(build_mode,
-        main_pkg_path, (main_pkg_path == nullptr) ? 0 : strlen(main_pkg_path),
+    ZigStage1 *stage1 = zig_stage1_create(optimize_mode,
+        nullptr, 0,
         in_file, strlen(in_file),
-        override_lib_dir, strlen(override_lib_dir), &target, false,
-        root_progress_node);
+        override_lib_dir, strlen(override_lib_dir),
+        &target, false);
 
+    stage1->main_progress_node = root_progress_node;
     stage1->root_name_ptr = out_name;
     stage1->root_name_len = strlen(out_name);
     stage1->strip = strip;
@@ -295,3 +459,66 @@ int main(int argc, char **argv) {
 
     return main_exit(root_progress_node, EXIT_SUCCESS);
 }
+
+void stage2_panic(const char *ptr, size_t len) {
+    fwrite(ptr, 1, len, stderr);
+    fprintf(stderr, "\n");
+    fflush(stderr);
+    abort();
+}
+
+struct Stage2Progress {
+    int trash;
+};
+
+struct Stage2ProgressNode {
+    int trash;
+};
+
+Stage2Progress *stage2_progress_create(void) {
+    return nullptr;
+}
+
+void stage2_progress_destroy(Stage2Progress *progress) {}
+
+Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress,
+        const char *name_ptr, size_t name_len, size_t estimated_total_items)
+{
+    return nullptr;
+}
+Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node,
+        const char *name_ptr, size_t name_len, size_t estimated_total_items)
+{
+    return nullptr;
+}
+void stage2_progress_end(Stage2ProgressNode *node) {}
+void stage2_progress_complete_one(Stage2ProgressNode *node) {}
+void stage2_progress_disable_tty(Stage2Progress *progress) {}
+void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){}
+
+const char *stage2_fetch_file(struct ZigStage1 *stage1, const char *path_ptr, size_t path_len,
+        size_t *result_len)
+{
+    Error err;
+    Buf contents_buf = BUF_INIT;
+    Buf path_buf = BUF_INIT;
+
+    buf_init_from_mem(&path_buf, path_ptr, path_len);
+    if ((err = os_fetch_file_path(&path_buf, &contents_buf))) {
+        return nullptr;
+    }
+    *result_len = buf_len(&contents_buf);
+    return buf_ptr(&contents_buf);
+}
+
+const char *stage2_cimport(struct ZigStage1 *stage1) {
+    const char *msg = "stage0 called stage2_cimport";
+    stage2_panic(msg, strlen(msg));
+}
+
+const char *stage2_add_link_lib(struct ZigStage1 *stage1,
+        const char *lib_name_ptr, size_t lib_name_len,
+        const char *symbol_name_ptr, size_t symbol_name_len)
+{
+    return nullptr;
+}
src-self-hosted/link/Elf.zig
@@ -1222,13 +1222,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
     // If there is no Zig code to compile, then we should skip flushing the output file because it
     // will not be part of the linker line anyway.
     const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
-        try self.flushModule(comp);
+        const use_stage1 = build_options.is_stage1 and self.base.options.use_llvm;
+        if (use_stage1) {
+            const obj_basename = try std.fmt.allocPrint(arena, "{}.o", .{self.base.options.root_name});
+            const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
+            break :blk full_obj_path;
+        }
 
+        try self.flushModule(comp);
         const obj_basename = self.base.intermediary_basename.?;
-        const full_obj_path = if (directory.path) |dir_path|
-            try std.fs.path.join(arena, &[_][]const u8{dir_path, obj_basename})
-        else 
-            obj_basename;
+        const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
         break :blk full_obj_path;
     } else null;
 
@@ -1504,7 +1507,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
         // (the check for that needs to be earlier), but they could be full paths to .so files, in which
         // case we want to avoid prepending "-l".
         const ext = Compilation.classifyFileExt(link_lib);
-        const arg = if (ext == .so) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
+        const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{}", .{link_lib});
         argv.appendAssumeCapacity(arg);
     }
 
src-self-hosted/Compilation.zig
@@ -19,6 +19,7 @@ const libunwind = @import("libunwind.zig");
 const fatal = @import("main.zig").fatal;
 const Module = @import("Module.zig");
 const Cache = @import("Cache.zig");
+const stage1 = @import("stage1.zig");
 
 /// General-purpose allocator. Used for both temporary and long-term storage.
 gpa: *Allocator,
@@ -26,6 +27,7 @@ gpa: *Allocator,
 arena_state: std.heap.ArenaAllocator.State,
 bin_file: *link.File,
 c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
+stage1_module: ?*stage1.Module,
 
 link_error_flags: link.File.ErrorFlags = .{},
 
@@ -122,6 +124,8 @@ const Job = union(enum) {
 
     /// Generate builtin.zig source code and write it into the correct place.
     generate_builtin_zig: void,
+    /// Use stage1 C++ code to compile zig code into an object file.
+    stage1_module: void,
 };
 
 pub const CObject = struct {
@@ -274,6 +278,7 @@ pub const InitOptions = struct {
     strip: bool = false,
     single_threaded: bool = false,
     is_native_os: bool,
+    time_report: bool = false,
     link_eh_frame_hdr: bool = false,
     linker_script: ?[]const u8 = null,
     version_script: ?[]const u8 = null,
@@ -288,12 +293,20 @@ pub const InitOptions = struct {
     clang_passthrough_mode: bool = false,
     verbose_cc: bool = false,
     verbose_link: bool = false,
+    verbose_tokenize: bool = false,
+    verbose_ast: bool = false,
+    verbose_ir: bool = false,
+    verbose_llvm_ir: bool = false,
+    verbose_cimport: bool = false,
+    verbose_llvm_cpu_features: bool = false,
     is_test: bool = false,
     stack_size_override: ?u64 = null,
     self_exe_path: ?[]const u8 = null,
     version: ?std.builtin.Version = null,
     libc_installation: ?*const LibCInstallation = null,
     machine_code_model: std.builtin.CodeModel = .default,
+    /// This is for stage1 and should be deleted upon completion of self-hosting.
+    color: @import("main.zig").Color = .Auto,
 };
 
 pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
@@ -332,11 +345,27 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             {
                 break :blk true;
             }
+
+            if (build_options.is_stage1) {
+                // If stage1 generates an object file, self-hosted linker is not
+                // yet sophisticated enough to handle that.
+                break :blk options.root_pkg != null;
+            }
+
             break :blk false;
         };
 
         // Make a decision on whether to use LLVM or our own backend.
         const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
+            // If we have no zig code to compile, no need for LLVM.
+            if (options.root_pkg == null)
+                break :blk false;
+
+            // If we are the stage1 compiler, we depend on the stage1 c++ llvm backend
+            // to compile zig code.
+            if (build_options.is_stage1)
+                break :blk true;
+
             // We would want to prefer LLVM for release builds when it is available, however
             // we don't have an LLVM backend yet :)
             // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
@@ -580,6 +609,118 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .ReleaseFast, .ReleaseSmall => false,
         };
 
+        const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
+            var buf = std.ArrayList(u8).init(arena);
+            for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| {
+                const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
+                const is_enabled = options.target.cpu.features.isEnabled(index);
+
+                if (feature.llvm_name) |llvm_name| {
+                    const plus_or_minus = "-+"[@boolToInt(is_enabled)];
+                    try buf.ensureCapacity(buf.items.len + 2 + llvm_name.len);
+                    buf.appendAssumeCapacity(plus_or_minus);
+                    buf.appendSliceAssumeCapacity(llvm_name);
+                    buf.appendSliceAssumeCapacity(",");
+                }
+            }
+            assert(mem.endsWith(u8, buf.items, ","));
+            buf.items[buf.items.len - 1] = 0;
+            buf.shrink(buf.items.len);
+            break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
+        } else null;
+
+        const stage1_module: ?*stage1.Module = if (build_options.is_stage1 and use_llvm) blk: {
+            // Here we use the legacy stage1 C++ compiler to compile Zig code.
+            const stage2_target = try arena.create(stage1.Stage2Target);
+            stage2_target.* = .{
+                .arch = @enumToInt(options.target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
+                .os = @enumToInt(options.target.os.tag),
+                .abi = @enumToInt(options.target.abi),
+                .is_native_os = options.is_native_os,
+                .is_native_cpu = false, // Only true when bootstrapping the compiler.
+                .llvm_cpu_name = if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
+                .llvm_cpu_features = llvm_cpu_features.?,
+            };
+            const progress = try arena.create(std.Progress);
+            const main_progress_node = try progress.start("", 100);
+            if (options.color == .Off) progress.terminal = null;
+
+            const mod = module.?;
+            const main_zig_file = mod.root_pkg.root_src_path;
+            const zig_lib_dir = options.zig_lib_directory.path.?;
+            const builtin_sub = &[_][]const u8{"builtin.zig"};
+            const builtin_zig_path = try mod.zig_cache_artifact_directory.join(arena, builtin_sub);
+
+            const stage1_module = stage1.create(
+                @enumToInt(options.optimize_mode),
+                undefined,
+                0, // TODO --main-pkg-path
+                main_zig_file.ptr,
+                main_zig_file.len,
+                zig_lib_dir.ptr,
+                zig_lib_dir.len,
+                stage2_target,
+                options.is_test,
+            ) orelse return error.OutOfMemory;
+
+            const output_dir = bin_directory.path orelse ".";
+
+            const stage1_pkg = try arena.create(stage1.Pkg);
+            stage1_pkg.* = .{
+                .name_ptr = undefined,
+                .name_len = 0,
+                .path_ptr = undefined,
+                .path_len = 0,
+                .children_ptr = undefined,
+                .children_len = 0,
+                .parent = null,
+            };
+
+            stage1_module.* = .{
+                .root_name_ptr = root_name.ptr,
+                .root_name_len = root_name.len,
+                .output_dir_ptr = output_dir.ptr,
+                .output_dir_len = output_dir.len,
+                .builtin_zig_path_ptr = builtin_zig_path.ptr,
+                .builtin_zig_path_len = builtin_zig_path.len,
+                .test_filter_ptr = "",
+                .test_filter_len = 0,
+                .test_name_prefix_ptr = "",
+                .test_name_prefix_len = 0,
+                .userdata = @ptrToInt(comp),
+                .root_pkg = stage1_pkg,
+                .code_model = @enumToInt(options.machine_code_model),
+                .subsystem = stage1.TargetSubsystem.Auto,
+                .err_color = @enumToInt(options.color),
+                .pic = pic,
+                .link_libc = options.link_libc,
+                .link_libcpp = options.link_libcpp,
+                .strip = options.strip,
+                .is_single_threaded = single_threaded,
+                .dll_export_fns = dll_export_fns,
+                .link_mode_dynamic = link_mode == .Dynamic,
+                .valgrind_enabled = valgrind,
+                .function_sections = options.function_sections orelse false,
+                .enable_stack_probing = stack_check,
+                .enable_time_report = options.time_report,
+                .enable_stack_report = false,
+                .dump_analysis = false,
+                .enable_doc_generation = false,
+                .emit_bin = true,
+                .emit_asm = false,
+                .emit_llvm_ir = false,
+                .test_is_evented = false,
+                .verbose_tokenize = options.verbose_tokenize,
+                .verbose_ast = options.verbose_ast,
+                .verbose_ir = options.verbose_ir,
+                .verbose_llvm_ir = options.verbose_llvm_ir,
+                .verbose_cimport = options.verbose_cimport,
+                .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
+                .main_progress_node = main_progress_node,
+            };
+            break :blk stage1_module;
+        } else null;
+
         const bin_file = try link.File.openPath(gpa, .{
             .directory = bin_directory,
             .sub_path = emit_bin.basename,
@@ -626,6 +767,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .machine_code_model = options.machine_code_model,
             .dll_export_fns = dll_export_fns,
             .error_return_tracing = error_return_tracing,
+            .llvm_cpu_features = llvm_cpu_features,
         });
         errdefer bin_file.destroy();
 
@@ -635,6 +777,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .zig_lib_directory = options.zig_lib_directory,
             .zig_cache_directory = options.zig_cache_directory,
             .bin_file = bin_file,
+            .stage1_module = stage1_module,
             .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
             .keep_source_files_loaded = options.keep_source_files_loaded,
             .use_clang = use_clang,
@@ -681,6 +824,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
         try comp.work_queue.writeItem(.{ .libunwind = {} });
     }
 
+    if (comp.stage1_module) |module| {
+        try comp.work_queue.writeItem(.{ .stage1_module = {} });
+    }
+
     return comp;
 }
 
@@ -689,6 +836,11 @@ pub fn destroy(self: *Compilation) void {
     self.bin_file.destroy();
     if (optional_module) |module| module.deinit();
 
+    if (self.stage1_module) |module| {
+        module.main_progress_node.?.end();
+        module.destroy();
+    }
+
     const gpa = self.gpa;
     self.work_queue.deinit();
 
@@ -997,6 +1149,10 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
                 fatal("unable to update builtin.zig file: {}", .{@errorName(err)});
             };
         },
+        .stage1_module => {
+            // This Job is only queued up if there is a zig module.
+            self.stage1_module.?.build_object();
+        },
     };
 }
 
@@ -1365,7 +1521,7 @@ pub fn addCCArgs(
                 try argv.append("-fPIC");
             }
         },
-        .so, .assembly, .ll, .bc, .unknown => {},
+        .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig, .zir => {},
     }
     if (out_dep_path) |p| {
         try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
@@ -1445,17 +1601,39 @@ pub const FileExt = enum {
     ll,
     bc,
     assembly,
-    so,
+    shared_library,
+    object,
+    static_library,
+    zig,
+    zir,
     unknown,
 
     pub fn clangSupportsDepFile(ext: FileExt) bool {
         return switch (ext) {
             .c, .cpp, .h => true,
-            .ll, .bc, .assembly, .so, .unknown => false,
+
+            .ll,
+            .bc,
+            .assembly,
+            .shared_library,
+            .object,
+            .static_library,
+            .zig,
+            .zir,
+            .unknown,
+            => false,
         };
     }
 };
 
+pub fn hasObjectExt(filename: []const u8) bool {
+    return mem.endsWith(u8, filename, ".o") or mem.endsWith(u8, filename, ".obj");
+}
+
+pub fn hasStaticLibraryExt(filename: []const u8) bool {
+    return mem.endsWith(u8, filename, ".a") or mem.endsWith(u8, filename, ".lib");
+}
+
 pub fn hasCExt(filename: []const u8) bool {
     return mem.endsWith(u8, filename, ".c");
 }
@@ -1471,6 +1649,32 @@ pub fn hasAsmExt(filename: []const u8) bool {
     return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
 }
 
+pub fn hasSharedLibraryExt(filename: []const u8) bool {
+    if (mem.endsWith(u8, filename, ".so") or
+        mem.endsWith(u8, filename, ".dll") or
+        mem.endsWith(u8, filename, ".dylib"))
+    {
+        return true;
+    }
+    // Look for .so.X, .so.X.Y, .so.X.Y.Z
+    var it = mem.split(filename, ".");
+    _ = it.next().?;
+    var so_txt = it.next() orelse return false;
+    while (!mem.eql(u8, so_txt, "so")) {
+        so_txt = it.next() orelse return false;
+    }
+    const n1 = it.next() orelse return false;
+    const n2 = it.next();
+    const n3 = it.next();
+
+    _ = std.fmt.parseInt(u32, n1, 10) catch return false;
+    if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
+    if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
+    if (it.next() != null) return false;
+
+    return true;
+}
+
 pub fn classifyFileExt(filename: []const u8) FileExt {
     if (hasCExt(filename)) {
         return .c;
@@ -1484,26 +1688,19 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
         return .assembly;
     } else if (mem.endsWith(u8, filename, ".h")) {
         return .h;
-    } else if (mem.endsWith(u8, filename, ".so")) {
-        return .so;
-    }
-    // Look for .so.X, .so.X.Y, .so.X.Y.Z
-    var it = mem.split(filename, ".");
-    _ = it.next().?;
-    var so_txt = it.next() orelse return .unknown;
-    while (!mem.eql(u8, so_txt, "so")) {
-        so_txt = it.next() orelse return .unknown;
+    } else if (mem.endsWith(u8, filename, ".zig")) {
+        return .zig;
+    } else if (mem.endsWith(u8, filename, ".zir")) {
+        return .zig;
+    } else if (hasSharedLibraryExt(filename)) {
+        return .shared_library;
+    } else if (hasStaticLibraryExt(filename)) {
+        return .static_library;
+    } else if (hasObjectExt(filename)) {
+        return .object;
+    } else {
+        return .unknown;
     }
-    const n1 = it.next() orelse return .unknown;
-    const n2 = it.next();
-    const n3 = it.next();
-
-    _ = std.fmt.parseInt(u32, n1, 10) catch return .unknown;
-    if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown;
-    if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return .unknown;
-    if (it.next() != null) return .unknown;
-
-    return .so;
 }
 
 test "classifyFileExt" {
@@ -1681,7 +1878,7 @@ pub fn dump_argv(argv: []const []const u8) void {
 }
 
 pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {
-    var buffer = std.ArrayList(u8).init(comp.gpa);
+    var buffer = std.ArrayList(u8).init(allocator);
     defer buffer.deinit();
 
     const target = comp.getTarget();
@@ -1691,9 +1888,9 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
     try buffer.writer().print(
         \\usingnamespace @import("std").builtin;
         \\/// Deprecated
-        \\pub const arch = std.Target.current.cpu.arch;
+        \\pub const arch = Target.current.cpu.arch;
         \\/// Deprecated
-        \\pub const endian = std.Target.current.cpu.arch.endian();
+        \\pub const endian = Target.current.cpu.arch.endian();
         \\pub const output_mode = OutputMode.{};
         \\pub const link_mode = LinkMode.{};
         \\pub const is_test = {};
src-self-hosted/link.zig
@@ -69,6 +69,7 @@ pub const Options = struct {
     linker_script: ?[]const u8 = null,
     version_script: ?[]const u8 = null,
     override_soname: ?[]const u8 = null,
+    llvm_cpu_features: ?[*:0]const u8 = null,
     /// Extra args passed directly to LLD. Ignored when not linking with LLD.
     extra_lld_args: []const []const u8 = &[0][]const u8,
 
@@ -134,6 +135,18 @@ pub const File = struct {
     /// rewriting it. A malicious file is detected as incremental link failure
     /// and does not cause Illegal Behavior. This operation is not atomic.
     pub fn openPath(allocator: *Allocator, options: Options) !*File {
+        const use_stage1 = build_options.is_stage1 and options.use_llvm;
+        if (use_stage1) {
+            return switch (options.object_format) {
+                .coff, .pe => &(try Coff.createEmpty(allocator, options)).base,
+                .elf => &(try Elf.createEmpty(allocator, options)).base,
+                .macho => &(try MachO.createEmpty(allocator, options)).base,
+                .wasm => &(try Wasm.createEmpty(allocator, options)).base,
+                .c => unreachable, // Reported error earlier.
+                .hex => return error.HexObjectFormatUnimplemented,
+                .raw => return error.RawObjectFormatUnimplemented,
+            };
+        }
         const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm
         const sub_path = if (use_lld) blk: {
             if (options.module == null) {
src-self-hosted/main.zig
@@ -222,21 +222,27 @@ const usage_build_generic =
     \\  --libc [file]             Provide a file which specifies libc paths
     \\
     \\Link Options:
-    \\  -l[lib], --library [lib]  Link against system library
+    \\  -l[lib], --library [lib]       Link against system library
     \\  -L[d], --library-directory [d] Add a directory to the library search path
-    \\  -T[script]                Use a custom linker script
-    \\  --dynamic-linker [path]   Set the dynamic interpreter path (usually ld.so)
-    \\  --version [ver]           Dynamic library semver
-    \\  -rdynamic                 Add all symbols to the dynamic symbol table
-    \\  -rpath [path]             Add directory to the runtime library search path
-    \\  --eh-frame-hdr            Enable C++ exception handling by passing --eh-frame-hdr to linker
-    \\  -dynamic                  Force output to be dynamically linked
-    \\  -static                   Force output to be statically linked
+    \\  -T[script]                     Use a custom linker script
+    \\  --dynamic-linker [path]        Set the dynamic interpreter path (usually ld.so)
+    \\  --version [ver]                Dynamic library semver
+    \\  -rdynamic                      Add all symbols to the dynamic symbol table
+    \\  -rpath [path]                  Add directory to the runtime library search path
+    \\  --eh-frame-hdr                 Enable C++ exception handling by passing --eh-frame-hdr to linker
+    \\  -dynamic                       Force output to be dynamically linked
+    \\  -static                        Force output to be statically linked
     \\
     \\Debug Options (Zig Compiler Development):
-    \\  -ftime-report             Print timing diagnostics
-    \\  --verbose-link            Display linker invocations
-    \\  --verbose-cc              Display C compiler invocations
+    \\  -ftime-report                Print timing diagnostics
+    \\  --verbose-link               Display linker invocations
+    \\  --verbose-cc                 Display C compiler invocations
+    \\  --verbose-tokenize           Enable compiler debug output for tokenization
+    \\  --verbose-ast                Enable compiler debug output for AST parsing
+    \\  --verbose-ir                 Enable compiler debug output for Zig IR
+    \\  --verbose-llvm-ir            Enable compiler debug output for LLVM IR
+    \\  --verbose-cimport            Enable compiler debug output for C imports
+    \\  --verbose-llvm-cpu-features  Enable compiler debug output for LLVM CPU features
     \\
 ;
 
@@ -278,6 +284,12 @@ pub fn buildOutputType(
     var watch = false;
     var verbose_link = false;
     var verbose_cc = false;
+    var verbose_tokenize = false;
+    var verbose_ast = false;
+    var verbose_ir = false;
+    var verbose_llvm_ir = false;
+    var verbose_cimport = false;
+    var verbose_llvm_cpu_features = false;
     var time_report = false;
     var show_builtin = false;
     var emit_bin: Emit = .yes_default_path;
@@ -548,6 +560,18 @@ pub fn buildOutputType(
                     verbose_link = true;
                 } else if (mem.eql(u8, arg, "--verbose-cc")) {
                     verbose_cc = true;
+                } else if (mem.eql(u8, arg, "--verbose-tokenize")) {
+                    verbose_tokenize = true;
+                } else if (mem.eql(u8, arg, "--verbose-ast")) {
+                    verbose_ast = 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, "--verbose-llvm-cpu-features")) {
+                    verbose_llvm_cpu_features = true;
                 } else if (mem.startsWith(u8, arg, "-T")) {
                     linker_script = arg[2..];
                 } else if (mem.startsWith(u8, arg, "-L")) {
@@ -563,28 +587,27 @@ pub fn buildOutputType(
                 } else {
                     fatal("unrecognized parameter: '{}'", .{arg});
                 }
-            } else if (mem.endsWith(u8, arg, ".o") or
-                mem.endsWith(u8, arg, ".obj") or
-                mem.endsWith(u8, arg, ".a") or
-                mem.endsWith(u8, arg, ".lib"))
-            {
-                try link_objects.append(arg);
-            } else if (Compilation.hasAsmExt(arg) or Compilation.hasCExt(arg) or Compilation.hasCppExt(arg)) {
-                // TODO a way to pass extra flags on the CLI
-                try c_source_files.append(.{ .src_path = arg });
-            } else if (mem.endsWith(u8, arg, ".so") or
-                mem.endsWith(u8, arg, ".dylib") or
-                mem.endsWith(u8, arg, ".dll"))
-            {
-                fatal("linking against dynamic libraries not yet supported", .{});
-            } else if (mem.endsWith(u8, arg, ".zig") or mem.endsWith(u8, arg, ".zir")) {
-                if (root_src_file) |other| {
-                    fatal("found another zig file '{}' after root source file '{}'", .{ arg, other });
-                } else {
-                    root_src_file = arg;
-                }
-            } else {
-                fatal("unrecognized file extension of parameter '{}'", .{arg});
+            } else switch (Compilation.classifyFileExt(arg)) {
+                .object, .static_library => {
+                    try link_objects.append(arg);
+                },
+                .assembly, .c, .cpp, .h, .ll, .bc => {
+                    // TODO a way to pass extra flags on the CLI
+                    try c_source_files.append(.{ .src_path = arg });
+                },
+                .shared_library => {
+                    fatal("linking against dynamic libraries not yet supported", .{});
+                },
+                .zig, .zir => {
+                    if (root_src_file) |other| {
+                        fatal("found another zig file '{}' after root source file '{}'", .{ arg, other });
+                    } else {
+                        root_src_file = arg;
+                    }
+                },
+                .unknown => {
+                    fatal("unrecognized file extension of parameter '{}'", .{arg});
+                },
             }
         }
     } else {
@@ -617,7 +640,16 @@ pub fn buildOutputType(
                     const file_ext = Compilation.classifyFileExt(mem.spanZ(it.only_arg));
                     switch (file_ext) {
                         .assembly, .c, .cpp, .ll, .bc, .h => try c_source_files.append(.{ .src_path = it.only_arg }),
-                        .unknown, .so => try link_objects.append(it.only_arg),
+                        .unknown, .shared_library, .object, .static_library => {
+                            try link_objects.append(it.only_arg);
+                        },
+                        .zig, .zir => {
+                            if (root_src_file) |other| {
+                                fatal("found another zig file '{}' after root source file '{}'", .{ it.only_arg, other });
+                            } else {
+                                root_src_file = it.only_arg;
+                            }
+                        },
                     }
                 },
                 .l => {
@@ -1173,7 +1205,15 @@ pub fn buildOutputType(
         .libc_installation = if (libc_installation) |*lci| lci else null,
         .verbose_cc = verbose_cc,
         .verbose_link = verbose_link,
+        .verbose_tokenize = verbose_tokenize,
+        .verbose_ast = verbose_ast,
+        .verbose_ir = verbose_ir,
+        .verbose_llvm_ir = verbose_llvm_ir,
+        .verbose_cimport = verbose_cimport,
+        .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
         .machine_code_model = machine_code_model,
+        .color = color,
+        .time_report = time_report,
     }) catch |err| {
         fatal("unable to create compilation: {}", .{@errorName(err)});
     };
@@ -1193,6 +1233,10 @@ pub fn buildOutputType(
         fatal("TODO: implement `zig cc` when using it as a preprocessor", .{});
     }
 
+    if (build_options.is_stage1 and comp.stage1_module != null and watch) {
+        std.log.warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{});
+    }
+
     const stdin = std.io.getStdIn().inStream();
     const stderr = std.io.getStdErr().outStream();
     var repl_buf: [1024]u8 = undefined;
src-self-hosted/stage1.zig
@@ -10,6 +10,7 @@ const stage2 = @import("main.zig");
 const fatal = stage2.fatal;
 const CrossTarget = std.zig.CrossTarget;
 const Target = std.Target;
+const Compilation = @import("Compilation.zig");
 
 comptime {
     assert(std.builtin.link_libc);
@@ -23,6 +24,8 @@ pub const log_level = stage2.log_level;
 pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int {
     std.debug.maybeEnableSegfaultHandler();
 
+    zig_stage1_os_init();
+
     const gpa = std.heap.c_allocator;
     var arena_instance = std.heap.ArenaAllocator.init(gpa);
     defer arena_instance.deinit();
@@ -36,6 +39,106 @@ pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int {
     return 0;
 }
 
+/// Matches stage2.Color;
+pub const ErrColor = c_int;
+/// Matches std.builtin.CodeModel
+pub const CodeModel = c_int;
+/// Matches std.Target.Os.Tag
+pub const OS = c_int;
+/// Matches std.builtin.BuildMode
+pub const BuildMode = c_int;
+
+pub const TargetSubsystem = extern enum(c_int) {
+    Console,
+    Windows,
+    Posix,
+    Native,
+    EfiApplication,
+    EfiBootServiceDriver,
+    EfiRom,
+    EfiRuntimeDriver,
+    Auto,
+};
+
+pub const Pkg = extern struct {
+    name_ptr: [*]const u8,
+    name_len: usize,
+    path_ptr: [*]const u8,
+    path_len: usize,
+    children_ptr: [*]*Pkg,
+    children_len: usize,
+    parent: ?*Pkg,
+};
+
+pub const Module = extern struct {
+    root_name_ptr: [*]const u8,
+    root_name_len: usize,
+    output_dir_ptr: [*]const u8,
+    output_dir_len: usize,
+    builtin_zig_path_ptr: [*]const u8,
+    builtin_zig_path_len: usize,
+    test_filter_ptr: [*]const u8,
+    test_filter_len: usize,
+    test_name_prefix_ptr: [*]const u8,
+    test_name_prefix_len: usize,
+    userdata: usize,
+    root_pkg: *Pkg,
+    main_progress_node: ?*std.Progress.Node,
+    code_model: CodeModel,
+    subsystem: TargetSubsystem,
+    err_color: ErrColor,
+    pic: bool,
+    link_libc: bool,
+    link_libcpp: bool,
+    strip: bool,
+    is_single_threaded: bool,
+    dll_export_fns: bool,
+    link_mode_dynamic: bool,
+    valgrind_enabled: bool,
+    function_sections: bool,
+    enable_stack_probing: bool,
+    enable_time_report: bool,
+    enable_stack_report: bool,
+    dump_analysis: bool,
+    enable_doc_generation: bool,
+    emit_bin: bool,
+    emit_asm: bool,
+    emit_llvm_ir: bool,
+    test_is_evented: bool,
+    verbose_tokenize: bool,
+    verbose_ast: bool,
+    verbose_ir: bool,
+    verbose_llvm_ir: bool,
+    verbose_cimport: bool,
+    verbose_llvm_cpu_features: bool,
+
+    pub fn build_object(mod: *Module) void {
+        zig_stage1_build_object(mod);
+    }
+
+    pub fn destroy(mod: *Module) void {
+        zig_stage1_destroy(mod);
+    }
+};
+
+extern fn zig_stage1_os_init() void;
+
+pub const create = zig_stage1_create;
+extern fn zig_stage1_create(
+    optimize_mode: BuildMode,
+    main_pkg_path_ptr: [*]const u8,
+    main_pkg_path_len: usize,
+    root_src_path_ptr: [*]const u8,
+    root_src_path_len: usize,
+    zig_lib_dir_ptr: [*c]const u8,
+    zig_lib_dir_len: usize,
+    target: [*c]const Stage2Target,
+    is_test_build: bool,
+) ?*Module;
+
+extern fn zig_stage1_build_object(*Module) void;
+extern fn zig_stage1_destroy(*Module) void;
+
 // ABI warning
 export fn stage2_panic(ptr: [*]const u8, len: usize) void {
     @panic(ptr[0..len]);
@@ -199,297 +302,50 @@ export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usiz
 }
 
 // ABI warning
-const Stage2Target = extern struct {
+pub const Stage2Target = extern struct {
     arch: c_int,
-    vendor: c_int,
-
+    os: OS,
     abi: c_int,
-    os: c_int,
 
     is_native_os: bool,
     is_native_cpu: bool,
 
     llvm_cpu_name: ?[*:0]const u8,
     llvm_cpu_features: ?[*:0]const u8,
-    cpu_builtin_str: ?[*:0]const u8,
-    os_builtin_str: ?[*:0]const u8,
-
-    dynamic_linker: ?[*:0]const u8,
-
-    llvm_cpu_features_asm_ptr: [*]const [*:0]const u8,
-    llvm_cpu_features_asm_len: usize,
-
-    fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
-        const allocator = std.heap.c_allocator;
-
-        var dynamic_linker: ?[*:0]u8 = null;
-        const target = try crossTargetToTarget(cross_target, &dynamic_linker);
-
-        const generic_arch_name = target.cpu.arch.genericName();
-        var cpu_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
-            \\Cpu{{
-            \\    .arch = .{},
-            \\    .model = &Target.{}.cpu.{},
-            \\    .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
-            \\
-        , .{
-            @tagName(target.cpu.arch),
-            generic_arch_name,
-            target.cpu.model.name,
-            generic_arch_name,
-            generic_arch_name,
-        });
-        defer cpu_builtin_str_buffer.deinit();
-
-        var llvm_features_buffer = try std.ArrayListSentineled(u8, 0).initSize(allocator, 0);
-        defer llvm_features_buffer.deinit();
-
-        // Unfortunately we have to do the work twice, because Clang does not support
-        // the same command line parameters for CPU features when assembling code as it does
-        // when compiling C code.
-        var asm_features_list = std.ArrayList([*:0]const u8).init(allocator);
-        defer asm_features_list.deinit();
-
-        for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
-            const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
-            const is_enabled = target.cpu.features.isEnabled(index);
-
-            if (feature.llvm_name) |llvm_name| {
-                const plus_or_minus = "-+"[@boolToInt(is_enabled)];
-                try llvm_features_buffer.append(plus_or_minus);
-                try llvm_features_buffer.appendSlice(llvm_name);
-                try llvm_features_buffer.appendSlice(",");
-            }
-
-            if (is_enabled) {
-                // TODO some kind of "zig identifier escape" function rather than
-                // unconditionally using @"" syntax
-                try cpu_builtin_str_buffer.appendSlice("        .@\"");
-                try cpu_builtin_str_buffer.appendSlice(feature.name);
-                try cpu_builtin_str_buffer.appendSlice("\",\n");
-            }
-        }
-
-        switch (target.cpu.arch) {
-            .riscv32, .riscv64 => {
-                if (Target.riscv.featureSetHas(target.cpu.features, .relax)) {
-                    try asm_features_list.append("-mrelax");
-                } else {
-                    try asm_features_list.append("-mno-relax");
-                }
-            },
-            else => {
-                // TODO
-                // Argh, why doesn't the assembler accept the list of CPU features?!
-                // I don't see a way to do this other than hard coding everything.
-            },
-        }
-
-        try cpu_builtin_str_buffer.appendSlice(
-            \\    }),
-            \\};
-            \\
-        );
-
-        assert(mem.endsWith(u8, llvm_features_buffer.span(), ","));
-        llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
-
-        var os_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
-            \\Os{{
-            \\    .tag = .{},
-            \\    .version_range = .{{
-        , .{@tagName(target.os.tag)});
-        defer os_builtin_str_buffer.deinit();
-
-        // We'll re-use the OS version range builtin string for the cache hash.
-        const os_builtin_str_ver_start_index = os_builtin_str_buffer.len();
-
-        @setEvalBranchQuota(2000);
-        switch (target.os.tag) {
-            .freestanding,
-            .ananas,
-            .cloudabi,
-            .dragonfly,
-            .fuchsia,
-            .ios,
-            .kfreebsd,
-            .lv2,
-            .solaris,
-            .haiku,
-            .minix,
-            .rtems,
-            .nacl,
-            .cnk,
-            .aix,
-            .cuda,
-            .nvcl,
-            .amdhsa,
-            .ps4,
-            .elfiamcu,
-            .tvos,
-            .watchos,
-            .mesa3d,
-            .contiki,
-            .amdpal,
-            .hermit,
-            .hurd,
-            .wasi,
-            .emscripten,
-            .uefi,
-            .other,
-            => try os_builtin_str_buffer.appendSlice(" .none = {} }\n"),
-
-            .freebsd,
-            .macosx,
-            .netbsd,
-            .openbsd,
-            => try os_builtin_str_buffer.outStream().print(
-                \\ .semver = .{{
-                \\        .min = .{{
-                \\            .major = {},
-                \\            .minor = {},
-                \\            .patch = {},
-                \\        }},
-                \\        .max = .{{
-                \\            .major = {},
-                \\            .minor = {},
-                \\            .patch = {},
-                \\        }},
-                \\    }}}},
-                \\
-            , .{
-                target.os.version_range.semver.min.major,
-                target.os.version_range.semver.min.minor,
-                target.os.version_range.semver.min.patch,
-
-                target.os.version_range.semver.max.major,
-                target.os.version_range.semver.max.minor,
-                target.os.version_range.semver.max.patch,
-            }),
-
-            .linux => try os_builtin_str_buffer.outStream().print(
-                \\ .linux = .{{
-                \\        .range = .{{
-                \\            .min = .{{
-                \\                .major = {},
-                \\                .minor = {},
-                \\                .patch = {},
-                \\            }},
-                \\            .max = .{{
-                \\                .major = {},
-                \\                .minor = {},
-                \\                .patch = {},
-                \\            }},
-                \\        }},
-                \\        .glibc = .{{
-                \\            .major = {},
-                \\            .minor = {},
-                \\            .patch = {},
-                \\        }},
-                \\    }}}},
-                \\
-            , .{
-                target.os.version_range.linux.range.min.major,
-                target.os.version_range.linux.range.min.minor,
-                target.os.version_range.linux.range.min.patch,
-
-                target.os.version_range.linux.range.max.major,
-                target.os.version_range.linux.range.max.minor,
-                target.os.version_range.linux.range.max.patch,
-
-                target.os.version_range.linux.glibc.major,
-                target.os.version_range.linux.glibc.minor,
-                target.os.version_range.linux.glibc.patch,
-            }),
-
-            .windows => try os_builtin_str_buffer.outStream().print(
-                \\ .windows = .{{
-                \\        .min = {s},
-                \\        .max = {s},
-                \\    }}}},
-                \\
-            , .{
-                target.os.version_range.windows.min,
-                target.os.version_range.windows.max,
-            }),
-        }
-        try os_builtin_str_buffer.appendSlice("};\n");
-
-        const glibc_or_darwin_version = blk: {
-            if (target.isGnuLibC()) {
-                const stage1_glibc = try std.heap.c_allocator.create(Stage2SemVer);
-                const stage2_glibc = target.os.version_range.linux.glibc;
-                stage1_glibc.* = .{
-                    .major = stage2_glibc.major,
-                    .minor = stage2_glibc.minor,
-                    .patch = stage2_glibc.patch,
-                };
-                break :blk stage1_glibc;
-            } else if (target.isDarwin()) {
-                const stage1_semver = try std.heap.c_allocator.create(Stage2SemVer);
-                const stage2_semver = target.os.version_range.semver.min;
-                stage1_semver.* = .{
-                    .major = stage2_semver.major,
-                    .minor = stage2_semver.minor,
-                    .patch = stage2_semver.patch,
-                };
-                break :blk stage1_semver;
-            } else {
-                break :blk null;
-            }
-        };
-
-        const std_dl = target.standardDynamicLinkerPath();
-        const std_dl_z = if (std_dl.get()) |dl|
-            (try mem.dupeZ(std.heap.c_allocator, u8, dl)).ptr
-        else
-            null;
-
-        const asm_features = asm_features_list.toOwnedSlice();
-        self.* = .{
-            .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
-            .vendor = 0,
-            .os = @enumToInt(target.os.tag),
-            .abi = @enumToInt(target.abi),
-            .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
-            .llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
-            .llvm_cpu_features_asm_ptr = asm_features.ptr,
-            .llvm_cpu_features_asm_len = asm_features.len,
-            .cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
-            .os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
-            .is_native_os = cross_target.isNativeOs(),
-            .is_native_cpu = cross_target.isNativeCpu(),
-            .glibc_or_darwin_version = glibc_or_darwin_version,
-            .dynamic_linker = dynamic_linker,
-            .standard_dynamic_linker_path = std_dl_z,
-        };
-    }
 };
 
-fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
-    var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
-    if (info.cpu_detection_unimplemented) {
-        // TODO We want to just use detected_info.target but implementing
-        // CPU model & feature detection is todo so here we rely on LLVM.
-        const llvm = @import("llvm.zig");
-        const llvm_cpu_name = llvm.GetHostCPUName();
-        const llvm_cpu_features = llvm.GetNativeFeatures();
-        const arch = Target.current.cpu.arch;
-        info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
-        cross_target.updateCpuFeatures(&info.target.cpu.features);
-        info.target.cpu.arch = cross_target.getCpuArch();
-    }
-    if (info.dynamic_linker.get()) |dl| {
-        dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
-    } else {
-        dynamic_linker_ptr.* = null;
-    }
-    return info.target;
-}
-
 // ABI warning
 const Stage2SemVer = extern struct {
     major: u32,
     minor: u32,
     patch: u32,
 };
+
+// ABI warning
+export fn stage2_cimport(stage1: *Module) [*:0]const u8 {
+    @panic("TODO implement stage2_cimport");
+}
+
+export fn stage2_add_link_lib(
+    stage1: *Module,
+    lib_name_ptr: [*c]const u8,
+    lib_name_len: usize,
+    symbol_name_ptr: [*c]const u8,
+    symbol_name_len: usize,
+) ?[*:0]const u8 {
+    return null; // no error
+}
+
+export fn stage2_fetch_file(
+    stage1: *Module,
+    path_ptr: [*]const u8,
+    path_len: usize,
+    result_len: *usize,
+) ?[*]const u8 {
+    const comp = @intToPtr(*Compilation, stage1.userdata);
+    // TODO integrate this with cache hash
+    const file_path = path_ptr[0..path_len];
+    const contents = std.fs.cwd().readFileAlloc(comp.gpa, file_path, std.math.maxInt(u32)) catch return null;
+    result_len.* = contents.len;
+    return contents.ptr;
+}
BRANCH_TODO
@@ -1,3 +1,6 @@
+ * build & link against compiler-rt
+ * build & link against freestanding libc
+ * Cache integration for stage1 zig code compilation
  * `zig test`
  * `zig build`
  * `-ftime-report`
@@ -14,10 +17,7 @@
    - using it as a preprocessor (-E)
    - try building some software
  * support rpaths in ELF linker code
- * build & link against compiler-rt
-   - stage1 C++ code integration
  * repair @cImport
- * build & link against freestanding libc
  * add CLI support for a way to pass extra flags to c source files
  * capture lld stdout/stderr better
  * musl
@@ -35,10 +35,12 @@
  * implement emit-h in stage2
  * implement -fno-emit-bin
  * audit the base cache hash
+ * --main-pkg-path
  * audit the CLI options for stage2
  * `zig init-lib`
  * `zig init-exe`
  * `zig run`
+ * restore error messages for stage2_add_link_lib
 
  * implement serialization/deserialization of incremental compilation metadata
  * incremental compilation - implement detection of which source files changed
CMakeLists.txt
@@ -258,7 +258,6 @@ find_package(Threads)
 # This is our shim which will be replaced by stage1.zig.
 set(ZIG0_SOURCES
     "${CMAKE_SOURCE_DIR}/src/zig0.cpp"
-    "${CMAKE_SOURCE_DIR}/src/stage2.cpp"
 )
 
 set(ZIG_SOURCES