diff options
Diffstat (limited to 'toolchain/akibacompile/main.zig')
| -rw-r--r-- | toolchain/akibacompile/main.zig | 224 |
1 files changed, 115 insertions, 109 deletions
diff --git a/toolchain/akibacompile/main.zig b/toolchain/akibacompile/main.zig index e0ab87c..9a52c1c 100644 --- a/toolchain/akibacompile/main.zig +++ b/toolchain/akibacompile/main.zig @@ -1,5 +1,8 @@ const std = @import("std"); +const MAX_LIBS = 32; +const MAX_NAME = 64; + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -30,39 +33,93 @@ pub fn main() !void { }; defer allocator.free(zon_content); - // Collect all libraries and their dependencies - var all_libs = std.StringHashMap([]const u8).init(allocator); - defer { - var it = all_libs.iterator(); - while (it.next()) |entry| { - allocator.free(entry.value_ptr.*); - } - all_libs.deinit(); - } + // Get all available library names + var available: [MAX_LIBS][MAX_NAME]u8 = undefined; + var available_len: [MAX_LIBS]usize = undefined; + var available_count: usize = 0; - // First pass: find direct dependencies from binary's zon var lib_dir = try std.fs.cwd().openDir(libraries_dir, .{ .iterate = true }); - defer lib_dir.close(); - var lib_iter = lib_dir.iterate(); while (try lib_iter.next()) |entry| { if (entry.kind != .directory) continue; - if (std.mem.indexOf(u8, zon_content, entry.name) != null) { - try collectLibraryDeps(allocator, libraries_dir, entry.name, &all_libs); + if (entry.name.len < MAX_NAME and available_count < MAX_LIBS) { + @memcpy(available[available_count][0..entry.name.len], entry.name); + available_len[available_count] = entry.name.len; + available_count += 1; + } + } + lib_dir.close(); + + // Track which libs are needed + var needed: [MAX_LIBS]bool = [_]bool{false} ** MAX_LIBS; + var deps: [MAX_LIBS][256]u8 = undefined; + var deps_len: [MAX_LIBS]usize = [_]usize{0} ** MAX_LIBS; + + // Mark direct dependencies from binary's zon + for (0..available_count) |i| { + const name = available[i][0..available_len[i]]; + if (std.mem.indexOf(u8, zon_content, name) != null) { + needed[i] = true; } } - // Generate build.zig content - var parts = std.ArrayList([]const u8).init(allocator); - defer { - for (parts.items) |part| { - allocator.free(part); + // Iteratively find transitive dependencies (max 10 passes) + for (0..10) |_| { + var changed = false; + for (0..available_count) |i| { + if (!needed[i]) continue; + + // Read this lib's zon + const lib_zon_path = try std.fmt.allocPrint(allocator, "{s}/{s}/{s}.zon", .{ + libraries_dir, + available[i][0..available_len[i]], + available[i][0..available_len[i]], + }); + defer allocator.free(lib_zon_path); + + const lib_zon = std.fs.cwd().readFileAlloc(allocator, lib_zon_path, 4096) catch continue; + defer allocator.free(lib_zon); + + // Check for dependencies on other libs + for (0..available_count) |j| { + if (i == j) continue; + const dep_name = available[j][0..available_len[j]]; + if (std.mem.indexOf(u8, lib_zon, dep_name) != null) { + if (!needed[j]) { + needed[j] = true; + changed = true; + } + // Record dependency + if (deps_len[i] > 0) { + deps[i][deps_len[i]] = ','; + deps_len[i] += 1; + } + // Check if already in deps + var already = false; + var check_iter = std.mem.splitScalar(u8, deps[i][0..deps_len[i]], ','); + while (check_iter.next()) |existing| { + if (std.mem.eql(u8, existing, dep_name)) { + already = true; + break; + } + } + if (!already) { + @memcpy(deps[i][deps_len[i]..][0..dep_name.len], dep_name); + deps_len[i] += dep_name.len; + } else if (deps_len[i] > 0) { + deps_len[i] -= 1; // Remove the comma we added + } + } + } } - parts.deinit(); + if (!changed) break; } - // Header - try parts.append(try allocator.dupe(u8, + // Build the build.zig content + var content = std.ArrayListUnmanaged(u8){}; + defer content.deinit(allocator); + + try content.appendSlice(allocator, \\const std = @import("std"); \\pub fn build(b: *std.Build) void { \\ const target = b.resolveTargetQuery(.{ @@ -71,44 +128,44 @@ pub fn main() !void { \\ .abi = .none, \\ }); \\ - )); + ); - // Create modules for all libraries - var lib_it = all_libs.iterator(); - while (lib_it.next()) |entry| { - const lib_name = entry.key_ptr.*; - try parts.append(try std.fmt.allocPrint(allocator, + // Create modules for needed libs + for (0..available_count) |i| { + if (!needed[i]) continue; + const name = available[i][0..available_len[i]]; + const module_decl = try std.fmt.allocPrint(allocator, \\ const {s}_module = b.addModule("{s}", .{{ \\ .root_source_file = b.path("../{s}/{s}/{s}.zig"), \\ .target = target, \\ .optimize = .ReleaseSmall, \\ }}); \\ - , .{ lib_name, lib_name, libraries_dir, lib_name, lib_name })); - std.debug.print(" + Library: {s}\n", .{lib_name}); + , .{ name, name, libraries_dir, name, name }); + defer allocator.free(module_decl); + try content.appendSlice(allocator, module_decl); + std.debug.print(" + Library: {s}\n", .{name}); } - // Add library-to-library dependencies - lib_it = all_libs.iterator(); - while (lib_it.next()) |entry| { - const lib_name = entry.key_ptr.*; - const lib_deps = entry.value_ptr.*; - - // Parse deps string and add imports - var dep_iter = std.mem.splitScalar(u8, lib_deps, ','); + // Add inter-library dependencies + for (0..available_count) |i| { + if (!needed[i]) continue; + const name = available[i][0..available_len[i]]; + var dep_iter = std.mem.splitScalar(u8, deps[i][0..deps_len[i]], ','); while (dep_iter.next()) |dep| { - const trimmed = std.mem.trim(u8, dep, " "); - if (trimmed.len > 0) { - try parts.append(try std.fmt.allocPrint(allocator, + if (dep.len > 0) { + const import_stmt = try std.fmt.allocPrint(allocator, \\ {s}_module.addImport("{s}", {s}_module); \\ - , .{ lib_name, trimmed, trimmed })); + , .{ name, dep, dep }); + defer allocator.free(import_stmt); + try content.appendSlice(allocator, import_stmt); } } } // Create executable - try parts.append(try std.fmt.allocPrint(allocator, + const exe_decl = try std.fmt.allocPrint(allocator, \\ const exe = b.addExecutable(.{{ \\ .name = "{s}", \\ .root_module = b.createModule(.{{ @@ -119,28 +176,27 @@ pub fn main() !void { \\ }}); \\ exe.setLinkerScript(b.path("../toolchain/linker/akiba.binary.linker")); \\ - , .{ bin_name, zig_file })); - - // Add library imports to executable - lib_it = all_libs.iterator(); - while (lib_it.next()) |entry| { - const lib_name = entry.key_ptr.*; - try parts.append(try std.fmt.allocPrint(allocator, + , .{ bin_name, zig_file }); + defer allocator.free(exe_decl); + try content.appendSlice(allocator, exe_decl); + + // Add library imports to exe + for (0..available_count) |i| { + if (!needed[i]) continue; + const name = available[i][0..available_len[i]]; + const import_stmt = try std.fmt.allocPrint(allocator, \\ exe.root_module.addImport("{s}", {s}_module); \\ - , .{ lib_name, lib_name })); + , .{ name, name }); + defer allocator.free(import_stmt); + try content.appendSlice(allocator, import_stmt); } - // Footer - try parts.append(try allocator.dupe(u8, + try content.appendSlice(allocator, \\ b.installArtifact(exe); \\} \\ - )); - - // Concatenate all parts - const build_content = try std.mem.concat(allocator, u8, parts.items); - defer allocator.free(build_content); + ); // Create temp directory and build const temp_dir = try std.fmt.allocPrint(allocator, ".akiba-build-{s}", .{bin_name}); @@ -152,7 +208,7 @@ pub fn main() !void { const build_path = try std.fmt.allocPrint(allocator, "{s}/build.zig", .{temp_dir}); defer allocator.free(build_path); - try std.fs.cwd().writeFile(.{ .sub_path = build_path, .data = build_content }); + try std.fs.cwd().writeFile(.{ .sub_path = build_path, .data = content.items }); const result = try std.process.Child.run(.{ .allocator = allocator, @@ -173,53 +229,3 @@ pub fn main() !void { try std.fs.cwd().rename(built_exe, output_path); std.debug.print("✓ Compiled {s}\n", .{bin_name}); } - -fn collectLibraryDeps( - allocator: std.mem.Allocator, - libraries_dir: []const u8, - lib_name: []const u8, - all_libs: *std.StringHashMap([]const u8), -) !void { - // Skip if already processed - if (all_libs.contains(lib_name)) return; - - const lib_zon_path = try std.fmt.allocPrint(allocator, "{s}/{s}/{s}.zon", .{ libraries_dir, lib_name, lib_name }); - defer allocator.free(lib_zon_path); - - const lib_zon = std.fs.cwd().readFileAlloc(allocator, lib_zon_path, 4096) catch { - // No zon file, add with empty deps - const key = try allocator.dupe(u8, lib_name); - const val = try allocator.dupe(u8, ""); - try all_libs.put(key, val); - return; - }; - defer allocator.free(lib_zon); - - // Extract dependencies from zon - var deps_list = std.ArrayList(u8).init(allocator); - defer deps_list.deinit(); - - // Scan for other library names in the zon file - var lib_dir = try std.fs.cwd().openDir(libraries_dir, .{ .iterate = true }); - defer lib_dir.close(); - - var lib_iter = lib_dir.iterate(); - while (try lib_iter.next()) |entry| { - if (entry.kind != .directory) continue; - if (std.mem.eql(u8, entry.name, lib_name)) continue; // Skip self - - if (std.mem.indexOf(u8, lib_zon, entry.name) != null) { - if (deps_list.items.len > 0) { - try deps_list.append(','); - } - try deps_list.appendSlice(entry.name); - - // Recursively collect this dependency's deps - try collectLibraryDeps(allocator, libraries_dir, entry.name, all_libs); - } - } - - const key = try allocator.dupe(u8, lib_name); - const val = try allocator.toOwnedSlice(deps_list); - try all_libs.put(key, val); -} |
