authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-12-23 23:53:14-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 17:51:21-07:00
log1ef4df9044a01f78841393f7b92da742775ffbfb
treeec85675a049a87cf4e4add9748364854f81dc7dd
parent524dc756b30c19db070362c8094459c7c8e4fd8a

std.Build.Step.Compile: support modules with different args

Now that the CLI supports per-module settings, the build system takes advantage of this when lowering a compilation to the command line.

1 files changed, 64 insertions(+), 78 deletions(-)

lib/std/Build/Step/Compile.zig+64-78
...@@ -831,81 +831,42 @@ pub fn setExecCmd(self: *Compile, args: []const ?[]const u8) void {...@@ -831,81 +831,42 @@ pub fn setExecCmd(self: *Compile, args: []const ?[]const u8) void {
831 self.exec_cmd_args = duped_args;831 self.exec_cmd_args = duped_args;
832}832}
833833
834fn appendModuleArgs(cs: *Compile, zig_args: *ArrayList([]const u8)) !void {834const CliNamedModules = struct {
835 const b = cs.step.owner;835 modules: std.AutoArrayHashMapUnmanaged(*Module, void),
836 // First, traverse the whole dependency graph and give every module a836 names: std.StringArrayHashMapUnmanaged(void),
837 // unique name, ideally one named after what it's called somewhere in the837
838 // graph. It will help here to have both a mapping from module to name and838 /// Traverse the whole dependency graph and give every module a unique
839 // a set of all the currently-used names.839 /// name, ideally one named after what it's called somewhere in the graph.
840 var mod_names: std.AutoArrayHashMapUnmanaged(*Module, []const u8) = .{};840 /// It will help here to have both a mapping from module to name and a set
841 var names = std.StringHashMap(void).init(b.allocator);841 /// of all the currently-used names.
842842 fn init(arena: Allocator, root_module: *Module) Allocator.Error!CliNamedModules {
843 {843 var self: CliNamedModules = .{
844 var it = cs.root_module.iterateDependencies(null, false);844 .modules = .{},
845 _ = it.next(); // Skip over the root module.845 .names = .{},
846 };
847 var it = root_module.iterateDependencies(null, false);
848 {
849 const item = it.next().?;
850 assert(root_module == item.module);
851 try self.modules.put(arena, root_module, {});
852 try self.names.put(arena, "root", {});
853 }
846 while (it.next()) |item| {854 while (it.next()) |item| {
847 // While we're traversing the root dependencies, let's make sure that no module names
848 // have colons in them, since the CLI forbids it. We handle this for transitive
849 // dependencies further down.
850 if (std.mem.indexOfScalar(u8, item.name, ':') != null) {
851 return cs.step.fail("module '{s}' contains a colon", .{item.name});
852 }
853
854 var name = item.name;855 var name = item.name;
855 var n: usize = 0;856 var n: usize = 0;
856 while (names.contains(name)) {857 while (true) {
857 name = b.fmt("{s}{d}", .{ item.name, n });858 const gop = try self.names.getOrPut(arena, name);
859 if (!gop.found_existing) {
860 try self.modules.putNoClobber(arena, item.module, {});
861 break;
862 }
863 name = try std.fmt.allocPrint(arena, "{s}{d}", .{ item.name, n });
858 n += 1;864 n += 1;
859 }865 }
860
861 try mod_names.put(b.allocator, item.module, name);
862 try names.put(name, {});
863 }866 }
867 return self;
864 }868 }
865869};
866 // Since the module names given to the CLI are based off of the exposed
867 // names, we already know that none of the CLI names have colons in them,
868 // so there's no need to check that explicitly.
869
870 // Every module in the graph is now named; output their definitions
871 for (mod_names.keys(), mod_names.values()) |mod, name| {
872 const root_src = mod.root_source_file orelse continue;
873 const deps_str = try constructDepString(b.allocator, mod_names, mod.import_table);
874 const src = root_src.getPath2(mod.owner, &cs.step);
875 try zig_args.append("--mod");
876 try zig_args.append(b.fmt("{s}:{s}:{s}", .{ name, deps_str, src }));
877 }
878
879 // Lastly, output the root dependencies
880 const deps_str = try constructDepString(b.allocator, mod_names, cs.root_module.import_table);
881 if (deps_str.len > 0) {
882 try zig_args.append("--deps");
883 try zig_args.append(deps_str);
884 }
885}
886
887fn constructDepString(
888 allocator: std.mem.Allocator,
889 mod_names: std.AutoArrayHashMapUnmanaged(*Module, []const u8),
890 deps: std.StringArrayHashMapUnmanaged(*Module),
891) ![]const u8 {
892 var deps_str = std.ArrayList(u8).init(allocator);
893 var it = deps.iterator();
894 while (it.next()) |kv| {
895 const expose = kv.key_ptr.*;
896 const name = mod_names.get(kv.value_ptr.*).?;
897 if (std.mem.eql(u8, expose, name)) {
898 try deps_str.writer().print("{s},", .{name});
899 } else {
900 try deps_str.writer().print("{s}={s},", .{ expose, name });
901 }
902 }
903 if (deps_str.items.len > 0) {
904 return deps_str.items[0 .. deps_str.items.len - 1]; // omit trailing comma
905 } else {
906 return "";
907 }
908}
909870
910fn getGeneratedFilePath(self: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) []const u8 {871fn getGeneratedFilePath(self: *Compile, comptime tag_name: []const u8, asking_step: ?*Step) []const u8 {
911 const maybe_path: ?*GeneratedFile = @field(self, tag_name);872 const maybe_path: ?*GeneratedFile = @field(self, tag_name);
...@@ -991,14 +952,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -991,14 +952,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
991 var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;952 var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;
992 // Track the number of positional arguments so that a nice error can be953 // Track the number of positional arguments so that a nice error can be
993 // emitted if there is nothing to link.954 // emitted if there is nothing to link.
994 var total_linker_objects: usize = 0;955 var total_linker_objects: usize = @intFromBool(self.root_module.root_source_file != null);
995
996 if (self.root_module.root_source_file) |lp| {
997 try zig_args.append(lp.getPath(b));
998 total_linker_objects += 1;
999 }
1000
1001 try self.root_module.appendZigProcessFlags(&zig_args, step);
1002956
1003 {957 {
1004 // Fully recursive iteration including dynamic libraries to detect958 // Fully recursive iteration including dynamic libraries to detect
...@@ -1010,6 +964,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1010,6 +964,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1010 }964 }
1011 }965 }
1012966
967 var cli_named_modules = try CliNamedModules.init(b.allocator, &self.root_module);
968
1013 // For this loop, don't chase dynamic libraries because their link969 // For this loop, don't chase dynamic libraries because their link
1014 // objects are already linked.970 // objects are already linked.
1015 var it = self.root_module.iterateDependencies(self, false);971 var it = self.root_module.iterateDependencies(self, false);
...@@ -1233,6 +1189,38 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1233,6 +1189,38 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1233 },1189 },
1234 }1190 }
1235 }1191 }
1192
1193 // We need to emit the --mod argument here so that the above link objects
1194 // have the correct parent module, but only if the module is part of
1195 // this compilation.
1196 if (cli_named_modules.modules.getIndex(module)) |module_cli_index| {
1197 const module_cli_name = cli_named_modules.names.keys()[module_cli_index];
1198 try module.appendZigProcessFlags(&zig_args, step);
1199
1200 // --dep arguments
1201 try zig_args.ensureUnusedCapacity(module.import_table.count() * 2);
1202 for (module.import_table.keys(), module.import_table.values()) |name, dep| {
1203 const dep_index = cli_named_modules.modules.getIndex(dep).?;
1204 const dep_cli_name = cli_named_modules.names.keys()[dep_index];
1205 zig_args.appendAssumeCapacity("--dep");
1206 if (std.mem.eql(u8, dep_cli_name, name)) {
1207 zig_args.appendAssumeCapacity(dep_cli_name);
1208 } else {
1209 zig_args.appendAssumeCapacity(b.fmt("{s}={s}", .{ name, dep_cli_name }));
1210 }
1211 }
1212
1213 // The CLI assumes if it sees a --mod argument that it is a zig
1214 // compilation unit. If there is no root source file, then this
1215 // is not a zig compilation unit - it is perhaps a set of
1216 // linker objects, or C source files instead.
1217 // In such case, there will be only one module, so we can leave
1218 // off the naming here.
1219 if (module.root_source_file) |lp| {
1220 const src = lp.getPath2(b, step);
1221 try zig_args.appendSlice(&.{ "--mod", module_cli_name, src });
1222 }
1223 }
1236 }1224 }
12371225
1238 if (total_linker_objects == 0) {1226 if (total_linker_objects == 0) {
...@@ -1470,8 +1458,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1470,8 +1458,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1470 }1458 }
1471 }1459 }
14721460
1473 try self.appendModuleArgs(&zig_args);
1474
1475 if (b.sysroot) |sysroot| {1461 if (b.sysroot) |sysroot| {
1476 try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });1462 try zig_args.appendSlice(&[_][]const u8{ "--sysroot", sysroot });
1477 }1463 }