From b6556c944b88726c2bdb34ce72358ade88c5a984 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 26 Sep 2020 21:03:38 -0700 Subject: [PATCH] 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. --- BRANCH_TODO | 10 +- build.zig | 5 +- doc/docgen.zig | 247 ++++++++++++++-------------------------- doc/langref.html.in | 1 + lib/std/log.zig | 8 +- src/Compilation.zig | 13 ++- src/main.zig | 65 +---------- src/stage1.zig | 26 ++++- src/stage1/stage1.h | 2 +- src/stage1/zig0.cpp | 2 +- src/target.zig | 56 +++++++++ test/compile_errors.zig | 2 +- test/tests.zig | 49 ++++---- 13 files changed, 213 insertions(+), 273 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index b224b2a7fe..5306f29746 100644 --- a/BRANCH_TODO +++ b/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 diff --git a/build.zig b/build.zig index df575e3356..b4d8b71f79 100644 --- a/build.zig +++ b/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)); diff --git a/doc/docgen.zig b/doc/docgen.zig index af4d2530d0..50523d0948 100644 --- a/doc/docgen.zig +++ b/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("
$ 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("
$ 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("
$ 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("
$ zig build-obj {}.zig", .{code.name});
                         }
 
                         switch (code.mode) {
                             .Debug => {},
-                            .ReleaseSafe => {
-                                try build_args.append("--release-safe");
+                            else => {
+                                try build_args.appendSlice(&[_][]const u8{ "-O", @tagName(code.mode) });
                                 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");
-                                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("
$ 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{}{}
\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", .{}); +} diff --git a/doc/langref.html.in b/doc/langref.html.in index 740984619b..320b10bbe5 100644 --- a/doc/langref.html.in +++ b/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:

{#code_begin|obj|foo#} {#code_release_fast#} + {#code_disable_cache#} const std = @import("std"); const builtin = std.builtin; const big = @as(f64, 1 << 40); diff --git a/lib/std/log.zig b/lib/std/log.zig index bc83e6053d..0cc2b54452 100644 --- a/lib/std/log.zig +++ b/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", diff --git a/src/Compilation.zig b/src/Compilation.zig index fc042cdd47..10adfb8c45 100644 --- a/src/Compilation.zig +++ b/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); diff --git a/src/main.zig b/src/main.zig index 572ab4b7b0..31eaf5d8ae 100644 --- a/src/main.zig +++ b/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}); diff --git a/src/stage1.zig b/src/stage1.zig index d05c0ba7fb..2124c23f14 100644 --- a/src/stage1.zig +++ b/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( diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h index e5ffa62e14..efbd02e393 100644 --- a/src/stage1/stage1.h +++ b/src/stage1/stage1.h @@ -117,8 +117,8 @@ struct Stage2ProgressNode; enum BuildMode { BuildModeDebug, - BuildModeFastRelease, BuildModeSafeRelease, + BuildModeFastRelease, BuildModeSmallRelease, }; diff --git a/src/stage1/zig0.cpp b/src/stage1/zig0.cpp index e63c68bc94..839ff0263f 100644 --- a/src/stage1/zig0.cpp +++ b/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" diff --git a/src/target.zig b/src/target.zig index 0402ccbd51..9b5ea2a366 100644 --- a/src/target.zig +++ b/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"); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f457c74609..d27517bc38 100644 --- a/test/compile_errors.zig +++ b/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", diff --git a/test/tests.zig b/test/tests.zig index 6598a05ea7..58b2b50094 100644 --- a/test/tests.zig +++ b/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); }