diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-06-27 20:05:22 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-07-07 22:43:51 -0700 |
| commit | 0e37ff0d591dd75ceec9208196bec29efaec607a (patch) | |
| tree | c126fa823a1f3864e9c363aac70e3a3db0219957 /lib/std/Build/Step/ConfigHeader.zig | |
| parent | 0b3f0124dc33403d329fb8ee63a93215d9af1f1e (diff) | |
| download | zig-0e37ff0d591dd75ceec9208196bec29efaec607a.tar.gz zig-0e37ff0d591dd75ceec9208196bec29efaec607a.zip | |
std.fmt: breaking API changes
added adapter to AnyWriter and GenericWriter to help bridge the gap
between old and new API
make std.testing.expectFmt work at compile-time
std.fmt no longer has a dependency on std.unicode. Formatted printing
was never properly unicode-aware. Now it no longer pretends to be.
Breakage/deprecations:
* std.fs.File.reader -> std.fs.File.deprecatedReader
* std.fs.File.writer -> std.fs.File.deprecatedWriter
* std.io.GenericReader -> std.io.Reader
* std.io.GenericWriter -> std.io.Writer
* std.io.AnyReader -> std.io.Reader
* std.io.AnyWriter -> std.io.Writer
* std.fmt.format -> std.fmt.deprecatedFormat
* std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape
* std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape
* std.fmt.fmtSliceHexLower -> {x}
* std.fmt.fmtSliceHexUpper -> {X}
* std.fmt.fmtIntSizeDec -> {B}
* std.fmt.fmtIntSizeBin -> {Bi}
* std.fmt.fmtDuration -> {D}
* std.fmt.fmtDurationSigned -> {D}
* {} -> {f} when there is a format method
* format method signature
- anytype -> *std.io.Writer
- inferred error set -> error{WriteFailed}
- options -> (deleted)
* std.fmt.Formatted
- now takes context type explicitly
- no fmt string
Diffstat (limited to 'lib/std/Build/Step/ConfigHeader.zig')
| -rw-r--r-- | lib/std/Build/Step/ConfigHeader.zig | 230 |
1 files changed, 91 insertions, 139 deletions
diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index 967e1edd05..d8a7a08b33 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -2,6 +2,7 @@ const std = @import("std"); const ConfigHeader = @This(); const Step = std.Build.Step; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; pub const Style = union(enum) { /// A configure format supported by autotools that uses `#undef foo` to @@ -87,7 +88,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { owner.fmt("configure {s} header to {s}", .{ @tagName(options.style), include_path }); config_header.* = .{ - .step = Step.init(.{ + .step = .init(.{ .id = base_id, .name = name, .owner = owner, @@ -95,7 +96,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { .first_ret_addr = options.first_ret_addr orelse @returnAddress(), }), .style = options.style, - .values = std.StringArrayHashMap(Value).init(owner.allocator), + .values = .init(owner.allocator), .max_bytes = options.max_bytes, .include_path = include_path, @@ -195,8 +196,9 @@ fn make(step: *Step, options: Step.MakeOptions) !void { man.hash.addBytes(config_header.include_path); man.hash.addOptionalBytes(config_header.include_guard_override); - var output = std.ArrayList(u8).init(gpa); - defer output.deinit(); + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; const header_text = "This file was generated by ConfigHeader using the Zig Build System."; const c_generated_line = "/* " ++ header_text ++ " */\n"; @@ -204,7 +206,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { switch (config_header.style) { .autoconf_undef, .autoconf, .autoconf_at => |file_source| { - try output.appendSlice(c_generated_line); + try bw.writeAll(c_generated_line); const src_path = file_source.getPath2(b, step); const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| { return step.fail("unable to read autoconf input file '{s}': {s}", .{ @@ -212,32 +214,33 @@ fn make(step: *Step, options: Step.MakeOptions) !void { }); }; switch (config_header.style) { - .autoconf_undef, .autoconf => try render_autoconf_undef(step, contents, &output, config_header.values, src_path), - .autoconf_at => try render_autoconf_at(step, contents, &output, config_header.values, src_path), + .autoconf_undef, .autoconf => try render_autoconf_undef(step, contents, bw, config_header.values, src_path), + .autoconf_at => try render_autoconf_at(step, contents, &aw, config_header.values, src_path), else => unreachable, } }, .cmake => |file_source| { - try output.appendSlice(c_generated_line); + try bw.writeAll(c_generated_line); const src_path = file_source.getPath2(b, step); const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| { return step.fail("unable to read cmake input file '{s}': {s}", .{ src_path, @errorName(err), }); }; - try render_cmake(step, contents, &output, config_header.values, src_path); + try render_cmake(step, contents, bw, config_header.values, src_path); }, .blank => { - try output.appendSlice(c_generated_line); - try render_blank(&output, config_header.values, config_header.include_path, config_header.include_guard_override); + try bw.writeAll(c_generated_line); + try render_blank(gpa, bw, config_header.values, config_header.include_path, config_header.include_guard_override); }, .nasm => { - try output.appendSlice(asm_generated_line); - try render_nasm(&output, config_header.values); + try bw.writeAll(asm_generated_line); + try render_nasm(bw, config_header.values); }, } - man.hash.addBytes(output.items); + const output = aw.getWritten(); + man.hash.addBytes(output); if (try step.cacheHit(&man)) { const digest = man.final(); @@ -256,13 +259,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void { const sub_path_dirname = std.fs.path.dirname(sub_path).?; b.cache_root.handle.makePath(sub_path_dirname) catch |err| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.cache_root, sub_path_dirname, @errorName(err), }); }; - b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = output.items }) catch |err| { - return step.fail("unable to write file '{}{s}': {s}", .{ + b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = output }) catch |err| { + return step.fail("unable to write file '{f}{s}': {s}", .{ b.cache_root, sub_path, @errorName(err), }); }; @@ -274,7 +277,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { fn render_autoconf_undef( step: *Step, contents: []const u8, - output: *std.ArrayList(u8), + bw: *Writer, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { @@ -289,15 +292,15 @@ fn render_autoconf_undef( var line_it = std.mem.splitScalar(u8, contents, '\n'); while (line_it.next()) |line| : (line_index += 1) { if (!std.mem.startsWith(u8, line, "#")) { - try output.appendSlice(line); - try output.appendSlice("\n"); + try bw.writeAll(line); + try bw.writeByte('\n'); continue; } var it = std.mem.tokenizeAny(u8, line[1..], " \t\r"); const undef = it.next().?; if (!std.mem.eql(u8, undef, "undef")) { - try output.appendSlice(line); - try output.appendSlice("\n"); + try bw.writeAll(line); + try bw.writeByte('\n'); continue; } const name = it.next().?; @@ -309,7 +312,7 @@ fn render_autoconf_undef( continue; }; is_used.set(index); - try renderValueC(output, name, values.values()[index]); + try renderValueC(bw, name, values.values()[index]); } var unused_value_it = is_used.iterator(.{ .kind = .unset }); @@ -326,12 +329,13 @@ fn render_autoconf_undef( fn render_autoconf_at( step: *Step, contents: []const u8, - output: *std.ArrayList(u8), + aw: *std.io.Writer.Allocating, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { const build = step.owner; const allocator = build.allocator; + const bw = &aw.interface; const used = allocator.alloc(bool, values.count()) catch @panic("OOM"); for (used) |*u| u.* = false; @@ -343,11 +347,11 @@ fn render_autoconf_at( while (line_it.next()) |line| : (line_index += 1) { const last_line = line_it.index == line_it.buffer.len; - const old_len = output.items.len; - expand_variables_autoconf_at(output, line, values, used) catch |err| switch (err) { + const old_len = aw.getWritten().len; + expand_variables_autoconf_at(bw, line, values, used) catch |err| switch (err) { error.MissingValue => { - const name = output.items[old_len..]; - defer output.shrinkRetainingCapacity(old_len); + const name = aw.getWritten()[old_len..]; + defer aw.shrinkRetainingCapacity(old_len); try step.addError("{s}:{d}: error: unspecified config header value: '{s}'", .{ src_path, line_index + 1, name, }); @@ -362,9 +366,7 @@ fn render_autoconf_at( continue; }, }; - if (!last_line) { - try output.append('\n'); - } + if (!last_line) try bw.writeByte('\n'); } for (values.unmanaged.entries.slice().items(.key), used) |name, u| { @@ -374,15 +376,13 @@ fn render_autoconf_at( } } - if (any_errors) { - return error.MakeFailed; - } + if (any_errors) return error.MakeFailed; } fn render_cmake( step: *Step, contents: []const u8, - output: *std.ArrayList(u8), + bw: *Writer, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { @@ -417,10 +417,8 @@ fn render_cmake( defer allocator.free(line); if (!std.mem.startsWith(u8, line, "#")) { - try output.appendSlice(line); - if (!last_line) { - try output.appendSlice("\n"); - } + try bw.writeAll(line); + if (!last_line) try bw.writeByte('\n'); continue; } var it = std.mem.tokenizeAny(u8, line[1..], " \t\r"); @@ -428,10 +426,8 @@ fn render_cmake( if (!std.mem.eql(u8, cmakedefine, "cmakedefine") and !std.mem.eql(u8, cmakedefine, "cmakedefine01")) { - try output.appendSlice(line); - if (!last_line) { - try output.appendSlice("\n"); - } + try bw.writeAll(line); + if (!last_line) try bw.writeByte('\n'); continue; } @@ -502,7 +498,7 @@ fn render_cmake( value = Value{ .ident = it.rest() }; } - try renderValueC(output, name, value); + try renderValueC(bw, name, value); } if (any_errors) { @@ -511,13 +507,14 @@ fn render_cmake( } fn render_blank( - output: *std.ArrayList(u8), + gpa: std.mem.Allocator, + bw: *Writer, defines: std.StringArrayHashMap(Value), include_path: []const u8, include_guard_override: ?[]const u8, ) !void { const include_guard_name = include_guard_override orelse blk: { - const name = try output.allocator.dupe(u8, include_path); + const name = try gpa.dupe(u8, include_path); for (name) |*byte| { switch (byte.*) { 'a'...'z' => byte.* = byte.* - 'a' + 'A', @@ -527,92 +524,53 @@ fn render_blank( } break :blk name; }; + defer if (include_guard_override == null) gpa.free(include_guard_name); - try output.appendSlice("#ifndef "); - try output.appendSlice(include_guard_name); - try output.appendSlice("\n#define "); - try output.appendSlice(include_guard_name); - try output.appendSlice("\n"); + try bw.print( + \\#ifndef {[0]s} + \\#define {[0]s} + \\ + , .{include_guard_name}); const values = defines.values(); - for (defines.keys(), 0..) |name, i| { - try renderValueC(output, name, values[i]); - } + for (defines.keys(), 0..) |name, i| try renderValueC(bw, name, values[i]); - try output.appendSlice("#endif /* "); - try output.appendSlice(include_guard_name); - try output.appendSlice(" */\n"); + try bw.print( + \\#endif /* {s} */ + \\ + , .{include_guard_name}); } -fn render_nasm(output: *std.ArrayList(u8), defines: std.StringArrayHashMap(Value)) !void { - const values = defines.values(); - for (defines.keys(), 0..) |name, i| { - try renderValueNasm(output, name, values[i]); - } +fn render_nasm(bw: *Writer, defines: std.StringArrayHashMap(Value)) !void { + for (defines.keys(), defines.values()) |name, value| try renderValueNasm(bw, name, value); } -fn renderValueC(output: *std.ArrayList(u8), name: []const u8, value: Value) !void { +fn renderValueC(bw: *Writer, name: []const u8, value: Value) !void { switch (value) { - .undef => { - try output.appendSlice("/* #undef "); - try output.appendSlice(name); - try output.appendSlice(" */\n"); - }, - .defined => { - try output.appendSlice("#define "); - try output.appendSlice(name); - try output.appendSlice("\n"); - }, - .boolean => |b| { - try output.appendSlice("#define "); - try output.appendSlice(name); - try output.appendSlice(if (b) " 1\n" else " 0\n"); - }, - .int => |i| { - try output.writer().print("#define {s} {d}\n", .{ name, i }); - }, - .ident => |ident| { - try output.writer().print("#define {s} {s}\n", .{ name, ident }); - }, - .string => |string| { - // TODO: use C-specific escaping instead of zig string literals - try output.writer().print("#define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) }); - }, + .undef => try bw.print("/* #undef {s} */\n", .{name}), + .defined => try bw.print("#define {s}\n", .{name}), + .boolean => |b| try bw.print("#define {s} {c}\n", .{ name, @as(u8, '0') + @intFromBool(b) }), + .int => |i| try bw.print("#define {s} {d}\n", .{ name, i }), + .ident => |ident| try bw.print("#define {s} {s}\n", .{ name, ident }), + // TODO: use C-specific escaping instead of zig string literals + .string => |string| try bw.print("#define {s} \"{f}\"\n", .{ name, std.zig.fmtString(string) }), } } -fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !void { +fn renderValueNasm(bw: *Writer, name: []const u8, value: Value) !void { switch (value) { - .undef => { - try output.appendSlice("; %undef "); - try output.appendSlice(name); - try output.appendSlice("\n"); - }, - .defined => { - try output.appendSlice("%define "); - try output.appendSlice(name); - try output.appendSlice("\n"); - }, - .boolean => |b| { - try output.appendSlice("%define "); - try output.appendSlice(name); - try output.appendSlice(if (b) " 1\n" else " 0\n"); - }, - .int => |i| { - try output.writer().print("%define {s} {d}\n", .{ name, i }); - }, - .ident => |ident| { - try output.writer().print("%define {s} {s}\n", .{ name, ident }); - }, - .string => |string| { - // TODO: use nasm-specific escaping instead of zig string literals - try output.writer().print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) }); - }, + .undef => try bw.print("; %undef {s}\n", .{name}), + .defined => try bw.print("%define {s}\n", .{name}), + .boolean => |b| try bw.print("%define {s} {c}\n", .{ name, @as(u8, '0') + @intFromBool(b) }), + .int => |i| try bw.print("%define {s} {d}\n", .{ name, i }), + .ident => |ident| try bw.print("%define {s} {s}\n", .{ name, ident }), + // TODO: use nasm-specific escaping instead of zig string literals + .string => |string| try bw.print("%define {s} \"{f}\"\n", .{ name, std.zig.fmtString(string) }), } } fn expand_variables_autoconf_at( - output: *std.ArrayList(u8), + bw: *Writer, contents: []const u8, values: std.StringArrayHashMap(Value), used: []bool, @@ -637,23 +595,17 @@ fn expand_variables_autoconf_at( const key = contents[curr + 1 .. close_pos]; const index = values.getIndex(key) orelse { // Report the missing key to the caller. - try output.appendSlice(key); + try bw.writeAll(key); return error.MissingValue; }; const value = values.unmanaged.entries.slice().items(.value)[index]; used[index] = true; - try output.appendSlice(contents[source_offset..curr]); + try bw.writeAll(contents[source_offset..curr]); switch (value) { .undef, .defined => {}, - .boolean => |b| { - try output.append(if (b) '1' else '0'); - }, - .int => |i| { - try output.writer().print("{d}", .{i}); - }, - .ident, .string => |s| { - try output.appendSlice(s); - }, + .boolean => |b| try bw.writeByte(@as(u8, '0') + @intFromBool(b)), + .int => |i| try bw.print("{d}", .{i}), + .ident, .string => |s| try bw.writeAll(s), } curr = close_pos; @@ -661,7 +613,7 @@ fn expand_variables_autoconf_at( } } - try output.appendSlice(contents[source_offset..]); + try bw.writeAll(contents[source_offset..]); } fn expand_variables_cmake( @@ -669,7 +621,7 @@ fn expand_variables_cmake( contents: []const u8, values: std.StringArrayHashMap(Value), ) ![]const u8 { - var result = std.ArrayList(u8).init(allocator); + var result: std.ArrayList(u8) = .init(allocator); errdefer result.deinit(); const valid_varname_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_.+-"; @@ -681,7 +633,7 @@ fn expand_variables_cmake( source: usize, target: usize, }; - var var_stack = std.ArrayList(Position).init(allocator); + var var_stack: std.ArrayList(Position) = .init(allocator); defer var_stack.deinit(); loop: while (curr < contents.len) : (curr += 1) { switch (contents[curr]) { @@ -707,7 +659,7 @@ fn expand_variables_cmake( try result.append(if (b) '1' else '0'); }, .int => |i| { - try result.writer().print("{d}", .{i}); + try result.print("{d}", .{i}); }, .ident, .string => |s| { try result.appendSlice(s); @@ -764,7 +716,7 @@ fn expand_variables_cmake( try result.append(if (b) '1' else '0'); }, .int => |i| { - try result.writer().print("{d}", .{i}); + try result.print("{d}", .{i}); }, .ident, .string => |s| { try result.appendSlice(s); @@ -801,17 +753,17 @@ fn testReplaceVariablesAutoconfAt( expected: []const u8, values: std.StringArrayHashMap(Value), ) !void { - var output = std.ArrayList(u8).init(allocator); + var output: std.io.Writer.Allocating = .init(allocator); defer output.deinit(); const used = try allocator.alloc(bool, values.count()); for (used) |*u| u.* = false; defer allocator.free(used); - try expand_variables_autoconf_at(&output, contents, values, used); + try expand_variables_autoconf_at(&output.interface, contents, values, used); for (used) |u| if (!u) return error.UnusedValue; - try std.testing.expectEqualStrings(expected, output.items); + try std.testing.expectEqualStrings(expected, output.getWritten()); } fn testReplaceVariablesCMake( @@ -828,7 +780,7 @@ fn testReplaceVariablesCMake( test "expand_variables_autoconf_at simple cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); // empty strings are preserved @@ -924,7 +876,7 @@ test "expand_variables_autoconf_at simple cases" { test "expand_variables_autoconf_at edge cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); // @-vars resolved only when they wrap valid characters, otherwise considered literals @@ -940,7 +892,7 @@ test "expand_variables_autoconf_at edge cases" { test "expand_variables_cmake simple cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); try values.putNoClobber("undef", .undef); @@ -1028,7 +980,7 @@ test "expand_variables_cmake simple cases" { test "expand_variables_cmake edge cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); // special symbols @@ -1089,7 +1041,7 @@ test "expand_variables_cmake edge cases" { test "expand_variables_cmake escaped characters" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); try values.putNoClobber("string", Value{ .string = "text" }); |
