Skip to content

Commit

Permalink
build: remove gir-files dependency
Browse files Browse the repository at this point in the history
Closes #30

This commit also adds some rudimentary error reporting to the GIR search
process to make it more obvious when errors occur due to missing GIRs,
which will be much more common now that the GIRs are no longer bundled
in a dependency.
  • Loading branch information
ianprime0509 committed Jan 31, 2024
1 parent 330c6b9 commit e0f848a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 18 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ development environment:

## Running the binding generator

Running the binding generator requires GIR files to process. The easiest way to
get the full set of required GIR files is to set up a Flatpak development
environment as described in the previous section. Otherwise, a custom set of
bindings can be built by running the `zig-gobject` binary directly.

To generate all available bindings using the files under `lib/gir-files`, run
`zig build codegen`. This will generate bindings to the `bindings` directory,
which can be used as a dependency (using the Zig package manager) in other
Expand Down
4 changes: 2 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ fn addCodegenStep(b: *std.Build, codegen_exe: *std.Build.Step.Compile) !*std.Bui

const codegen_cmd = b.addRunArtifact(codegen_exe);
codegen_cmd.addArgs(&.{ "--gir-dir", try b.build_root.join(b.allocator, &.{"gir-overrides"}) });
codegen_cmd.addArg("--gir-dir");
codegen_cmd.addDirectoryArg(b.dependency("gir", .{}).path("."));
const gir_files_path = b.option([]const u8, "gir-files-path", "Path to GIR files") orelse "/usr/share/gir-1.0";
codegen_cmd.addArgs(&.{ "--gir-dir", gir_files_path });
codegen_cmd.addArgs(&.{ "--bindings-dir", try b.build_root.join(b.allocator, &.{"binding-overrides"}) });
codegen_cmd.addArgs(&.{ "--extensions-dir", try b.build_root.join(b.allocator, &.{"extensions"}) });
codegen_cmd.addArgs(&.{ "--output-dir", try b.build_root.join(b.allocator, &.{"bindings"}) });
Expand Down
4 changes: 0 additions & 4 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
"build.zig.zon",
},
.dependencies = .{
.gir = .{
.url = "git+https://github.com/ianprime0509/gir-files#d0d06238bc0f1759b450cc7113f8fc3637c6533d",
.hash = "1220d03206a277aa5adac91667c7ff7236017fde65c2034bdeec3203cfca09a7152e",
},
.xml = .{
.url = "git+https://github.com/ianprime0509/zig-xml#5d995ef95bb5796f38bf16c0d4750cba06d86549",
.hash = "1220d70515390ed942a0864fe3aad2f3b485b3fcb9df07d61dbefea9873373647e33",
Expand Down
51 changes: 40 additions & 11 deletions src/gir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@ const xml = @import("xml");
const mem = std.mem;
const Allocator = mem.Allocator;

pub const FindError = error{ InvalidGir, RepositoryNotFound } || Allocator.Error || std.fs.File.OpenError || std.fs.File.ReadError || error{
FileSystem,
InputOutput,
NotSupported,
Unseekable,
pub const Diagnostics = struct {
errors: std.ArrayListUnmanaged([]u8) = .{},
allocator: Allocator,

pub fn deinit(diag: *Diagnostics) void {
for (diag.errors.items) |err| diag.allocator.free(err);
diag.errors.deinit(diag.allocator);
diag.* = undefined;
}

fn add(diag: *Diagnostics, comptime fmt: []const u8, args: anytype) Allocator.Error!void {
const formatted = try std.fmt.allocPrint(diag.allocator, fmt, args);
errdefer diag.allocator.free(formatted);
try diag.errors.append(diag.allocator, formatted);
}
};

/// Finds and parses all repositories for the given root libraries, transitively
/// including dependencies.
pub fn findRepositories(allocator: Allocator, gir_path: []const std.fs.Dir, roots: []const Include) FindError![]Repository {
pub fn findRepositories(allocator: Allocator, gir_path: []const std.fs.Dir, roots: []const Include, diag: *Diagnostics) Allocator.Error![]Repository {
var repos = std.ArrayHashMap(Include, Repository, Include.ArrayContext, true).init(allocator);
defer repos.deinit();
errdefer for (repos.values()) |*repo| repo.deinit();
Expand All @@ -22,7 +32,10 @@ pub fn findRepositories(allocator: Allocator, gir_path: []const std.fs.Dir, root
try needed_repos.appendSlice(roots);
while (needed_repos.popOrNull()) |needed_repo| {
if (!repos.contains(needed_repo)) {
const repo = try findRepository(allocator, gir_path, needed_repo);
const repo = findRepository(allocator, gir_path, needed_repo, diag) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.FindFailed => continue,
};
try repos.put(needed_repo, repo);
try needed_repos.appendSlice(repo.includes);
}
Expand All @@ -31,19 +44,35 @@ pub fn findRepositories(allocator: Allocator, gir_path: []const std.fs.Dir, root
return try allocator.dupe(Repository, repos.values());
}

fn findRepository(allocator: Allocator, gir_path: []const std.fs.Dir, include: Include) !Repository {
fn findRepository(allocator: Allocator, gir_path: []const std.fs.Dir, include: Include, diag: *Diagnostics) !Repository {
const repo_path = try std.fmt.allocPrintZ(allocator, "{s}-{s}.gir", .{ include.name, include.version });
defer allocator.free(repo_path);

for (gir_path) |dir| {
const file = dir.openFile(repo_path, .{}) catch |err| switch (err) {
error.FileNotFound => continue,
else => |other| return other,
else => {
try diag.add("failed to open GIR file: {s}: {}", .{ repo_path, err });
return error.FindFailed;
},
};
defer file.close();
var reader = std.io.bufferedReader(file.reader());
return try Repository.parse(allocator, reader.reader());
return Repository.parse(allocator, reader.reader()) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.InvalidGir => {
try diag.add("failed to parse GIR file: {s}", .{repo_path});
return error.FindFailed;
},
else => {
try diag.add("failed to read GIR file: {s}: {}", .{ repo_path, err });
return error.FindFailed;
},
};
}
return error.RepositoryNotFound;

try diag.add("failed to find GIR file: {s}", .{repo_path});
return error.FindFailed;
}

const ns = struct {
Expand Down
13 changes: 12 additions & 1 deletion src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,18 @@ pub fn main() Allocator.Error!void {
var src_out_dir = output_dir.?.makeOpenPath("src", .{}) catch |err| fatal("failed to create output src directory: {}", .{err});
defer src_out_dir.close();

const repositories = gir.findRepositories(allocator, gir_path.items, roots.items) catch |err| fatal("failed to discover GIR repositories: {}", .{err});
const repositories = repositories: {
var diag: gir.Diagnostics = .{ .allocator = allocator };
defer diag.deinit();
const repositories = try gir.findRepositories(allocator, gir_path.items, roots.items, &diag);
if (diag.errors.items.len > 0) {
for (diag.errors.items) |err| {
log.err("{s}", .{err});
}
fatal("failed to find and parse GIR repositories", .{});
}
break :repositories repositories;
};
defer allocator.free(repositories);
defer for (repositories) |*repository| repository.deinit();
translate.createBindings(allocator, repositories, bindings_path.items, extensions_path.items, src_out_dir) catch |err| fatal("failed to create bindings: {}", .{err});
Expand Down

0 comments on commit e0f848a

Please sign in to comment.