Commit b6556c944b

Andrew Kelley <andrew@ziglang.org>
2020-09-27 06:03:38
fix another round of regressions in this branch
* std.log: still print error messages in ReleaseSmall builds. - when start code gets an error code from main, it uses std.log.err to report the error. this resulted in a test failure because ReleaseSmall wasn't printing `error: TheErrorCode` when an error was returned from main. But that seems like it should keep working. So I changed the std.log defaults. I plan to follow this up with a proposal to change the names of and reduce the quantity of the log levels. * warning emitted when using -femit-h when using stage1 backend; fatal log message when using -femit-h with self-hosted backend (because the feature is not yet available) * fix double `test-cli` build steps in zig's build.zig * update docgen to use new CLI * translate-c uses `-x c` and generates a temporary basename with a `.h` extension. Otherwise clang reports an error. * --show-builtin implies -fno-emit-bin * restore the compile error for using an extern "c" function without putting -lc on the build line. we have to know about the libc dependency up front. * Fix ReleaseFast and ReleaseSmall getting swapped when passing the value to the stage1 backend. * correct the zig0 CLI usage text. * update test harness code to the new CLI.
1 parent fe4c348
doc/docgen.zig
@@ -4,7 +4,7 @@ const io = std.io;
 const fs = std.fs;
 const process = std.process;
 const ChildProcess = std.ChildProcess;
-const warn = std.debug.warn;
+const print = std.debug.print;
 const mem = std.mem;
 const testing = std.testing;
 
