| ... | @@ -955,7 +955,10 @@ pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void { | ... | @@ -955,7 +955,10 @@ pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void { |
| 955 | /// package's module table using `name`. | 955 | /// package's module table using `name`. |
| 956 | pub fn addModule(cs: *CompileStep, name: []const u8, module: *Module) void { | 956 | pub fn addModule(cs: *CompileStep, name: []const u8, module: *Module) void { |
| 957 | cs.modules.put(cs.builder.dupe(name), module) catch @panic("OOM"); | 957 | cs.modules.put(cs.builder.dupe(name), module) catch @panic("OOM"); |
| 958 | cs.addRecursiveBuildDeps(module); | 958 | |
| | 959 | var done = std.AutoHashMap(*Module, void).init(cs.builder.allocator); |
| | 960 | defer done.deinit(); |
| | 961 | cs.addRecursiveBuildDeps(module, &done) catch @panic("OOM"); |
| 959 | } | 962 | } |
| 960 | | 963 | |
| 961 | /// Adds a module to be used with `@import` without exposing it in the current | 964 | /// Adds a module to be used with `@import` without exposing it in the current |
| ... | @@ -969,10 +972,12 @@ pub fn addOptions(cs: *CompileStep, module_name: []const u8, options: *OptionsSt | ... | @@ -969,10 +972,12 @@ pub fn addOptions(cs: *CompileStep, module_name: []const u8, options: *OptionsSt |
| 969 | addModule(cs, module_name, options.createModule()); | 972 | addModule(cs, module_name, options.createModule()); |
| 970 | } | 973 | } |
| 971 | | 974 | |
| 972 | fn addRecursiveBuildDeps(cs: *CompileStep, module: *Module) void { | 975 | fn addRecursiveBuildDeps(cs: *CompileStep, module: *Module, done: *std.AutoHashMap(*Module, void)) !void { |
| | 976 | if (done.contains(module)) return; |
| | 977 | try done.put(module, {}); |
| 973 | module.source_file.addStepDependencies(&cs.step); | 978 | module.source_file.addStepDependencies(&cs.step); |
| 974 | for (module.dependencies.values()) |dep| { | 979 | for (module.dependencies.values()) |dep| { |
| 975 | cs.addRecursiveBuildDeps(dep); | 980 | try cs.addRecursiveBuildDeps(dep, done); |
| 976 | } | 981 | } |
| 977 | } | 982 | } |
| 978 | | 983 | |
| ... | @@ -1031,22 +1036,110 @@ fn linkLibraryOrObject(self: *CompileStep, other: *CompileStep) void { | ... | @@ -1031,22 +1036,110 @@ fn linkLibraryOrObject(self: *CompileStep, other: *CompileStep) void { |
| 1031 | fn appendModuleArgs( | 1036 | fn appendModuleArgs( |
| 1032 | cs: *CompileStep, | 1037 | cs: *CompileStep, |
| 1033 | zig_args: *ArrayList([]const u8), | 1038 | zig_args: *ArrayList([]const u8), |
| 1034 | name: []const u8, | | |
| 1035 | module: *Module, | | |
| 1036 | ) error{OutOfMemory}!void { | 1039 | ) error{OutOfMemory}!void { |
| 1037 | try zig_args.append("--pkg-begin"); | 1040 | // First, traverse the whole dependency graph and give every module a unique name, ideally one |
| 1038 | try zig_args.append(name); | 1041 | // named after what it's called somewhere in the graph. It will help here to have both a mapping |
| 1039 | try zig_args.append(module.builder.pathFromRoot(module.source_file.getPath(module.builder))); | 1042 | // from module to name and a set of all the currently-used names. |
| | 1043 | var mod_names = std.AutoHashMap(*Module, []const u8).init(cs.builder.allocator); |
| | 1044 | var names = std.StringHashMap(void).init(cs.builder.allocator); |
| | 1045 | |
| | 1046 | var to_name = std.ArrayList(struct { |
| | 1047 | name: []const u8, |
| | 1048 | mod: *Module, |
| | 1049 | }).init(cs.builder.allocator); |
| | 1050 | { |
| | 1051 | var it = cs.modules.iterator(); |
| | 1052 | while (it.next()) |kv| { |
| | 1053 | // While we're traversing the root dependencies, let's make sure that no module names |
| | 1054 | // have colons in them, since the CLI forbids it. We handle this for transitive |
| | 1055 | // dependencies further down. |
| | 1056 | if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) { |
| | 1057 | @panic("Module names cannot contain colons"); |
| | 1058 | } |
| | 1059 | try to_name.append(.{ |
| | 1060 | .name = kv.key_ptr.*, |
| | 1061 | .mod = kv.value_ptr.*, |
| | 1062 | }); |
| | 1063 | } |
| | 1064 | } |
| | 1065 | |
| | 1066 | while (to_name.popOrNull()) |dep| { |
| | 1067 | if (mod_names.contains(dep.mod)) continue; |
| | 1068 | |
| | 1069 | // We'll use this buffer to store the name we decide on |
| | 1070 | var buf = try cs.builder.allocator.alloc(u8, dep.name.len + 32); |
| | 1071 | // First, try just the exposed dependency name |
| | 1072 | std.mem.copy(u8, buf, dep.name); |
| | 1073 | var name = buf[0..dep.name.len]; |
| | 1074 | var n: usize = 0; |
| | 1075 | while (names.contains(name)) { |
| | 1076 | // If that failed, append an incrementing number to the end |
| | 1077 | name = std.fmt.bufPrint(buf, "{s}{}", .{ dep.name, n }) catch unreachable; |
| | 1078 | n += 1; |
| | 1079 | } |
| | 1080 | |
| | 1081 | try mod_names.put(dep.mod, name); |
| | 1082 | try names.put(name, {}); |
| | 1083 | |
| | 1084 | var it = dep.mod.dependencies.iterator(); |
| | 1085 | while (it.next()) |kv| { |
| | 1086 | // Same colon-in-name check as above, but for transitive dependencies. |
| | 1087 | if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) { |
| | 1088 | @panic("Module names cannot contain colons"); |
| | 1089 | } |
| | 1090 | try to_name.append(.{ |
| | 1091 | .name = kv.key_ptr.*, |
| | 1092 | .mod = kv.value_ptr.*, |
| | 1093 | }); |
| | 1094 | } |
| | 1095 | } |
| 1040 | | 1096 | |
| | 1097 | // Since the module names given to the CLI are based off of the exposed names, we already know |
| | 1098 | // that none of the CLI names have colons in them, so there's no need to check that explicitly. |
| | 1099 | |
| | 1100 | // Every module in the graph is now named; output their definitions |
| 1041 | { | 1101 | { |
| 1042 | const keys = module.dependencies.keys(); | 1102 | var it = mod_names.iterator(); |
| 1043 | for (module.dependencies.values(), 0..) |sub_module, i| { | 1103 | while (it.next()) |kv| { |
| 1044 | const sub_name = keys[i]; | 1104 | const mod = kv.key_ptr.*; |
| 1045 | try cs.appendModuleArgs(zig_args, sub_name, sub_module); | 1105 | const name = kv.value_ptr.*; |
| | 1106 | |
| | 1107 | const deps_str = try constructDepString(cs.builder.allocator, mod_names, mod.dependencies); |
| | 1108 | const src = mod.builder.pathFromRoot(mod.source_file.getPath(mod.builder)); |
| | 1109 | try zig_args.append("--mod"); |
| | 1110 | try zig_args.append(try std.fmt.allocPrint(cs.builder.allocator, "{s}:{s}:{s}", .{ name, deps_str, src })); |
| 1046 | } | 1111 | } |
| 1047 | } | 1112 | } |
| 1048 | | 1113 | |
| 1049 | try zig_args.append("--pkg-end"); | 1114 | // Lastly, output the root dependencies |
| | 1115 | const deps_str = try constructDepString(cs.builder.allocator, mod_names, cs.modules); |
| | 1116 | if (deps_str.len > 0) { |
| | 1117 | try zig_args.append("--deps"); |
| | 1118 | try zig_args.append(deps_str); |
| | 1119 | } |
| | 1120 | } |
| | 1121 | |
| | 1122 | fn constructDepString( |
| | 1123 | allocator: std.mem.Allocator, |
| | 1124 | mod_names: std.AutoHashMap(*Module, []const u8), |
| | 1125 | deps: std.StringArrayHashMap(*Module), |
| | 1126 | ) ![]const u8 { |
| | 1127 | var deps_str = std.ArrayList(u8).init(allocator); |
| | 1128 | var it = deps.iterator(); |
| | 1129 | while (it.next()) |kv| { |
| | 1130 | const expose = kv.key_ptr.*; |
| | 1131 | const name = mod_names.get(kv.value_ptr.*).?; |
| | 1132 | if (std.mem.eql(u8, expose, name)) { |
| | 1133 | try deps_str.writer().print("{s},", .{name}); |
| | 1134 | } else { |
| | 1135 | try deps_str.writer().print("{s}={s},", .{ expose, name }); |
| | 1136 | } |
| | 1137 | } |
| | 1138 | if (deps_str.items.len > 0) { |
| | 1139 | return deps_str.items[0 .. deps_str.items.len - 1]; // omit trailing comma |
| | 1140 | } else { |
| | 1141 | return ""; |
| | 1142 | } |
| 1050 | } | 1143 | } |
| 1051 | | 1144 | |
| 1052 | fn make(step: *Step) !void { | 1145 | fn make(step: *Step) !void { |
| ... | @@ -1573,13 +1666,7 @@ fn make(step: *Step) !void { | ... | @@ -1573,13 +1666,7 @@ fn make(step: *Step) !void { |
| 1573 | try zig_args.append("--test-no-exec"); | 1666 | try zig_args.append("--test-no-exec"); |
| 1574 | } | 1667 | } |
| 1575 | | 1668 | |
| 1576 | { | 1669 | try self.appendModuleArgs(&zig_args); |
| 1577 | const keys = self.modules.keys(); | | |
| 1578 | for (self.modules.values(), 0..) |module, i| { | | |
| 1579 | const name = keys[i]; | | |
| 1580 | try self.appendModuleArgs(&zig_args, name, module); | | |
| 1581 | } | | |
| 1582 | } | | |
| 1583 | | 1670 | |
| 1584 | for (self.include_dirs.items) |include_dir| { | 1671 | for (self.include_dirs.items) |include_dir| { |
| 1585 | switch (include_dir) { | 1672 | switch (include_dir) { |