aboutsummaryrefslogtreecommitdiff
path: root/toolchain/akibacompile/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain/akibacompile/main.zig')
-rw-r--r--toolchain/akibacompile/main.zig224
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);
-}