Commit dbde5df568

Andrew Kelley <andrew@ziglang.org>
2020-03-18 04:03:45
clean up some self-hosted bitrot + don't assume libstdc++
closes #4682 The self-hosted compiler is still bit rotted and still not compiling successfully yet. I have a more serious rework of the code in a different branch.
1 parent 7251eb1
lib/std/math/big/int.zig
@@ -520,13 +520,13 @@ pub const Int = struct {
         comptime fmt: []const u8,
         options: std.fmt.FormatOptions,
         out_stream: var,
-    ) FmtError!void {
+    ) !void {
         self.assertWritable();
         // TODO look at fmt and support other bases
         // TODO support read-only fixed integers
         const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating");
         defer self.allocator.?.free(str);
-        return out_stream.print(str);
+        return out_stream.writeAll(str);
     }
 
     /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
src-self-hosted/c_int.zig
@@ -69,9 +69,9 @@ pub const CInt = struct {
     };
 
     pub fn sizeInBits(cint: CInt, self: Target) u32 {
-        const arch = self.getArch();
+        const arch = self.cpu.arch;
         switch (self.os.tag) {
-            .freestanding, .other => switch (self.getArch()) {
+            .freestanding, .other => switch (self.cpu.arch) {
                 .msp430 => switch (cint.id) {
                     .Short,
                     .UShort,
@@ -94,7 +94,7 @@ pub const CInt = struct {
                     => return 32,
                     .Long,
                     .ULong,
-                    => return self.getArchPtrBitWidth(),
+                    => return self.cpu.arch.ptrBitWidth(),
                     .LongLong,
                     .ULongLong,
                     => return 64,
@@ -114,7 +114,7 @@ pub const CInt = struct {
                 => return 32,
                 .Long,
                 .ULong,
-                => return self.getArchPtrBitWidth(),
+                => return self.cpu.arch.ptrBitWidth(),
                 .LongLong,
                 .ULongLong,
                 => return 64,
src-self-hosted/compilation.zig
@@ -95,7 +95,7 @@ pub const ZigCompiler = struct {
 
     pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation {
         if (self.native_libc.start()) |ptr| return ptr;
-        try self.native_libc.data.findNative(self.allocator);
+        self.native_libc.data = try LibCInstallation.findNative(.{ .allocator = self.allocator });
         self.native_libc.resolve();
         return &self.native_libc.data;
     }
@@ -126,7 +126,7 @@ pub const Compilation = struct {
     name: Buffer,
     llvm_triple: Buffer,
     root_src_path: ?[]const u8,
-    target: Target,
+    target: std.Target,
     llvm_target: *llvm.Target,
     build_mode: builtin.Mode,
     zig_lib_dir: []const u8,
@@ -338,7 +338,7 @@ pub const Compilation = struct {
         zig_compiler: *ZigCompiler,
         name: []const u8,
         root_src_path: ?[]const u8,
-        target: Target,
+        target: std.zig.CrossTarget,
         kind: Kind,
         build_mode: builtin.Mode,
         is_static: bool,
@@ -370,13 +370,18 @@ pub const Compilation = struct {
         zig_compiler: *ZigCompiler,
         name: []const u8,
         root_src_path: ?[]const u8,
-        target: Target,
+        cross_target: std.zig.CrossTarget,
         kind: Kind,
         build_mode: builtin.Mode,
         is_static: bool,
         zig_lib_dir: []const u8,
     ) !void {
         const allocator = zig_compiler.allocator;
+
+        // TODO merge this line with stage2.zig crossTargetToTarget
+        const target_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
+        const target = target_info.target;
+
         var comp = Compilation{
             .arena_allocator = std.heap.ArenaAllocator.init(allocator),
             .zig_compiler = zig_compiler,
@@ -419,7 +424,7 @@ pub const Compilation = struct {
             .target_machine = undefined,
             .target_data_ref = undefined,
             .target_layout_str = undefined,
-            .target_ptr_bits = target.getArchPtrBitWidth(),
+            .target_ptr_bits = target.cpu.arch.ptrBitWidth(),
 
             .root_package = undefined,
             .std_package = undefined,
@@ -440,7 +445,7 @@ pub const Compilation = struct {
         }
 
         comp.name = try Buffer.init(comp.arena(), name);
-        comp.llvm_triple = try util.getTriple(comp.arena(), target);
+        comp.llvm_triple = try util.getLLVMTriple(comp.arena(), target);
         comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple);
         comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" });
 
@@ -451,17 +456,12 @@ pub const Compilation = struct {
 
         const reloc_mode = if (is_static) llvm.RelocStatic else llvm.RelocPIC;
 
-        // LLVM creates invalid binaries on Windows sometimes.
-        // See https://github.com/ziglang/zig/issues/508
-        // As a workaround we do not use target native features on Windows.
         var target_specific_cpu_args: ?[*:0]u8 = null;
         var target_specific_cpu_features: ?[*:0]u8 = null;
         defer llvm.DisposeMessage(target_specific_cpu_args);
         defer llvm.DisposeMessage(target_specific_cpu_features);
-        if (target == Target.Native and !target.isWindows()) {
-            target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory;
-            target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory;
-        }
+
+        // TODO detect native CPU & features here
 
         comp.target_machine = llvm.CreateTargetMachine(
             comp.llvm_target,
@@ -1125,7 +1125,9 @@ pub const Compilation = struct {
             self.libc_link_lib = link_lib;
 
             // get a head start on looking for the native libc
-            if (self.target == Target.Native and self.override_libc == null) {
+            // TODO this is missing a bunch of logic related to whether the target is native
+            // and whether we can build libc
+            if (self.override_libc == null) {
                 try self.deinit_group.call(startFindingNativeLibC, .{self});
             }
         }
src-self-hosted/errmsg.zig
@@ -164,8 +164,7 @@ pub const Msg = struct {
         const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath);
         errdefer comp.gpa().free(realpath_copy);
 
-        var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
-        try parse_error.render(&tree_scope.tree.tokens, out_stream);
+        try parse_error.render(&tree_scope.tree.tokens, text_buf.outStream());
 
         const msg = try comp.gpa().create(Msg);
         msg.* = Msg{
@@ -204,8 +203,7 @@ pub const Msg = struct {
         const realpath_copy = try mem.dupe(allocator, u8, realpath);
         errdefer allocator.free(realpath_copy);
 
-        var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
-        try parse_error.render(&tree.tokens, out_stream);
+        try parse_error.render(&tree.tokens, text_buf.outStream());
 
         const msg = try allocator.create(Msg);
         msg.* = Msg{
@@ -272,7 +270,7 @@ pub const Msg = struct {
         });
         try stream.writeByteNTimes(' ', start_loc.column);
         try stream.writeByteNTimes('~', last_token.end - first_token.start);
-        try stream.write("\n");
+        try stream.writeAll("\n");
     }
 
     pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void {
@@ -281,7 +279,6 @@ pub const Msg = struct {
             .On => true,
             .Off => false,
         };
-        var stream = &file.outStream().stream;
-        return msg.printToStream(stream, color_on);
+        return msg.printToStream(file.outStream(), color_on);
     }
 };
src-self-hosted/ir.zig
@@ -1099,7 +1099,6 @@ pub const Builder = struct {
                     .Await => return error.Unimplemented,
                     .BitNot => return error.Unimplemented,
                     .BoolNot => return error.Unimplemented,
-                    .Cancel => return error.Unimplemented,
                     .OptionalType => return error.Unimplemented,
                     .Negation => return error.Unimplemented,
                     .NegationWrap => return error.Unimplemented,
@@ -1188,6 +1187,7 @@ pub const Builder = struct {
             .ParamDecl => return error.Unimplemented,
             .FieldInitializer => return error.Unimplemented,
             .EnumLiteral => return error.Unimplemented,
+            .Noasync => return error.Unimplemented,
         }
     }
 
src-self-hosted/link.zig
@@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void {
     if (comp.haveLibC()) {
         // TODO https://github.com/ziglang/zig/issues/3190
         var libc = ctx.comp.override_libc orelse blk: {
-            switch (comp.target) {
-                Target.Native => {
-                    break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound;
-                },
-                else => return error.LibCRequiredButNotProvidedOrFound,
-            }
+            @panic("this code has bitrotted");
+            //switch (comp.target) {
+            //    Target.Native => {
+            //        break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound;
+            //    },
+            //    else => return error.LibCRequiredButNotProvidedOrFound,
+            //}
         };
         ctx.libc = libc;
     }
@@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
     //bool shared = !g->is_static && is_lib;
     //Buf *soname = nullptr;
     if (ctx.comp.is_static) {
-        if (util.isArmOrThumb(ctx.comp.target)) {
-            try ctx.args.append("-Bstatic");
-        } else {
-            try ctx.args.append("-static");
-        }
+        //if (util.isArmOrThumb(ctx.comp.target)) {
+        //    try ctx.args.append("-Bstatic");
+        //} else {
+        //    try ctx.args.append("-static");
+        //}
     }
     //} else if (shared) {
     //    lj->args.append("-shared");
@@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
 
     if (ctx.link_in_crt) {
         const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";
-        const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o";
-        try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o);
-        try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o");
-        try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino);
+        try addPathJoin(ctx, ctx.libc.crt_dir.?, crt1o);
+        try addPathJoin(ctx, ctx.libc.crt_dir.?, "crti.o");
     }
 
     if (ctx.comp.haveLibC()) {
         try ctx.args.append("-L");
         // TODO addNullByte should probably return [:0]u8
-        try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr));
+        try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.crt_dir.?)).ptr));
 
-        try ctx.args.append("-L");
-        try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr));
-
-        if (!ctx.comp.is_static) {
-            const dl = blk: {
-                if (ctx.libc.dynamic_linker_path) |dl| break :blk dl;
-                if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl;
-                return error.LibCMissingDynamicLinker;
-            };
-            try ctx.args.append("-dynamic-linker");
-            try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr));
-        }
+        //if (!ctx.comp.is_static) {
+        //    const dl = blk: {
+        //        //if (ctx.libc.dynamic_linker_path) |dl| break :blk dl;
+        //        //if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl;
+        //        return error.LibCMissingDynamicLinker;
+        //    };
+        //    try ctx.args.append("-dynamic-linker");
+        //    try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr));
+        //}
     }
 
     //if (shared) {
@@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
 
     // crt end
     if (ctx.link_in_crt) {
-        try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o");
-        try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o");
+        try addPathJoin(ctx, ctx.libc.crt_dir.?, "crtn.o");
     }
 
-    if (ctx.comp.target != Target.Native) {
-        try ctx.args.append("--allow-shlib-undefined");
-    }
+    //if (ctx.comp.target != Target.Native) {
+    //    try ctx.args.append("--allow-shlib-undefined");
+    //}
 }
 
 fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
@@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
         try ctx.args.append("-DEBUG");
     }
 
-    switch (ctx.comp.target.getArch()) {
+    switch (ctx.comp.target.cpu.arch) {
         .i386 => try ctx.args.append("-MACHINE:X86"),
         .x86_64 => try ctx.args.append("-MACHINE:X64"),
         .aarch64 => try ctx.args.append("-MACHINE:ARM"),
@@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
     if (ctx.comp.haveLibC()) {
         try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr));
         try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr));
-        try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr));
+        try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.crt_dir.?})).ptr));
     }
 
     if (ctx.link_in_crt) {
@@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
                 }
             },
             .IPhoneOS => {
-                if (ctx.comp.target.getArch() == .aarch64) {
+                if (ctx.comp.target.cpu.arch == .aarch64) {
                     // iOS does not need any crt1 files for arm64
                 } else if (platform.versionLessThan(3, 1)) {
                     try ctx.args.append("-lcrt1.o");
@@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
     }
     try addFnObjects(ctx);
 
-    if (ctx.comp.target == Target.Native) {
-        for (ctx.comp.link_libs_list.toSliceConst()) |lib| {
-            if (mem.eql(u8, lib.name, "c")) {
-                // on Darwin, libSystem has libc in it, but also you have to use it
-                // to make syscalls because the syscall numbers are not documented
-                // and change between versions.
-                // so we always link against libSystem
-                try ctx.args.append("-lSystem");
-            } else {
-                if (mem.indexOfScalar(u8, lib.name, '/') == null) {
-                    const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});
-                    try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
-                } else {
-                    const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
-                    try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
-                }
-            }
-        }
-    } else {
-        try ctx.args.append("-undefined");
-        try ctx.args.append("dynamic_lookup");
-    }
+    // TODO
+    //if (ctx.comp.target == Target.Native) {
+    //    for (ctx.comp.link_libs_list.toSliceConst()) |lib| {
+    //        if (mem.eql(u8, lib.name, "c")) {
+    //            // on Darwin, libSystem has libc in it, but also you have to use it
+    //            // to make syscalls because the syscall numbers are not documented
+    //            // and change between versions.
+    //            // so we always link against libSystem
+    //            try ctx.args.append("-lSystem");
+    //        } else {
+    //            if (mem.indexOfScalar(u8, lib.name, '/') == null) {
+    //                const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});
+    //                try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
+    //            } else {
+    //                const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
+    //                try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
+    //            }
+    //        }
+    //    }
+    //} else {
+    //    try ctx.args.append("-undefined");
+    //    try ctx.args.append("dynamic_lookup");
+    //}
 
     if (platform.kind == .MacOS) {
         if (platform.versionLessThan(10, 5)) {
src-self-hosted/main.zig
@@ -18,10 +18,6 @@ const Target = std.Target;
 const errmsg = @import("errmsg.zig");
 const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
 
-var stderr_file: fs.File = undefined;
-var stderr: *io.OutStream(fs.File.WriteError) = undefined;
-var stdout: *io.OutStream(fs.File.WriteError) = undefined;
-
 pub const io_mode = .evented;
 
 pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
@@ -51,17 +47,14 @@ const Command = struct {
 pub fn main() !void {
     const allocator = std.heap.c_allocator;
 
-    stdout = &std.io.getStdOut().outStream().stream;
-
-    stderr_file = std.io.getStdErr();
-    stderr = &stderr_file.outStream().stream;
+    const stderr = io.getStdErr().outStream();
 
     const args = try process.argsAlloc(allocator);
     defer process.argsFree(allocator, args);
 
     if (args.len <= 1) {
-        try stderr.write("expected command argument\n\n");
-        try stderr.write(usage);
+        try stderr.writeAll("expected command argument\n\n");
+        try stderr.writeAll(usage);
         process.exit(1);
     }
 
@@ -78,8 +71,8 @@ pub fn main() !void {
     } else if (mem.eql(u8, cmd, "libc")) {
         return cmdLibC(allocator, cmd_args);
     } else if (mem.eql(u8, cmd, "targets")) {
-        const info = try std.zig.system.NativeTargetInfo.detect(allocator);
-        defer info.deinit(allocator);
+        const info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});
+        const stdout = io.getStdOut().outStream();
         return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target);
     } else if (mem.eql(u8, cmd, "version")) {
         return cmdVersion(allocator, cmd_args);
@@ -91,7 +84,7 @@ pub fn main() !void {
         return cmdInternal(allocator, cmd_args);
     } else {
         try stderr.print("unknown command: {}\n\n", .{args[1]});
-        try stderr.write(usage);
+        try stderr.writeAll(usage);
         process.exit(1);
     }
 }
@@ -156,6 +149,8 @@ const usage_build_generic =
 ;
 
 fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void {
+    const stderr = io.getStdErr().outStream();
+
     var color: errmsg.Color = .Auto;
     var build_mode: std.builtin.Mode = .Debug;
     var emit_bin = true;
@@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
             const arg = args[i];
             if (mem.startsWith(u8, arg, "-")) {
                 if (mem.eql(u8, arg, "--help")) {
-                    try stdout.write(usage_build_generic);
+                    try io.getStdOut().writeAll(usage_build_generic);
                     process.exit(0);
                 } else if (mem.eql(u8, arg, "--color")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected [auto|on|off] after --color\n");
+                        try stderr.writeAll("expected [auto|on|off] after --color\n");
                         process.exit(1);
                     }
                     i += 1;
@@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
                     }
                 } else if (mem.eql(u8, arg, "--mode")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n");
+                        try stderr.writeAll("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n");
                         process.exit(1);
                     }
                     i += 1;
@@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
                     }
                 } else if (mem.eql(u8, arg, "--name")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after --name\n");
+                        try stderr.writeAll("expected parameter after --name\n");
                         process.exit(1);
                     }
                     i += 1;
                     provided_name = args[i];
                 } else if (mem.eql(u8, arg, "--ver-major")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after --ver-major\n");
+                        try stderr.writeAll("expected parameter after --ver-major\n");
                         process.exit(1);
                     }
                     i += 1;
                     version.major = try std.fmt.parseInt(u32, args[i], 10);
                 } else if (mem.eql(u8, arg, "--ver-minor")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after --ver-minor\n");
+                        try stderr.writeAll("expected parameter after --ver-minor\n");
                         process.exit(1);
                     }
                     i += 1;
                     version.minor = try std.fmt.parseInt(u32, args[i], 10);
                 } else if (mem.eql(u8, arg, "--ver-patch")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after --ver-patch\n");
+                        try stderr.writeAll("expected parameter after --ver-patch\n");
                         process.exit(1);
                     }
                     i += 1;
                     version.patch = try std.fmt.parseInt(u32, args[i], 10);
                 } else if (mem.eql(u8, arg, "--linker-script")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after --linker-script\n");
+                        try stderr.writeAll("expected parameter after --linker-script\n");
                         process.exit(1);
                     }
                     i += 1;
                     linker_script = args[i];
                 } else if (mem.eql(u8, arg, "--libc")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after --libc\n");
+                        try stderr.writeAll("expected parameter after --libc\n");
                         process.exit(1);
                     }
                     i += 1;
                     libc_arg = args[i];
                 } else if (mem.eql(u8, arg, "-mllvm")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after -mllvm\n");
+                        try stderr.writeAll("expected parameter after -mllvm\n");
                         process.exit(1);
                     }
                     i += 1;
