authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-20 13:51:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:36-07:00
log91a7ea4ff41fd21e7465ddfe68bace533ab8c77d
tree82b0b6d903cb5c7523ece42694fa846538dc5ce6
parent88e066bb7b69d065758fa05442de6e317625df68

Maker: implement TranslateC


3 files changed, 124 insertions(+), 94 deletions(-)

lib/compiler/Maker/Step.zig+2-1
...@@ -26,6 +26,7 @@ pub const InstallFile = @import("Step/InstallFile.zig");...@@ -26,6 +26,7 @@ pub const InstallFile = @import("Step/InstallFile.zig");
26pub const ObjCopy = @import("Step/ObjCopy.zig");26pub const ObjCopy = @import("Step/ObjCopy.zig");
27pub const Options = @import("Step/Options.zig");27pub const Options = @import("Step/Options.zig");
28pub const Run = @import("Step/Run.zig");28pub const Run = @import("Step/Run.zig");
29pub const TranslateC = @import("Step/TranslateC.zig");
29pub const UpdateSourceFiles = @import("Step/UpdateSourceFiles.zig");30pub const UpdateSourceFiles = @import("Step/UpdateSourceFiles.zig");
30pub const WriteFile = @import("Step/WriteFile.zig");31pub const WriteFile = @import("Step/WriteFile.zig");
3132
...@@ -86,7 +87,7 @@ pub const Extended = union(enum) {...@@ -86,7 +87,7 @@ pub const Extended = union(enum) {
86 options: Options,87 options: Options,
87 run: Run,88 run: Run,
88 top_level: TopLevel,89 top_level: TopLevel,
89 translate_c: Todo,90 translate_c: TranslateC,
90 update_source_files: UpdateSourceFiles,91 update_source_files: UpdateSourceFiles,
91 write_file: WriteFile,92 write_file: WriteFile,
9293
lib/compiler/Maker/Step/Compile.zig+13-15
...@@ -291,18 +291,19 @@ fn lowerZigArgs(...@@ -291,18 +291,19 @@ fn lowerZigArgs(
291 system_lib.flags.preferred_link_mode != prev_preferred_link_mode) and291 system_lib.flags.preferred_link_mode != prev_preferred_link_mode) and
292 conf_comp.flags2.linkage != .static)292 conf_comp.flags2.linkage != .static)
293 {293 {
294 try zig_args.ensureUnusedCapacity(gpa, 1);
294 switch (system_lib.flags.search_strategy) {295 switch (system_lib.flags.search_strategy) {
295 .no_fallback => switch (system_lib.flags.preferred_link_mode) {296 .no_fallback => switch (system_lib.flags.preferred_link_mode) {
296 .dynamic => try zig_args.append(gpa, "-search_dylibs_only"),297 .dynamic => zig_args.appendAssumeCapacity("-search_dylibs_only"),
297 .static => try zig_args.append(gpa, "-search_static_only"),298 .static => zig_args.appendAssumeCapacity("-search_static_only"),
298 },299 },
299 .paths_first => switch (system_lib.flags.preferred_link_mode) {300 .paths_first => switch (system_lib.flags.preferred_link_mode) {
300 .dynamic => try zig_args.append(gpa, "-search_paths_first"),301 .dynamic => zig_args.appendAssumeCapacity("-search_paths_first"),
301 .static => try zig_args.append(gpa, "-search_paths_first_static"),302 .static => zig_args.appendAssumeCapacity("-search_paths_first_static"),
302 },303 },
303 .mode_first => switch (system_lib.flags.preferred_link_mode) {304 .mode_first => switch (system_lib.flags.preferred_link_mode) {
304 .dynamic => try zig_args.append(gpa, "-search_dylibs_first"),305 .dynamic => zig_args.appendAssumeCapacity("-search_dylibs_first"),
305 .static => try zig_args.append(gpa, "-search_static_first"),306 .static => zig_args.appendAssumeCapacity("-search_static_first"),
306 },307 },
307 }308 }
308 prev_search_strategy = system_lib.flags.search_strategy;309 prev_search_strategy = system_lib.flags.search_strategy;
...@@ -1317,6 +1318,7 @@ fn appendModuleFlags(...@@ -1317,6 +1318,7 @@ fn appendModuleFlags(
1317 try zig_args.append(gpa, try allocPrint(arena, "--export={s}", .{symbol_name.slice(conf)}));1318 try zig_args.append(gpa, try allocPrint(arena, "--export={s}", .{symbol_name.slice(conf)}));
1318 }1319 }
13191320
1321 try zig_args.ensureUnusedCapacity(gpa, 2 * m.include_dirs.len);
1320 for (0..m.include_dirs.len) |i|1322 for (0..m.include_dirs.len) |i|
1321 try appendIncludeDirFlags(m.include_dirs.get(conf.extra, i), zig_args, asking_step, maker);1323 try appendIncludeDirFlags(m.include_dirs.get(conf.extra, i), zig_args, asking_step, maker);
13221324
...@@ -1343,17 +1345,16 @@ fn appendModuleFlags(...@@ -1343,17 +1345,16 @@ fn appendModuleFlags(
1343 };1345 };
1344}1346}
13451347
1346fn appendIncludeDirFlags(1348/// Assumes unused capacity for at least 2 items.
1349pub fn appendIncludeDirFlags(
1347 include_dir: Configuration.Module.IncludeDir,1350 include_dir: Configuration.Module.IncludeDir,
1348 zig_args: *std.ArrayList([]const u8),1351 zig_args: *std.ArrayList([]const u8),
1349 asking_step: Configuration.Step.Index,1352 asking_step: Configuration.Step.Index,
1350 maker: *const Maker,1353 maker: *const Maker,
1351) !void {1354) !void {
1352 const gpa = maker.gpa;
1353 const graph = maker.graph;1355 const graph = maker.graph;
1354 const arena = graph.arena; // TODO don't leak into the process arena1356 const arena = graph.arena; // TODO don't leak into the process arena
13551357
1356 try zig_args.ensureUnusedCapacity(gpa, 2);
1357 switch (include_dir) {1358 switch (include_dir) {
1358 .path => |lp| {1359 .path => |lp| {
1359 zig_args.appendAssumeCapacity("-I");1360 zig_args.appendAssumeCapacity("-I");
...@@ -1386,12 +1387,9 @@ fn appendIncludeDirFlags(...@@ -1386,12 +1387,9 @@ fn appendIncludeDirFlags(
1386 comp.installed_headers_include_tree.?.getDirectory();1387 comp.installed_headers_include_tree.?.getDirectory();
1387 },1388 },
1388 .embed_path => |lazy_path| {1389 .embed_path => |lazy_path| {
1389 try zig_args.append(1390 zig_args.appendAssumeCapacity(try allocPrint(arena, "--embed-dir={f}", .{
1390 gpa,1391 try maker.resolveLazyPathIndex(arena, lazy_path, asking_step),
1391 try allocPrint(arena, "--embed-dir={f}", .{1392 }));
1392 try maker.resolveLazyPathIndex(arena, lazy_path, asking_step),
1393 }),
1394 );
1395 },1393 },
1396 }1394 }
1397}1395}
lib/compiler/Maker/Step/TranslateC.zig+109-78
...@@ -1,121 +1,152 @@...@@ -1,121 +1,152 @@
1fn make(step: *Step, options: Step.MakeOptions) !void {1const TranslateC = @This();
2 const prog_node = options.progress_node;2
3 const b = step.owner;3const std = @import("std");
4 const translate_c: *TranslateC = @fieldParentPtr("step", step);4const Io = std.Io;
5 const arena = b.graph.arena;5const Configuration = std.Build.Configuration;
66const allocPrint = std.fmt.allocPrint;
7 var argv_list = std.array_list.Managed([]const u8).init(b.allocator);7const assert = std.debug.assert;
8 try argv_list.append(b.graph.zig_exe);8
9 try argv_list.append("translate-c");9const Step = @import("../Step.zig");
10 if (translate_c.link_libc) {10const Maker = @import("../../Maker.zig");
11 try argv_list.append("-lc");11const PkgConfig = @import("../PkgConfig.zig");
12 }
1312
14 try argv_list.append("--cache-dir");13pub fn make(
15 try argv_list.append(b.cache_root.path orelse ".");14 translate_c: *TranslateC,
15 step_index: Configuration.Step.Index,
16 maker: *Maker,
17 progress_node: std.Progress.Node,
18) Step.ExtendedMakeError!void {
19 _ = translate_c;
20 const graph = maker.graph;
21 const arena = graph.arena; // TODO don't leak into the process arena
22 const step = maker.stepByIndex(step_index);
23 const conf = &maker.scanned_config.configuration;
24 const conf_step = step_index.ptr(conf);
25 const conf_tc = conf_step.extended.get(conf.extra).translate_c;
26 const cache_root = graph.local_cache_root;
1627
17 try argv_list.append("--global-cache-dir");28 var argv: std.ArrayList([]const u8) = .empty;
18 try argv_list.append(b.graph.global_cache_root.path orelse ".");
1929
20 if (!translate_c.target.query.isNative()) {30 try argv.ensureUnusedCapacity(arena, 10);
21 try argv_list.append("-target");31 argv.appendAssumeCapacity(graph.zig_exe);
22 try argv_list.append(try translate_c.target.query.zigTriple(b.allocator));32 argv.appendAssumeCapacity("translate-c");
33 if (conf_tc.flags.link_libc) {
34 argv.appendAssumeCapacity("-lc");
23 }35 }
2436
25 switch (translate_c.optimize) {37 argv.appendAssumeCapacity("--cache-dir");
26 .Debug => {}, // Skip since it's the default.38 argv.appendAssumeCapacity(cache_root.path orelse ".");
27 else => try argv_list.append(b.fmt("-O{s}", .{@tagName(translate_c.optimize)})),39
40 argv.appendAssumeCapacity("--global-cache-dir");
41 argv.appendAssumeCapacity(graph.global_cache_root.path orelse ".");
42
43 if (conf_tc.target.get(conf).?.query.unwrap()) |compact_query| {
44 const query = compact_query.get(conf).unwrap(conf);
45 argv.appendAssumeCapacity("-target");
46 argv.appendAssumeCapacity(try query.zigTriple(arena));
28 }47 }
2948
30 for (translate_c.include_dirs.items) |include_dir| {49 switch (conf_tc.flags.optimize) {
31 try include_dir.appendZigProcessFlags(b, &argv_list, step);50 .debug, .default => {}, // Skip since it's the default.
51 else => argv.appendAssumeCapacity(try allocPrint(arena, "-O{t}", .{conf_tc.flags.optimize})),
32 }52 }
3353
34 for (translate_c.c_macros.items) |c_macro| {54 try argv.ensureUnusedCapacity(arena, conf_tc.include_dirs.len * 2);
35 try argv_list.append("-D");55 for (0..conf_tc.include_dirs.len) |i|
36 try argv_list.append(c_macro);56 try Step.Compile.appendIncludeDirFlags(conf_tc.include_dirs.get(conf.extra, i), &argv, step_index, maker);
57
58 for (conf_tc.c_macros.slice) |c_macro| {
59 (try argv.addManyAsArray(arena, 2)).* = .{ "-D", c_macro.slice(conf) };
37 }60 }
3861
39 var prev_search_strategy: std.Build.Module.SystemLib.SearchStrategy = .paths_first;62 var prev_search_strategy: std.Build.Module.SystemLib.SearchStrategy = .paths_first;
40 var prev_preferred_link_mode: std.builtin.LinkMode = .dynamic;63 var prev_preferred_link_mode: std.builtin.LinkMode = .dynamic;
64 var seen_system_libs: std.AutoArrayHashMapUnmanaged(Configuration.String, []const []const u8) = .empty;
4165
42 for (translate_c.system_libs.items) |*system_lib| {66 for (conf_tc.system_libs.slice) |system_lib_index| {
43 var seen_system_libs: std.StringHashMapUnmanaged([]const []const u8) = .empty;67 const system_lib = system_lib_index.get(conf);
68 const system_lib_name = system_lib.name.slice(conf);
44 const system_lib_gop = try seen_system_libs.getOrPut(arena, system_lib.name);69 const system_lib_gop = try seen_system_libs.getOrPut(arena, system_lib.name);
45 if (system_lib_gop.found_existing) {70 if (system_lib_gop.found_existing) {
46 try argv_list.appendSlice(system_lib_gop.value_ptr.*);71 try argv.appendSlice(arena, system_lib_gop.value_ptr.*);
47 continue;72 continue;
48 } else {73 } else {
49 system_lib_gop.value_ptr.* = &.{};74 system_lib_gop.value_ptr.* = &.{};
50 }75 }
5176
52 if (system_lib.search_strategy != prev_search_strategy or77 if ((system_lib.flags.search_strategy != prev_search_strategy or
53 system_lib.preferred_link_mode != prev_preferred_link_mode)78 system_lib.flags.preferred_link_mode != prev_preferred_link_mode))
54 {79 {
55 switch (system_lib.search_strategy) {80 try argv.ensureUnusedCapacity(arena, 1);
56 .no_fallback => switch (system_lib.preferred_link_mode) {81 switch (system_lib.flags.search_strategy) {
57 .dynamic => try argv_list.append("-search_dylibs_only"),82 .no_fallback => switch (system_lib.flags.preferred_link_mode) {
58 .static => try argv_list.append("-search_static_only"),83 .dynamic => argv.appendAssumeCapacity("-search_dylibs_only"),
84 .static => argv.appendAssumeCapacity("-search_static_only"),
59 },85 },
60 .paths_first => switch (system_lib.preferred_link_mode) {86 .paths_first => switch (system_lib.flags.preferred_link_mode) {
61 .dynamic => try argv_list.append("-search_paths_first"),87 .dynamic => argv.appendAssumeCapacity("-search_paths_first"),
62 .static => try argv_list.append("-search_paths_first_static"),88 .static => argv.appendAssumeCapacity("-search_paths_first_static"),
63 },89 },
64 .mode_first => switch (system_lib.preferred_link_mode) {90 .mode_first => switch (system_lib.flags.preferred_link_mode) {
65 .dynamic => try argv_list.append("-search_dylibs_first"),91 .dynamic => argv.appendAssumeCapacity("-search_dylibs_first"),
66 .static => try argv_list.append("-search_static_first"),92 .static => argv.appendAssumeCapacity("-search_static_first"),
67 },93 },
68 }94 }
69 prev_search_strategy = system_lib.search_strategy;95 prev_search_strategy = system_lib.flags.search_strategy;
70 prev_preferred_link_mode = system_lib.preferred_link_mode;96 prev_preferred_link_mode = system_lib.flags.preferred_link_mode;
71 }97 }
7298
73 const prefix: []const u8 = prefix: {99 const prefix: []const u8 = prefix: {
74 if (system_lib.needed) break :prefix "-needed-l";100 if (system_lib.flags.needed) break :prefix "-needed-l";
75 if (system_lib.weak) break :prefix "-weak-l";101 if (system_lib.flags.weak) break :prefix "-weak-l";
76 break :prefix "-l";102 break :prefix "-l";
77 };103 };
78 switch (system_lib.use_pkg_config) {104 l: {
79 .no => try argv_list.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })),105 pc: {
80 .yes, .force => {106 const force = switch (system_lib.flags.use_pkg_config) {
81 if (Step.Compile.runPkgConfig(&translate_c.step, system_lib.name)) |result| {107 .no => break :pc,
82 try argv_list.appendSlice(result.cflags);108 .yes => false,
83 try argv_list.appendSlice(result.libs);109 .force => true,
110 };
111
112 const pkg_conf_node = progress_node.start("pkg-config", 0);
113 defer pkg_conf_node.end();
114
115 if (PkgConfig.run(maker, step, pkg_conf_node, system_lib_name, force)) |result| {
116 try argv.appendSlice(arena, result.cflags);
117 try argv.appendSlice(arena, result.libs);
84 try seen_system_libs.put(arena, system_lib.name, result.cflags);118 try seen_system_libs.put(arena, system_lib.name, result.cflags);
119 break :l;
85 } else |err| switch (err) {120 } else |err| switch (err) {
86 error.PkgConfigInvalidOutput,121 error.PkgConfigUnavailable,
87 error.PkgConfigCrashed,
88 error.PkgConfigFailed,
89 error.PkgConfigNotInstalled,
90 error.PackageNotFound,122 error.PackageNotFound,
91 => switch (system_lib.use_pkg_config) {123 => {
92 .yes => {124 // pkg-config failed, so fall back to linking the library by name directly.
93 // pkg-config failed, so fall back to linking the library125 assert(!force);
94 // by name directly.126 break :pc;
95 try argv_list.append(b.fmt("{s}{s}", .{
96 prefix,
97 system_lib.name,
98 }));
99 },
100 .force => {
101 std.debug.panic("pkg-config failed for library {s}", .{system_lib.name});
102 },
103 .no => unreachable,
104 },127 },
105
106 else => |e| return e,128 else => |e| return e,
107 }129 }
108 },130 }
131 try argv.append(arena, try allocPrint(arena, "{s}{s}", .{
132 prefix, system_lib_name,
133 }));
109 }134 }
110 }135 }
111136
112 const c_source_path = translate_c.source.getPath2(b, step);137 try argv.ensureUnusedCapacity(arena, 2);
113 try argv_list.append(c_source_path);138
139 const c_source_path = try maker.resolveLazyPathIndexAbs(arena, conf_tc.src_path, step_index);
140 argv.appendAssumeCapacity(c_source_path);
141
142 argv.appendAssumeCapacity("--listen=-");
143 const output_dir_path = (Step.evalZigProcess(step_index, maker, argv.items, progress_node, false) catch |err| switch (err) {
144 error.NeedCompileErrorCheck => unreachable,
145 else => |e| return e,
146 }).?;
114147
115 try argv_list.append("--listen=-");148 const stem = Io.Dir.path.stem(Io.Dir.path.basename(c_source_path));
116 const output_dir = try step.evalZigProcess(argv_list.items, prog_node, false, options.web_server, options.gpa);149 const out_basename = try allocPrint(arena, "{s}.zig", .{stem});
117150
118 const basename = std.fs.path.stem(std.fs.path.basename(c_source_path));151 maker.generatedPath(conf_tc.output_file).* = try output_dir_path.join(arena, out_basename);
119 translate_c.out_basename = b.fmt("{s}.zig", .{basename});
120 translate_c.output_file.path = output_dir.?.joinString(b.allocator, translate_c.out_basename) catch @panic("OOM");
121}152}