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.
master
Andrew Kelley 2020-09-26 21:03:38 -07:00
parent fe4c348f57
commit b6556c944b
13 changed files with 213 additions and 273 deletions

View File

@ -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

View File

@ -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));

View File

@ -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");
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("<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", .{});
}

View File

@ -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);

View File

@ -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",

View File

@ -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);

View File

@ -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});

View File

@ -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(

View File

@ -117,8 +117,8 @@ struct Stage2ProgressNode;
enum BuildMode {
BuildModeDebug,
BuildModeFastRelease,
BuildModeSafeRelease,
BuildModeFastRelease,
BuildModeSmallRelease,
};

View File

@ -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"

View File

@ -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");
}

View File

@ -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",

View File

@ -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);
}