@@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
                     try mllvm_flags.append(args[i]);
                 } else if (mem.eql(u8, arg, "-mmacosx-version-min")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after -mmacosx-version-min\n");
+                        try stderr.writeAll("expected parameter after -mmacosx-version-min\n");
                         process.exit(1);
                     }
                     i += 1;
                     macosx_version_min = args[i];
                 } else if (mem.eql(u8, arg, "-mios-version-min")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected parameter after -mios-version-min\n");
+                        try stderr.writeAll("expected parameter after -mios-version-min\n");
                         process.exit(1);
                     }
                     i += 1;
@@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
                     linker_rdynamic = true;
                 } else if (mem.eql(u8, arg, "--pkg-begin")) {
                     if (i + 2 >= args.len) {
-                        try stderr.write("expected [name] [path] after --pkg-begin\n");
+                        try stderr.writeAll("expected [name] [path] after --pkg-begin\n");
                         process.exit(1);
                     }
                     i += 1;
@@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
                     if (cur_pkg.parent) |parent| {
                         cur_pkg = parent;
                     } else {
-                        try stderr.write("encountered --pkg-end with no matching --pkg-begin\n");
+                        try stderr.writeAll("encountered --pkg-end with no matching --pkg-begin\n");
                         process.exit(1);
                     }
                 } else if (mem.startsWith(u8, arg, "-l")) {
@@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
             var it = mem.separate(basename, ".");
             break :blk it.next() orelse basename;
         } else {
-            try stderr.write("--name [name] not provided and unable to infer\n");
+            try stderr.writeAll("--name [name] not provided and unable to infer\n");
             process.exit(1);
         }
     };
 
     if (root_src_file == null and link_objects.len == 0 and assembly_files.len == 0) {
-        try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
+        try stderr.writeAll("Expected source file argument or at least one --object or --assembly argument\n");
         process.exit(1);
     }
 
     if (out_type == Compilation.Kind.Obj and link_objects.len != 0) {
-        try stderr.write("When building an object file, --object arguments are invalid\n");
+        try stderr.writeAll("When building an object file, --object arguments are invalid\n");
         process.exit(1);
     }
 
