From 30dfdfdbd09570f97420413015eb8a1517382961 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 24 Sep 2020 23:50:15 -0700 Subject: [PATCH] fix a round of regressions in this branch * Don't try to generate C header files yet since it will only cause a crash saying the feature is unimplemented. * Rename the CLI options for release modes to use the `-O` prefix to match C compiler precedent. Options are now `-ODebug`, `-OReleaseFast`, `-OReleaseSafe`, `-OReleaseSmall`. The optimization mode matches the enum tags of std.builtin.Mode. It is planned to, at some point, rename std.builtin.Mode to std.builtin.OptimizationMode and modify the tags to be lower case to match the style convention. - Update build.zig code to support this new CLI. * update std.zig.binNameAlloc to support an optional Version and update the implementation to correctly deal with dynamic library version suffixes. --- lib/std/build.zig | 8 +--- lib/std/zig.zig | 47 ++++++++++++++--------- src/Compilation.zig | 6 ++- src/libcxx.zig | 14 ++++++- src/libunwind.zig | 10 +++-- src/main.zig | 92 ++++++++++++++++++++++----------------------- src/test.zig | 7 +++- 7 files changed, 107 insertions(+), 77 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 2c7a0da53a39e70e29eb8803853b44b523836ca8..353862914458d8a4c721faff94dd9ec3c3ee3ecd 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1692,8 +1692,6 @@ pub const LibExeObjStep = struct { self.main_pkg_path = dir_path; } - pub const setDisableGenH = @compileError("deprecated; set the emit_h field directly"); - pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void { self.libc_file = libc_file; } @@ -2067,10 +2065,8 @@ pub const LibExeObjStep = struct { } switch (self.build_mode) { - .Debug => {}, - .ReleaseSafe => zig_args.append("--release-safe") catch unreachable, - .ReleaseFast => zig_args.append("--release-fast") catch unreachable, - .ReleaseSmall => zig_args.append("--release-small") catch unreachable, + .Debug => {}, // Skip since it's the default. + else => zig_args.append(builder.fmt("-O{s}", .{@tagName(self.build_mode)})) catch unreachable, } try zig_args.append("--cache-dir"); diff --git a/lib/std/zig.zig b/lib/std/zig.zig index b6dfada6cc0e8a5211dd470602d24cceafe281c1..fc173ecda977f6b2e968b1a87ff2adef133d8111 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -64,17 +64,21 @@ pub fn lineDelta(source: []const u8, start: usize, end: usize) isize { return line; } -/// Returns the standard file system basename of a binary generated by the Zig compiler. -pub fn binNameAlloc( - allocator: *std.mem.Allocator, +pub const BinNameOptions = struct { root_name: []const u8, target: std.Target, output_mode: std.builtin.OutputMode, - link_mode: ?std.builtin.LinkMode, - object_format: ?std.Target.ObjectFormat, -) error{OutOfMemory}![]u8 { - switch (object_format orelse target.getObjectFormat()) { - .coff, .pe => switch (output_mode) { + link_mode: ?std.builtin.LinkMode = null, + object_format: ?std.Target.ObjectFormat = null, + version: ?std.builtin.Version = null, +}; + +/// Returns the standard file system basename of a binary generated by the Zig compiler. +pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 { + const root_name = options.root_name; + const target = options.target; + switch (options.object_format orelse target.getObjectFormat()) { + .coff, .pe => switch (options.output_mode) { .Exe => { const suffix = switch (target.os.tag) { .uefi => ".efi", @@ -83,7 +87,7 @@ pub fn binNameAlloc( return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, suffix }); }, .Lib => { - const suffix = switch (link_mode orelse .Static) { + const suffix = switch (options.link_mode orelse .Static) { .Static => ".lib", .Dynamic => ".dll", }; @@ -91,21 +95,30 @@ pub fn binNameAlloc( }, .Obj => return std.fmt.allocPrint(allocator, "{}.obj", .{root_name}), }, - .elf => switch (output_mode) { + .elf => switch (options.output_mode) { .Exe => return allocator.dupe(u8, root_name), .Lib => { - const suffix = switch (link_mode orelse .Static) { - .Static => ".a", - .Dynamic => ".so", - }; - return std.fmt.allocPrint(allocator, "{}{}{}", .{ target.libPrefix(), root_name, suffix }); + switch (options.link_mode orelse .Static) { + .Static => return std.fmt.allocPrint(allocator, "{}{}.a", .{ + target.libPrefix(), root_name, + }), + .Dynamic => { + if (options.version) |ver| { + return std.fmt.allocPrint(allocator, "{}{}.so.{}.{}.{}", .{ + target.libPrefix(), root_name, ver.major, ver.minor, ver.patch, + }); + } else { + return std.fmt.allocPrint(allocator, "{}{}.so", .{ target.libPrefix(), root_name }); + } + }, + } }, .Obj => return std.fmt.allocPrint(allocator, "{}.o", .{root_name}), }, - .macho => switch (output_mode) { + .macho => switch (options.output_mode) { .Exe => return allocator.dupe(u8, root_name), .Lib => { - const suffix = switch (link_mode orelse .Static) { + const suffix = switch (options.link_mode orelse .Static) { .Static => ".a", .Dynamic => ".dylib", }; diff --git a/src/Compilation.zig b/src/Compilation.zig index 03da22d80c1af1bfba9ab2884def8383d4dd47f3..bdd11abc20d3220d83ed7e4802e20b5be13d0f0a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2562,7 +2562,11 @@ pub fn build_crt_file( defer tracy.end(); const target = comp.getTarget(); - const basename = try std.zig.binNameAlloc(comp.gpa, root_name, target, output_mode, null, null); + const basename = try std.zig.binNameAlloc(comp.gpa, .{ + .root_name = root_name, + .target = target, + .output_mode = output_mode, + }); errdefer comp.gpa.free(basename); // TODO: This is extracted into a local variable to work around a stage1 miscompilation. diff --git a/src/libcxx.zig b/src/libcxx.zig index 4fbca428758912c70489614cb24e999652ebf345..16c9581f8221e417e35f7a8eeabd1a78c21f997e 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -88,7 +88,12 @@ pub fn buildLibCXX(comp: *Compilation) !void { const output_mode = .Lib; const link_mode = .Static; const target = comp.getTarget(); - const basename = try std.zig.binNameAlloc(arena, root_name, target, output_mode, link_mode, null); + const basename = try std.zig.binNameAlloc(arena, .{ + .root_name = root_name, + .target = target, + .output_mode = output_mode, + .link_mode = link_mode, + }); const emit_bin = Compilation.EmitLoc{ .directory = null, // Put it in the cache directory. @@ -205,7 +210,12 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { const output_mode = .Lib; const link_mode = .Static; const target = comp.getTarget(); - const basename = try std.zig.binNameAlloc(arena, root_name, target, output_mode, link_mode, null); + const basename = try std.zig.binNameAlloc(arena, .{ + .root_name = root_name, + .target = target, + .output_mode = output_mode, + .link_mode = link_mode, + }); const emit_bin = Compilation.EmitLoc{ .directory = null, // Put it in the cache directory. diff --git a/src/libunwind.zig b/src/libunwind.zig index 28445b7284857da6c137a04082b013b050a73cb5..cbe632ba94ace72156c5e17db2215b944a44ba4b 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -23,13 +23,16 @@ pub fn buildStaticLib(comp: *Compilation) !void { const output_mode = .Lib; const link_mode = .Static; const target = comp.getTarget(); - const basename = try std.zig.binNameAlloc(arena, root_name, target, output_mode, link_mode, null); - + const basename = try std.zig.binNameAlloc(arena, .{ + .root_name = root_name, + .target = target, + .output_mode = output_mode, + .link_mode = link_mode, + }); const emit_bin = Compilation.EmitLoc{ .directory = null, // Put it in the cache directory. .basename = basename, }; - const unwind_src_list = [_][]const u8{ "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "libunwind.cpp", "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-EHABI.cpp", @@ -40,7 +43,6 @@ pub fn buildStaticLib(comp: *Compilation) !void { "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S", "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S", }; - var c_source_files: [unwind_src_list.len]Compilation.CSourceFile = undefined; for (unwind_src_list) |unwind_src, i| { var cflags = std.ArrayList([]const u8).init(arena); diff --git a/src/main.zig b/src/main.zig index be2c55f828d4a38bf5b97b845c396bf3fb31f1e5..fe4c27ced6008960c84245945994bc312236b14f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -210,11 +210,10 @@ const usage_build_generic = \\ small|kernel| \\ medium|large] \\ --name [name] Override root name (not a file path) - \\ --mode [mode] Set the build mode - \\ Debug (default) optimizations off, safety on - \\ ReleaseFast Optimizations on, safety off - \\ ReleaseSafe Optimizations on, safety on - \\ ReleaseSmall Optimize for small binary, safety off + \\ -ODebug (default) optimizations off, safety on + \\ -OReleaseFast Optimizations on, safety off + \\ -OReleaseSafe Optimizations on, safety on + \\ -OReleaseSmall Optimize for small binary, safety off \\ --pkg-begin [name] [path] Make pkg available to import and push current pkg \\ --pkg-end Pop current pkg \\ --main-pkg-path Set the directory of the root package @@ -307,7 +306,7 @@ pub fn buildOutputType( }, ) !void { var color: Color = .Auto; - var build_mode: std.builtin.Mode = .Debug; + var optimize_mode: std.builtin.Mode = .Debug; var provided_name: ?[]const u8 = null; var link_mode: ?std.builtin.LinkMode = null; var dll_export_fns: ?bool = null; @@ -416,20 +415,23 @@ pub fn buildOutputType( switch (arg_mode) { .build, .translate_c, .zig_test, .run => { + var optimize_mode_string: ?[]const u8 = null; output_mode = switch (arg_mode) { .build => |m| m, .translate_c => .Obj, .zig_test, .run => .Exe, else => unreachable, }; - switch (arg_mode) { - .build => switch (output_mode) { - .Exe => emit_h = .no, - .Obj, .Lib => emit_h = .yes_default_path, - }, - .translate_c, .zig_test, .run => emit_h = .no, - else => unreachable, - } + // TODO finish self-hosted and add support for emitting C header files + emit_h = .no; + //switch (arg_mode) { + // .build => switch (output_mode) { + // .Exe => emit_h = .no, + // .Obj, .Lib => emit_h = .yes_default_path, + // }, + // .translate_c, .zig_test, .run => emit_h = .no, + // else => unreachable, + //} const args = all_args[2..]; var i: usize = 0; while (i < args.len) : (i += 1) { @@ -498,23 +500,10 @@ pub fn buildOutputType( } else { fatal("expected [auto|on|off] after --color, found '{}'", .{next_arg}); } - } else if (mem.eql(u8, arg, "--mode")) { - if (i + 1 >= args.len) { - fatal("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode", .{}); - } + } else if (mem.eql(u8, arg, "-O")) { + if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); i += 1; - const next_arg = args[i]; - if (mem.eql(u8, next_arg, "Debug")) { - build_mode = .Debug; - } else if (mem.eql(u8, next_arg, "ReleaseSafe")) { - build_mode = .ReleaseSafe; - } else if (mem.eql(u8, next_arg, "ReleaseFast")) { - build_mode = .ReleaseFast; - } else if (mem.eql(u8, next_arg, "ReleaseSmall")) { - build_mode = .ReleaseSmall; - } else { - fatal("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode, found '{}'", .{next_arg}); - } + optimize_mode_string = args[i]; } else if (mem.eql(u8, arg, "--stack")) { if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); i += 1; @@ -583,6 +572,8 @@ pub fn buildOutputType( target_mcpu = arg["-mcpu=".len..]; } else if (mem.startsWith(u8, arg, "-mcmodel=")) { machine_code_model = parseCodeModel(arg["-mcmodel=".len..]); + } else if (mem.startsWith(u8, arg, "-O")) { + optimize_mode_string = arg["-O".len..]; } else if (mem.eql(u8, arg, "--dynamic-linker")) { if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); i += 1; @@ -749,6 +740,10 @@ pub fn buildOutputType( }, } } + if (optimize_mode_string) |s| { + optimize_mode = std.meta.stringToEnum(std.builtin.Mode, s) orelse + fatal("unrecognized optimization mode: '{}'", .{s}); + } }, .cc, .cpp => { emit_h = .no; @@ -826,16 +821,16 @@ pub fn buildOutputType( .optimize => { // Alright, what release mode do they want? if (mem.eql(u8, it.only_arg, "Os")) { - build_mode = .ReleaseSmall; + optimize_mode = .ReleaseSmall; } else if (mem.eql(u8, it.only_arg, "O2") or mem.eql(u8, it.only_arg, "O3") or mem.eql(u8, it.only_arg, "O4")) { - build_mode = .ReleaseFast; + optimize_mode = .ReleaseFast; } else if (mem.eql(u8, it.only_arg, "Og") or mem.eql(u8, it.only_arg, "O0")) { - build_mode = .Debug; + optimize_mode = .Debug; } else { try clang_argv.appendSlice(it.other_args); } @@ -999,8 +994,8 @@ pub fn buildOutputType( } if (want_sanitize_c) |wsc| { - if (wsc and build_mode == .ReleaseFast) { - build_mode = .ReleaseSafe; + if (wsc and optimize_mode == .ReleaseFast) { + optimize_mode = .ReleaseSafe; } } @@ -1177,6 +1172,7 @@ pub fn buildOutputType( defer if (cleanup_emit_bin_dir) |*dir| dir.close(); const have_enable_cache = enable_cache orelse false; + const optional_version = if (have_version) version else null; const emit_bin_loc: ?Compilation.EmitLoc = switch (emit_bin) { .no => null, @@ -1193,14 +1189,14 @@ pub fn buildOutputType( }, } }, - .basename = try std.zig.binNameAlloc( - arena, - root_name, - target_info.target, - output_mode, - link_mode, - object_format, - ), + .basename = try std.zig.binNameAlloc(arena, .{ + .root_name = root_name, + .target = target_info.target, + .output_mode = output_mode, + .link_mode = link_mode, + .object_format = object_format, + .version = optional_version, + }), }, .yes => |full_path| b: { const basename = fs.path.basename(full_path); @@ -1374,7 +1370,7 @@ pub fn buildOutputType( .link_mode = link_mode, .dll_export_fns = dll_export_fns, .object_format = object_format, - .optimize_mode = build_mode, + .optimize_mode = optimize_mode, .keep_source_files_loaded = zir_out_path != null, .clang_argv = clang_argv.items, .lld_argv = lld_argv.items, @@ -1411,7 +1407,7 @@ pub fn buildOutputType( .self_exe_path = self_exe_path, .rand = &default_prng.random, .clang_passthrough_mode = arg_mode != .build, - .version = if (have_version) version else null, + .version = optional_version, .libc_installation = if (libc_installation) |*lci| lci else null, .verbose_cc = verbose_cc, .verbose_link = verbose_link, @@ -1977,7 +1973,11 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v const cross_target: std.zig.CrossTarget = .{}; const target_info = try detectNativeTargetInfo(gpa, cross_target); - const exe_basename = try std.zig.binNameAlloc(arena, "build", target_info.target, .Exe, null, null); + const exe_basename = try std.zig.binNameAlloc(arena, .{ + .root_name = "build", + .target = target_info.target, + .output_mode = .Exe, + }); const emit_bin: Compilation.EmitLoc = .{ .directory = null, // Use the local zig-cache. .basename = exe_basename, diff --git a/src/test.zig b/src/test.zig index 558fe3e95dce0159fb6110b8a463c2e828b42734..8ad11efa9c49677b978ba35ba3f5b77ab952ff82 100644 --- a/src/test.zig +++ b/src/test.zig @@ -469,7 +469,12 @@ pub const TestContext = struct { }; const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null; - const bin_name = try std.zig.binNameAlloc(arena, "test_case", target, case.output_mode, null, ofmt); + const bin_name = try std.zig.binNameAlloc(arena, .{ + .root_name = "test_case", + .target = target, + .output_mode = case.output_mode, + .object_format = ofmt, + }); const emit_directory: Compilation.Directory = .{ .path = bogus_path, -- 2.54.0