@@ -215,23 +215,23 @@ const Tokenizer = struct {
 fn parseError(tokenizer: *Tokenizer, token: Token, comptime fmt: []const u8, args: anytype) anyerror {
     const loc = tokenizer.getTokenLocation(token);
     const args_prefix = .{ tokenizer.source_file_name, loc.line + 1, loc.column + 1 };
-    warn("{}:{}:{}: error: " ++ fmt ++ "\n", args_prefix ++ args);
+    print("{}:{}:{}: error: " ++ fmt ++ "\n", args_prefix ++ args);
     if (loc.line_start <= loc.line_end) {
-        warn("{}\n", .{tokenizer.buffer[loc.line_start..loc.line_end]});
+        print("{}\n", .{tokenizer.buffer[loc.line_start..loc.line_end]});
         {
             var i: usize = 0;
             while (i < loc.column) : (i += 1) {
-                warn(" ", .{});
+                print(" ", .{});
             }
         }
         {
             const caret_count = token.end - token.start;
             var i: usize = 0;
             while (i < caret_count) : (i += 1) {
-                warn("~", .{});
+                print("~", .{});
             }
         }
-        warn("\n", .{});
+        print("\n", .{});
     }
     return error.ParseError;
 }
@@ -274,6 +274,7 @@ const Code = struct {
     link_objects: []const []const u8,
     target_str: ?[]const u8,
     link_libc: bool,
+    disable_cache: bool,
 
     const Id = union(enum) {
         Test,
@@ -522,6 +523,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
                     defer link_objects.deinit();
                     var target_str: ?[]const u8 = null;
                     var link_libc = false;
+                    var disable_cache = false;
 
                     const source_token = while (true) {
                         const content_tok = try eatToken(tokenizer, Token.Id.Content);
@@ -532,6 +534,8 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
                             mode = .ReleaseFast;
                         } else if (mem.eql(u8, end_tag_name, "code_release_safe")) {
                             mode = .ReleaseSafe;
+                        } else if (mem.eql(u8, end_tag_name, "code_disable_cache")) {
+                            disable_cache = true;
                         } else if (mem.eql(u8, end_tag_name, "code_link_object")) {
                             _ = try eatToken(tokenizer, Token.Id.Separator);
                             const obj_tok = try eatToken(tokenizer, Token.Id.TagContent);
@@ -572,6 +576,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
                             .link_objects = link_objects.toOwnedSlice(),
                             .target_str = target_str,
                             .link_libc = link_libc,
+                            .disable_cache = disable_cache,
                         },
                     });
                     tokenizer.code_node_count += 1;
@@ -1032,7 +1037,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
             },
             .Code => |code| {
                 code_progress_index += 1;
-                warn("docgen example code {}/{}...", .{ code_progress_index, tokenizer.code_node_count });
+                print("docgen example code {}/{}...", .{ code_progress_index, tokenizer.code_node_count });
 
                 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
                 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
@@ -1055,30 +1060,17 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                         var build_args = std.ArrayList([]const u8).init(allocator);
                         defer build_args.deinit();
                         try build_args.appendSlice(&[_][]const u8{
-                            zig_exe,
-                            "build-exe",
-                            tmp_source_file_name,
-                            "--name",
-                            code.name,
-                            "--color",
-                            "on",
-                            "--cache",
-                            "on",
+                            zig_exe,          "build-exe",
+                            "--name",         code.name,
+                            "--color",        "on",
+                            "--enable-cache", tmp_source_file_name,
                         });
                         try out.print("<pre><code class=\"shell\">$ zig build-exe {}.zig", .{code.name});
                         switch (code.mode) {
                             .Debug => {},
-                            .ReleaseSafe => {
-                                try build_args.append("--release-safe");
-                                try out.print(" --release-safe", .{});
-                            },
-                            .ReleaseFast => {
-                                try build_args.append("--release-fast");
-                                try out.print(" --release-fast", .{});
-                            },
-                            .ReleaseSmall => {
-                                try build_args.append("--release-small");
-                                try out.print(" --release-small", .{});
+                            else => {
+                                try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
+                                try out.print(" -O {s}", .{@tagName(code.mode)});
                             },
                         }
                         for (code.link_objects) |link_object| {
@@ -1087,9 +1079,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                                 allocator,
                                 &[_][]const u8{ tmp_dir_name, name_with_ext },
                             );
-                            try build_args.append("--object");
                             try build_args.append(full_path_object);
-                            try out.print(" --object {}", .{name_with_ext});
+                            try out.print(" {s}", .{name_with_ext});
                         }
                         if (code.link_libc) {
                             try build_args.append("-lc");
@@ -1114,20 +1105,14 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                             switch (result.term) {
                                 .Exited => |exit_code| {
                                     if (exit_code == 0) {
-                                        warn("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
-                                        for (build_args.items) |arg|
-                                            warn("{} ", .{arg})
-                                        else
-                                            warn("\n", .{});
+                                        print("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
+                                        dumpArgs(build_args.items);
                                         return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{});
                                     }
                                 },
                                 else => {
-                                    warn("{}\nThe following command crashed:\n", .{result.stderr});
-                                    for (build_args.items) |arg|
-                                        warn("{} ", .{arg})
-                                    else
-                                        warn("\n", .{});
+                                    print("{}\nThe following command crashed:\n", .{result.stderr});
+                                    dumpArgs(build_args.items);
                                     return parseError(tokenizer, code.source_token, "example compile crashed", .{});
                                 },
                             }
@@ -1174,11 +1159,8 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                             switch (result.term) {
                                 .Exited => |exit_code| {
                                     if (exit_code == 0) {
-                                        warn("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
-                                        for (run_args) |arg|
-                                            warn("{} ", .{arg})
-                                        else
-                                            warn("\n", .{});
+                                        print("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
+                                        dumpArgs(run_args);
                                         return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{});
                                     }
                                 },
@@ -1206,27 +1188,13 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                         var test_args = std.ArrayList([]const u8).init(allocator);
                         defer test_args.deinit();
 
-                        try test_args.appendSlice(&[_][]const u8{
-                            zig_exe,
-                            "test",
-                            tmp_source_file_name,
-                            "--cache",
-                            "on",
-                        });
+                        try test_args.appendSlice(&[_][]const u8{ zig_exe, "test", tmp_source_file_name });
                         try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
                         switch (code.mode) {
                             .Debug => {},
-                            .ReleaseSafe => {
-                                try test_args.append("--release-safe");
-                                try out.print(" --release-safe", .{});
-                            },
-                            .ReleaseFast => {
-                                try test_args.append("--release-fast");
-                                try out.print(" --release-fast", .{});
-                            },
-                            .ReleaseSmall => {
-                                try test_args.append("--release-small");
-                                try out.print(" --release-small", .{});
+                            else => {
+                                try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
+                                try out.print(" -O {s}", .{@tagName(code.mode)});
                             },
                         }
                         if (code.link_libc) {
@@ -1252,23 +1220,13 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                             "--color",
                             "on",
                             tmp_source_file_name,
-                            "--output-dir",
-                            tmp_dir_name,
                         });
                         try out.print("<pre><code class=\"shell\">$ zig test {}.zig", .{code.name});
                         switch (code.mode) {
                             .Debug => {},
-                            .ReleaseSafe => {
-                                try test_args.append("--release-safe");
-                                try out.print(" --release-safe", .{});
-                            },
-                            .ReleaseFast => {
-                                try test_args.append("--release-fast");
-                                try out.print(" --release-fast", .{});
-                            },
-                            .ReleaseSmall => {
-                                try test_args.append("--release-small");
-                                try out.print(" --release-small", .{});
+                            else => {
+                                try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
+                                try out.print(" -O {s}", .{@tagName(code.mode)});
                             },
                         }
                         const result = try ChildProcess.exec(.{
@@ -1280,25 +1238,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                         switch (result.term) {
                             .Exited => |exit_code| {
                                 if (exit_code == 0) {
-                                    warn("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
-                                    for (test_args.items) |arg|
-                                        warn("{} ", .{arg})
-                                    else
-                                        warn("\n", .{});
+                                    print("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
+                                    dumpArgs(test_args.items);
                                     return parseError(tokenizer, code.source_token, "example incorrectly compiled", .{});
                                 }
                             },
                             else => {
-                                warn("{}\nThe following command crashed:\n", .{result.stderr});
-                                for (test_args.items) |arg|
-                                    warn("{} ", .{arg})
-                                else
-                                    warn("\n", .{});
+                                print("{}\nThe following command crashed:\n", .{result.stderr});
+                                dumpArgs(test_args.items);
                                 return parseError(tokenizer, code.source_token, "example compile crashed", .{});
                             },
                         }
                         if (mem.indexOf(u8, result.stderr, error_match) == null) {
-                            warn("{}\nExpected to find '{}' in stderr", .{ result.stderr, error_match });
+                            print("{}\nExpected to find '{}' in stderr", .{ result.stderr, error_match });
                             return parseError(tokenizer, code.source_token, "example did not have expected compile error", .{});
                         }
                         const escaped_stderr = try escapeHtml(allocator, result.stderr);
@@ -1314,23 +1266,21 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                             zig_exe,
                             "test",
                             tmp_source_file_name,
-                            "--output-dir",
-                            tmp_dir_name,
                         });
                         var mode_arg: []const u8 = "";
                         switch (code.mode) {
                             .Debug => {},
                             .ReleaseSafe => {
-                                try test_args.append("--release-safe");
-                                mode_arg = " --release-safe";
+                                try test_args.append("-OReleaseSafe");
+                                mode_arg = "-OReleaseSafe";
                             },
                             .ReleaseFast => {
-                                try test_args.append("--release-fast");
-                                mode_arg = " --release-fast";
+                                try test_args.append("-OReleaseFast");
+                                mode_arg = "-OReleaseFast";
                             },
                             .ReleaseSmall => {
-                                try test_args.append("--release-small");
-                                mode_arg = " --release-small";
+                                try test_args.append("-OReleaseSmall");
+                                mode_arg = "-OReleaseSmall";
                             },
                         }
 
@@ -1343,25 +1293,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                         switch (result.term) {
                             .Exited => |exit_code| {
                                 if (exit_code == 0) {
-                                    warn("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
-                                    for (test_args.items) |arg|
-                                        warn("{} ", .{arg})
-                                    else
-                                        warn("\n", .{});
+                                    print("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
+                                    dumpArgs(test_args.items);
                                     return parseError(tokenizer, code.source_token, "example test incorrectly succeeded", .{});
                                 }
                             },
                             else => {
-                                warn("{}\nThe following command crashed:\n", .{result.stderr});
-                                for (test_args.items) |arg|
-                                    warn("{} ", .{arg})
-                                else
-                                    warn("\n", .{});
+                                print("{}\nThe following command crashed:\n", .{result.stderr});
+                                dumpArgs(test_args.items);
                                 return parseError(tokenizer, code.source_token, "example compile crashed", .{});
                             },
                         }
                         if (mem.indexOf(u8, result.stderr, error_match) == null) {
-                            warn("{}\nExpected to find '{}' in stderr", .{ result.stderr, error_match });
+                            print("{}\nExpected to find '{}' in stderr", .{ result.stderr, error_match });
                             return parseError(tokenizer, code.source_token, "example did not have expected runtime safety error message", .{});
                         }
                         const escaped_stderr = try escapeHtml(allocator, result.stderr);
@@ -1395,32 +1339,20 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                             "on",
                             "--name",
                             code.name,
-                            "--output-dir",
-                            tmp_dir_name,
+                            try std.fmt.allocPrint(allocator, "-femit-bin={s}{c}{s}", .{
+                                tmp_dir_name, fs.path.sep, name_plus_obj_ext,
+                            }),
                         });
-
                         if (!code.is_inline) {
                             try out.print("<pre><code class=\"shell\">$ zig build-obj {}.zig", .{code.name});
                         }
 
                         switch (code.mode) {
                             .Debug => {},
-                            .ReleaseSafe => {
-                                try build_args.append("--release-safe");
-                                if (!code.is_inline) {
-                                    try out.print(" --release-safe", .{});
-                                }
-                            },
-                            .ReleaseFast => {
-                                try build_args.append("--release-fast");
-                                if (!code.is_inline) {
-                                    try out.print(" --release-fast", .{});
-                                }
-                            },
-                            .ReleaseSmall => {
-                                try build_args.append("--release-small");
+                            else => {
+                                try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
                                 if (!code.is_inline) {
-                                    try out.print(" --release-small", .{});
+                                    try out.print(" -O {s}", .{@tagName(code.mode)});
                                 }
                             },
                         }
@@ -1440,25 +1372,19 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                             switch (result.term) {
                                 .Exited => |exit_code| {
                                     if (exit_code == 0) {
-                                        warn("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
-                                        for (build_args.items) |arg|
-                                            warn("{} ", .{arg})
-                                        else
-                                            warn("\n", .{});
+                                        print("{}\nThe following command incorrectly succeeded:\n", .{result.stderr});
+                                        dumpArgs(build_args.items);
                                         return parseError(tokenizer, code.source_token, "example build incorrectly succeeded", .{});
                                     }
                                 },
                                 else => {
-                                    warn("{}\nThe following command crashed:\n", .{result.stderr});
-                                    for (build_args.items) |arg|
-                                        warn("{} ", .{arg})
-                                    else
-                                        warn("\n", .{});
+                                    print("{}\nThe following command crashed:\n", .{result.stderr});
+                                    dumpArgs(build_args.items);
                                     return parseError(tokenizer, code.source_token, "example compile crashed", .{});
                                 },
                             }
                             if (mem.indexOf(u8, result.stderr, error_match) == null) {
-                                warn("{}\nExpected to find '{}' in stderr", .{ result.stderr, error_match });
+                                print("{}\nExpected to find '{}' in stderr", .{ result.stderr, error_match });
                                 return parseError(tokenizer, code.source_token, "example did not have expected compile error message", .{});
                             }
                             const escaped_stderr = try escapeHtml(allocator, result.stderr);
@@ -1472,6 +1398,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                         }
                     },
                     Code.Id.Lib => {
+                        const bin_basename = try std.zig.binNameAlloc(allocator, .{
+                            .root_name = code.name,
+                            .target = std.Target.current,
+                            .output_mode = .Lib,
+                        });
+
                         var test_args = std.ArrayList([]const u8).init(allocator);
                         defer test_args.deinit();
 
@@ -1479,23 +1411,16 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                             zig_exe,
                             "build-lib",
                             tmp_source_file_name,
-                            "--output-dir",
-                            tmp_dir_name,
+                            try std.fmt.allocPrint(allocator, "-femit-bin={s}{s}{s}", .{
+                                tmp_dir_name, fs.path.sep_str, bin_basename,
+                            }),
                         });
                         try out.print("<pre><code class=\"shell\">$ zig build-lib {}.zig", .{code.name});
                         switch (code.mode) {
                             .Debug => {},
-                            .ReleaseSafe => {
-                                try test_args.append("--release-safe");
-                                try out.print(" --release-safe", .{});
-                            },
-                            .ReleaseFast => {
-                                try test_args.append("--release-fast");
-                                try out.print(" --release-fast", .{});
-                            },
-                            .ReleaseSmall => {
-                                try test_args.append("--release-small");
-                                try out.print(" --release-small", .{});
+                            else => {
+                                try test_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
+                                try out.print(" -O {s}", .{@tagName(code.mode)});
                             },
                         }
                         if (code.target_str) |triple| {
@@ -1508,7 +1433,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: any
                         try out.print("\n{}{}</code></pre>\n", .{ escaped_stderr, escaped_stdout });
                     },
                 }
-                warn("OK\n", .{});
+                print("OK\n", .{});
             },
         }
     }
@@ -1524,20 +1449,14 @@ fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u
     switch (result.term) {
         .Exited => |exit_code| {
             if (exit_code != 0) {
-                warn("{}\nThe following command exited with code {}:\n", .{ result.stderr, exit_code });
-                for (args) |arg|
-                    warn("{} ", .{arg})
-                else
-                    warn("\n", .{});
+                print("{}\nThe following command exited with code {}:\n", .{ result.stderr, exit_code });
+                dumpArgs(args);
                 return error.ChildExitError;
             }
         },
         else => {
-            warn("{}\nThe following command crashed:\n", .{result.stderr});
-            for (args) |arg|
-                warn("{} ", .{arg})
-            else
-                warn("\n", .{});
+            print("{}\nThe following command crashed:\n", .{result.stderr});
+            dumpArgs(args);
             return error.ChildCrashed;
         },
     }
@@ -1545,9 +1464,13 @@ fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u
 }
 
 fn getBuiltinCode(allocator: *mem.Allocator, env_map: *std.BufMap, zig_exe: []const u8) ![]const u8 {
-    const result = try exec(allocator, env_map, &[_][]const u8{
-        zig_exe,
-        "builtin",
-    });
+    const result = try exec(allocator, env_map, &[_][]const u8{ zig_exe, "build-obj", "--show-builtin" });
     return result.stdout;
 }
+
+fn dumpArgs(args: []const []const u8) void {
+    for (args) |arg|
+        print("{} ", .{arg})
+    else
+        print("\n", .{});
+}
doc/langref.html.in
@@ -1078,6 +1078,7 @@ const nan = std.math.nan(f128);
           but you can switch to {#syntax#}Optimized{#endsyntax#} mode on a per-block basis:</p>
       {#code_begin|obj|foo#}
       {#code_release_fast#}
+      {#code_disable_cache#}
 const std = @import("std");
 const builtin = std.builtin;
 const big = @as(f64, 1 << 40);
lib/std/log.zig
@@ -101,14 +101,12 @@ pub const Level = enum {
     debug,
 };
 
-/// The default log level is based on build mode. Note that in ReleaseSmall
-/// builds the default level is emerg but no messages will be stored/logged
-/// by the default logger to save space.
+/// The default log level is based on build mode.
 pub const default_level: Level = switch (builtin.mode) {
     .Debug => .debug,
     .ReleaseSafe => .notice,
     .ReleaseFast => .err,
-    .ReleaseSmall => .emerg,
+    .ReleaseSmall => .err,
 };
 
 /// The current log level. This is set to root.log_level if present, otherwise
@@ -131,7 +129,7 @@ fn log(
             // On freestanding one must provide a log function; we do not have
             // any I/O configured.
             return;
-        } else if (builtin.mode != .ReleaseSmall) {
+        } else {
             const level_txt = switch (message_level) {
                 .emerg => "emergency",
                 .alert => "alert",
src/stage1/stage1.h
@@ -117,8 +117,8 @@ struct Stage2ProgressNode;
 
 enum BuildMode {
     BuildModeDebug,
-    BuildModeFastRelease,
     BuildModeSafeRelease,
+    BuildModeFastRelease,
     BuildModeSmallRelease,
 };
 
src/stage1/zig0.cpp
@@ -33,7 +33,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
         "Options:\n"
         "  --color [auto|off|on]        enable or disable colored error messages\n"
         "  --name [name]                override output name\n"
-        "  --output-dir [dir]           override output directory (defaults to cwd)\n"
+        "  -femit-bin=[path]            Output machine code\n"
         "  --pkg-begin [name] [path]    make pkg available to import and push current pkg\n"
         "  --pkg-end                    pop current pkg\n"
         "  -ODebug                      build with optimizations on and safety off\n"
src/Compilation.zig
@@ -714,6 +714,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             };
         };
 
+        if (!use_llvm and options.emit_h != null) {
+            fatal("TODO implement support for -femit-h in the self-hosted backend", .{});
+        }
+
         const bin_file = try link.File.openPath(gpa, .{
             .emit = bin_file_emit,
             .root_name = root_name,
@@ -1313,13 +1317,13 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
         const tmp_dir_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest });
         var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
         defer zig_cache_tmp_dir.close();
-        const cimport_c_basename = "cimport.c";
+        const cimport_basename = "cimport.h";
         const out_h_path = try comp.local_cache_directory.join(arena, &[_][]const u8{
-            tmp_dir_sub_path, cimport_c_basename,
+            tmp_dir_sub_path, cimport_basename,
         });
         const out_dep_path = try std.fmt.allocPrint(arena, "{}.d", .{out_h_path});
 
-        try zig_cache_tmp_dir.writeFile(cimport_c_basename, c_src);
+        try zig_cache_tmp_dir.writeFile(cimport_basename, c_src);
         if (comp.verbose_cimport) {
             log.info("C import source: {}", .{out_h_path});
         }
@@ -2542,6 +2546,9 @@ fn updateStage1Module(comp: *Compilation) !void {
         });
         break :blk try directory.join(arena, &[_][]const u8{bin_basename});
     } else "";
+    if (comp.emit_h != null) {
+        log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});
+    }
     const emit_h_path = try stage1LocPath(arena, comp.emit_h, directory);
     const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
     const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
src/main.zig
@@ -7,16 +7,18 @@ const process = std.process;
 const Allocator = mem.Allocator;
 const ArrayList = std.ArrayList;
 const ast = std.zig.ast;
+const warn = std.log.warn;
+
 const Compilation = @import("Compilation.zig");
 const link = @import("link.zig");
 const Package = @import("Package.zig");
 const zir = @import("zir.zig");
 const build_options = @import("build_options");
-const warn = std.log.warn;
 const introspect = @import("introspect.zig");
 const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
 const translate_c = @import("translate_c.zig");
 const Cache = @import("Cache.zig");
+const target_util = @import("target.zig");
 
 pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
     std.log.emerg(format, args);
@@ -773,6 +775,7 @@ fn buildOutputType(
                         dll_export_fns = false;
                     } else if (mem.eql(u8, arg, "--show-builtin")) {
                         show_builtin = true;
+                        emit_bin = .no;
                     } else if (mem.eql(u8, arg, "--strip")) {
                         strip = true;
                     } else if (mem.eql(u8, arg, "--single-threaded")) {
@@ -1219,12 +1222,12 @@ fn buildOutputType(
         var i: usize = 0;
         while (i < system_libs.items.len) {
             const lib_name = system_libs.items[i];
-            if (is_libc_lib_name(target_info.target, lib_name)) {
+            if (target_util.is_libc_lib_name(target_info.target, lib_name)) {
                 link_libc = true;
                 _ = system_libs.orderedRemove(i);
                 continue;
             }
-            if (is_libcpp_lib_name(target_info.target, lib_name)) {
+            if (target_util.is_libcpp_lib_name(target_info.target, lib_name)) {
                 link_libcpp = true;
                 _ = system_libs.orderedRemove(i);
                 continue;
@@ -2809,62 +2812,6 @@ pub const ClangArgIterator = struct {
     }
 };
 
-fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
-    if (ignore_case) {
-        return std.ascii.eqlIgnoreCase(a, b);
-    } else {
-        return mem.eql(u8, a, b);
-    }
-}
-
-fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
-    const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
-
-    if (eqlIgnoreCase(ignore_case, name, "c"))
-        return true;
-
-    if (target.isMinGW()) {
-        if (eqlIgnoreCase(ignore_case, name, "m"))
-            return true;
-
-        return false;
-    }
-
-    if (target.abi.isGnu() or target.abi.isMusl() or target.os.tag.isDarwin()) {
-        if (eqlIgnoreCase(ignore_case, name, "m"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "rt"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "pthread"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "crypt"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "util"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "xnet"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "resolv"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "dl"))
-            return true;
-        if (eqlIgnoreCase(ignore_case, name, "util"))
-            return true;
-    }
-
-    if (target.os.tag.isDarwin() and eqlIgnoreCase(ignore_case, name, "System"))
-        return true;
-
-    return false;
-}
-
-fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool {
-    const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
-
-    return eqlIgnoreCase(ignore_case, name, "c++") or
-        eqlIgnoreCase(ignore_case, name, "stdc++") or
-        eqlIgnoreCase(ignore_case, name, "c++abi");
-}
-
 fn parseCodeModel(arg: []const u8) std.builtin.CodeModel {
     return std.meta.stringToEnum(std.builtin.CodeModel, arg) orelse
         fatal("unsupported machine code model: '{}'", .{arg});
src/stage1.zig
@@ -5,13 +5,15 @@
 const std = @import("std");
 const assert = std.debug.assert;
 const mem = std.mem;
+const CrossTarget = std.zig.CrossTarget;
+const Target = std.Target;
+
 const build_options = @import("build_options");
 const stage2 = @import("main.zig");
 const fatal = stage2.fatal;
-const CrossTarget = std.zig.CrossTarget;
-const Target = std.Target;
 const Compilation = @import("Compilation.zig");
 const translate_c = @import("translate_c.zig");
+const target_util = @import("target.zig");
 
 comptime {
     assert(std.builtin.link_libc);
@@ -370,7 +372,25 @@ export fn stage2_add_link_lib(
     symbol_name_ptr: [*c]const u8,
     symbol_name_len: usize,
 ) ?[*:0]const u8 {
-    return null; // no error
+    const comp = @intToPtr(*Compilation, stage1.userdata);
+    const lib_name = lib_name_ptr[0..lib_name_len];
+    const symbol_name = symbol_name_ptr[0..symbol_name_len];
+    const target = comp.getTarget();
+    const is_libc = target_util.is_libc_lib_name(target, lib_name);
+    if (is_libc and !comp.bin_file.options.link_libc) {
+        return "dependency on libc must be explicitly specified in the build command";
+    }
+
+    if (!is_libc and !target.isWasm() and !comp.bin_file.options.pic) {
+        const msg = std.fmt.allocPrint0(
+            comp.gpa,
+            "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
+            .{ lib_name, lib_name },
+        ) catch return "out of memory";
+        return msg.ptr;
+    }
+
+    return null;
 }
 
 export fn stage2_fetch_file(
src/target.zig
@@ -223,3 +223,59 @@ pub fn osToLLVM(os_tag: std.Target.Os.Tag) llvm.OSType {
         .emscripten => .Emscripten,
     };
 }
+
+fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
+    if (ignore_case) {
+        return std.ascii.eqlIgnoreCase(a, b);
+    } else {
+        return std.mem.eql(u8, a, b);
+    }
+}
+
+pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
+    const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
+
+    if (eqlIgnoreCase(ignore_case, name, "c"))
+        return true;
+
+    if (target.isMinGW()) {
+        if (eqlIgnoreCase(ignore_case, name, "m"))
+            return true;
+
+        return false;
+    }
+
+    if (target.abi.isGnu() or target.abi.isMusl() or target.os.tag.isDarwin()) {
+        if (eqlIgnoreCase(ignore_case, name, "m"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "rt"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "pthread"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "crypt"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "util"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "xnet"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "resolv"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "dl"))
+            return true;
+        if (eqlIgnoreCase(ignore_case, name, "util"))
+            return true;
+    }
+
+    if (target.os.tag.isDarwin() and eqlIgnoreCase(ignore_case, name, "System"))
+        return true;
+
+    return false;
+}
+
+pub fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool {
+    const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
+
+    return eqlIgnoreCase(ignore_case, name, "c++") or
+        eqlIgnoreCase(ignore_case, name, "stdc++") or
+        eqlIgnoreCase(ignore_case, name, "c++abi");
+}
test/compile_errors.zig
@@ -2347,7 +2347,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
             \\    exit(0);
             \\}
         , &[_][]const u8{
-            "tmp.zig:3:5: error: dependency on library c must be explicitly specified in the build command",
+            "tmp.zig:3:5: error: dependency on libc must be explicitly specified in the build command",
         });
 
         cases.addTest("libc headers note",
test/tests.zig
@@ -634,7 +634,7 @@ pub const StackTracesContext = struct {
 
             warn("Test {}/{} {}...", .{ self.test_index + 1, self.context.test_index, self.name });
 
-            const child = std.ChildProcess.init(args.span(), b.allocator) catch unreachable;
+            const child = std.ChildProcess.init(args.items, b.allocator) catch unreachable;
             defer child.deinit();
 
             child.stdin_behavior = .Ignore;
@@ -643,7 +643,7 @@ pub const StackTracesContext = struct {
             child.env_map = b.env_map;
 
             if (b.verbose) {
-                printInvocation(args.span());
+                printInvocation(args.items);
             }
             child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", .{ full_exe_path, @errorName(err) });
 
@@ -666,23 +666,23 @@ pub const StackTracesContext = struct {
                             code,
                             expect_code,
                         });
-                        printInvocation(args.span());
+                        printInvocation(args.items);
                         return error.TestFailed;
                     }
                 },
                 .Signal => |signum| {
                     warn("Process {} terminated on signal {}\n", .{ full_exe_path, signum });
-                    printInvocation(args.span());
+                    printInvocation(args.items);
                     return error.TestFailed;
                 },
                 .Stopped => |signum| {
                     warn("Process {} stopped on signal {}\n", .{ full_exe_path, signum });
-                    printInvocation(args.span());
+                    printInvocation(args.items);
                     return error.TestFailed;
                 },
                 .Unknown => |code| {
                     warn("Process {} terminated unexpectedly with error code {}\n", .{ full_exe_path, code });
-                    printInvocation(args.span());
+                    printInvocation(args.items);
                     return error.TestFailed;
                 },
             }
@@ -837,34 +837,27 @@ pub const CompileErrorContext = struct {
             } else {
                 try zig_args.append("build-obj");
             }
-            const root_src_basename = self.case.sources.span()[0].filename;
+            const root_src_basename = self.case.sources.items[0].filename;
             try zig_args.append(self.write_src.getOutputPath(root_src_basename));
 
             zig_args.append("--name") catch unreachable;
             zig_args.append("test") catch unreachable;
 
-            zig_args.append("--output-dir") catch unreachable;
-            zig_args.append(b.pathFromRoot(b.cache_root)) catch unreachable;
-
             if (!self.case.target.isNative()) {
                 try zig_args.append("-target");
                 try zig_args.append(try self.case.target.zigTriple(b.allocator));
             }
 
-            switch (self.build_mode) {
-                Mode.Debug => {},
-                Mode.ReleaseSafe => zig_args.append("--release-safe") catch unreachable,
-                Mode.ReleaseFast => zig_args.append("--release-fast") catch unreachable,
-                Mode.ReleaseSmall => zig_args.append("--release-small") catch unreachable,
-            }
+            zig_args.append("-O") catch unreachable;
+            zig_args.append(@tagName(self.build_mode)) catch unreachable;
 
             warn("Test {}/{} {}...", .{ self.test_index + 1, self.context.test_index, self.name });
 
             if (b.verbose) {
-                printInvocation(zig_args.span());
+                printInvocation(zig_args.items);
             }
 
-            const child = std.ChildProcess.init(zig_args.span(), b.allocator) catch unreachable;
+            const child = std.ChildProcess.init(zig_args.items, b.allocator) catch unreachable;
             defer child.deinit();
 
             child.env_map = b.env_map;
@@ -886,19 +879,19 @@ pub const CompileErrorContext = struct {
             switch (term) {
                 .Exited => |code| {
                     if (code == 0) {
-                        printInvocation(zig_args.span());
+                        printInvocation(zig_args.items);
                         return error.CompilationIncorrectlySucceeded;
                     }
                 },
                 else => {
                     warn("Process {} terminated unexpectedly\n", .{b.zig_exe});
-                    printInvocation(zig_args.span());
+                    printInvocation(zig_args.items);
                     return error.TestFailed;
                 },
             }
 
-            const stdout = stdout_buf.span();
-            const stderr = stderr_buf.span();
+            const stdout = stdout_buf.items;
+            const stderr = stderr_buf.items;
 
             if (stdout.len != 0) {
                 warn(
@@ -927,12 +920,12 @@ pub const CompileErrorContext = struct {
 
                 if (!ok) {
                     warn("\n======== Expected these compile errors: ========\n", .{});
-                    for (self.case.expected_errors.span()) |expected| {
+                    for (self.case.expected_errors.items) |expected| {
                         warn("{}\n", .{expected});
                     }
                 }
             } else {
-                for (self.case.expected_errors.span()) |expected| {
+                for (self.case.expected_errors.items) |expected| {
                     if (mem.indexOf(u8, stderr, expected) == null) {
                         warn(
                             \\
@@ -1032,7 +1025,7 @@ pub const CompileErrorContext = struct {
             if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
         }
         const write_src = b.addWriteFiles();
-        for (case.sources.span()) |src_file| {
+        for (case.sources.items) |src_file| {
             write_src.add(src_file.filename, src_file.source);
         }
 
@@ -1079,7 +1072,7 @@ pub const StandaloneContext = struct {
             zig_args.append("--verbose") catch unreachable;
         }
 
-        const run_cmd = b.addSystemCommand(zig_args.span());
+        const run_cmd = b.addSystemCommand(zig_args.items);
 
         const log_step = b.addLog("PASS {}\n", .{annotated_case_name});
         log_step.step.dependOn(&run_cmd.step);
@@ -1179,7 +1172,7 @@ pub const GenHContext = struct {
             const full_h_path = self.obj.getOutputHPath();
             const actual_h = try io.readFileAlloc(b.allocator, full_h_path);
 
-            for (self.case.expected_lines.span()) |expected_line| {
+            for (self.case.expected_lines.items) |expected_line| {
                 if (mem.indexOf(u8, actual_h, expected_line) == null) {
                     warn(
                         \\
@@ -1240,7 +1233,7 @@ pub const GenHContext = struct {
         }
 
         const write_src = b.addWriteFiles();
-        for (case.sources.span()) |src_file| {
+        for (case.sources.items) |src_file| {
             write_src.add(src_file.filename, src_file.source);
         }
 
BRANCH_TODO
@@ -1,18 +1,15 @@
- * restore the legacy -femit-h feature using the stage1 backend
- * tests passing with -Dskip-non-native
- * `-ftime-report`
- *  -fstack-report               print stack size diagnostics\n"
+ * MachO LLD linking
  * subsystem
  * mingw-w64
- * MachO LLD linking
  * COFF LLD linking
  * WASM LLD linking
  * audit the CLI options for stage2
  * audit the base cache hash
  * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
- * restore error messages for stage2_add_link_lib
  * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]
  * try building some software with zig cc to make sure it didn't regress
+ * `-ftime-report`
+ *  -fstack-report               print stack size diagnostics\n"
 
  * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API
  * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API
@@ -51,3 +48,4 @@
  * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime
  * linking hello world with LLD, lld is silently calling exit(1) instead of reporting ok=false. when run standalone the error message is: ld.lld: error: section [index 3] has a sh_offset (0x57000) + sh_size (0x68) that is greater than the file size (0x57060)
  * submit PR to godbolt and update the CLI options (see changes to test/cli.zig)
+ * make proposal about log levels
build.zig
@@ -211,10 +211,7 @@ pub fn build(b: *Builder) !void {
     test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
     test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
     test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
-    const test_cli = tests.addCliTests(b, test_filter, modes);
-    const test_cli_step = b.step("test-cli", "Run zig cli tests");
-    test_cli_step.dependOn(test_cli);
-    test_step.dependOn(test_cli);
+    test_step.dependOn(tests.addCliTests(b, test_filter, modes));
     test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
     test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
     test_step.dependOn(tests.addTranslateCTests(b, test_filter));