@@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
         &zig_compiler,
         root_name,
         root_src_file,
-        Target.Native,
+        .{},
         out_type,
         build_mode,
         !is_dynamic,
@@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
     comp.linker_rdynamic = linker_rdynamic;
 
     if (macosx_version_min != null and ios_version_min != null) {
-        try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n");
+        try stderr.writeAll("-mmacosx-version-min and -mios-version-min options not allowed together\n");
         process.exit(1);
     }
 
@@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
 }
 
 fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
+    const stderr_file = io.getStdErr();
+    const stderr = stderr_file.outStream();
     var count: usize = 0;
     while (!comp.cancelled) {
         const build_event = comp.events.get();
@@ -551,7 +548,8 @@ const Fmt = struct {
 };
 
 fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void {
-    libc.parse(allocator, libc_paths_file, stderr) catch |err| {
+    const stderr = io.getStdErr().outStream();
+    libc.* = LibCInstallation.parse(allocator, libc_paths_file, stderr) catch |err| {
         stderr.print("Unable to parse libc path file '{}': {}.\n" ++
             "Try running `zig libc` to see an example for the native target.\n", .{
             libc_paths_file,
@@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil
 }
 
 fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
+    const stderr = io.getStdErr().outStream();
     switch (args.len) {
         0 => {},
         1 => {
@@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
         stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {};
         process.exit(1);
     };
-    libc.render(stdout) catch process.exit(1);
+    libc.render(io.getStdOut().outStream()) catch process.exit(1);
 }
 
 fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
+    const stderr_file = io.getStdErr();
+    const stderr = stderr_file.outStream();
     var color: errmsg.Color = .Auto;
     var stdin_flag: bool = false;
     var check_flag: bool = false;
@@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
             const arg = args[i];
             if (mem.startsWith(u8, arg, "-")) {
                 if (mem.eql(u8, arg, "--help")) {
-                    try stdout.write(usage_fmt);
+                    const stdout = io.getStdOut().outStream();
+                    try stdout.writeAll(usage_fmt);
                     process.exit(0);
                 } else if (mem.eql(u8, arg, "--color")) {
                     if (i + 1 >= args.len) {
-                        try stderr.write("expected [auto|on|off] after --color\n");
+                        try stderr.writeAll("expected [auto|on|off] after --color\n");
                         process.exit(1);
                     }
                     i += 1;
@@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
 
     if (stdin_flag) {
         if (input_files.len != 0) {
-            try stderr.write("cannot use --stdin with positional arguments\n");
+            try stderr.writeAll("cannot use --stdin with positional arguments\n");
             process.exit(1);
         }
 
-        var stdin_file = io.getStdIn();
-        var stdin = stdin_file.inStream();
+        const stdin = io.getStdIn().inStream();
 
-        const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);
+        const source_code = try stdin.readAllAlloc(allocator, max_src_size);
         defer allocator.free(source_code);
 
         const tree = std.zig.parse(allocator, source_code) catch |err| {
@@ -653,7 +654,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
             const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>");
             defer msg.destroy();
 
-            try msg.printToFile(stderr_file, color);
+            try msg.printToFile(io.getStdErr(), color);
         }
         if (tree.errors.len != 0) {
             process.exit(1);
@@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
             process.exit(code);
         }
 
+        const stdout = io.getStdOut().outStream();
         _ = try std.zig.render(allocator, stdout, tree);
         return;
     }
 
     if (input_files.len == 0) {
-        try stderr.write("expected at least one source file argument\n");
+        try stderr.writeAll("expected at least one source file argument\n");
         process.exit(1);
     }
 
@@ -713,6 +715,9 @@ const FmtError = error{
 } || fs.File.OpenError;
 
 async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {
+    const stderr_file = io.getStdErr();
+    const stderr = stderr_file.outStream();
+
     const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);
     defer fmt.allocator.free(file_path);
 
@@ -791,11 +796,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
 }
 
 fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
+    const stdout = io.getStdOut().outStream();
     try stdout.print("{}\n", .{c.ZIG_VERSION_STRING});
 }
 
 fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
-    try stdout.write(usage);
+    const stdout = io.getStdOut();
+    try stdout.writeAll(usage);
 }
 
 pub const info_zen =
@@ -816,7 +823,7 @@ pub const info_zen =
 ;
 
 fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {
-    try stdout.write(info_zen);
+    try io.getStdOut().writeAll(info_zen);
 }
 
 const usage_internal =
@@ -829,8 +836,9 @@ const usage_internal =
 ;
 
 fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
+    const stderr = io.getStdErr().outStream();
     if (args.len == 0) {
-        try stderr.write(usage_internal);
+        try stderr.writeAll(usage_internal);
         process.exit(1);
     }
 
@@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
     }
 
     try stderr.print("unknown sub command: {}\n\n", .{args[0]});
-    try stderr.write(usage_internal);
+    try stderr.writeAll(usage_internal);
 }
 
 fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
+    const stdout = io.getStdOut().outStream();
     try stdout.print(
         \\ZIG_CMAKE_BINARY_DIR {}
         \\ZIG_CXX_COMPILER     {}
src-self-hosted/util.zig
@@ -3,8 +3,7 @@ const Target = std.Target;
 const llvm = @import("llvm.zig");
 
 pub fn getDarwinArchString(self: Target) [:0]const u8 {
-    const arch = self.getArch();
-    switch (arch) {
+    switch (self.cpu.arch) {
         .aarch64 => return "arm64",
         .thumb,
         .arm,
@@ -34,3 +33,15 @@ pub fn initializeAllTargets() void {
     llvm.InitializeAllAsmPrinters();
     llvm.InitializeAllAsmParsers();
 }
+
+pub fn getLLVMTriple(allocator: *std.mem.Allocator, target: std.Target) !std.Buffer {
+    var result = try std.Buffer.initSize(allocator, 0);
+    errdefer result.deinit();
+
+    try result.outStream().print(
+        "{}-unknown-{}-{}",
+        .{ @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi) },
+    );
+
+    return result;
+}
build.zig
@@ -298,10 +298,14 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
     dependOnLib(b, exe, ctx.llvm);
 
     if (exe.target.getOsTag() == .linux) {
-        try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
-            \\Unable to determine path to libstdc++.a
-            \\On Fedora, install libstdc++-static and try again.
-        );
+        // First we try to static link against gcc libstdc++. If that doesn't work,
+        // we fall back to -lc++ and cross our fingers.
+        addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) {
+            error.RequiredLibraryNotFound => {
+                exe.linkSystemLibrary("c++");
+            },
+            else => |e| return e,
+        };
 
         exe.linkSystemLibrary("pthread");
     } else if (exe.target.isFreeBSD()) {
@@ -320,7 +324,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
                 // System compiler, not gcc.
                 exe.linkSystemLibrary("c++");
             },
-            else => return err,
+            else => |e| return e,
         }
     }