From a3af1c76a3dd75944b4933c717805ebdaa089c32 Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Mon, 26 Sep 2022 21:38:10 +0100 Subject: [PATCH 1/3] support pkgconfig --- src/special/build_runner.zig | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/special/build_runner.zig b/src/special/build_runner.zig index 98ce81f..1389746 100644 --- a/src/special/build_runner.zig +++ b/src/special/build_runner.zig @@ -98,11 +98,13 @@ fn processStep( ) anyerror!void { if (step.cast(InstallArtifactStep)) |install_exe| { try processIncludeDirs(allocator, include_dirs, install_exe.artifact.include_dirs.items); + try processPkgConfig(allocator, include_dirs, install_exe.artifact); for (install_exe.artifact.packages.items) |pkg| { try processPackage(allocator, packages, pkg); } } else if (step.cast(LibExeObjStep)) |exe| { try processIncludeDirs(allocator, include_dirs, exe.include_dirs.items); + try processPkgConfig(allocator, include_dirs, exe); for (exe.packages.items) |pkg| { try processPackage(allocator, packages, pkg); } @@ -161,6 +163,49 @@ fn processIncludeDirs( } } +fn processPkgConfig( + allocator: std.mem.Allocator, + include_dirs: *std.ArrayListUnmanaged(BuildConfig.IncludeDir), + exe: *std.build.LibExeObjStep, +) !void { + for (exe.link_objects.items) |link_object| { + switch (link_object) { + .system_lib => |system_lib| { + switch (system_lib.use_pkg_config) { + .no => {}, + .yes, .force => { + if (exe.runPkgConfig(system_lib.name)) |args| { + for (args) |arg| { + if (std.mem.startsWith(u8, arg, "-I")) { + try include_dirs.append(allocator, .{ .path = arg[2..], .system = true }); + } + } + } else |err| switch (err) { + error.PkgConfigInvalidOutput, + error.PkgConfigCrashed, + error.PkgConfigFailed, + error.PkgConfigNotInstalled, + error.PackageNotFound, + => switch (system_lib.use_pkg_config) { + .yes => { + // pkg-config failed, so zig will not add any include paths + }, + .force => { + log.warn("pkg-config failed for library {s}", .{system_lib.name}); + }, + .no => unreachable, + }, + + else => |e| return e, + } + }, + } + }, + else => {}, + } + } +} + fn runBuild(builder: *Builder) anyerror!void { switch (@typeInfo(@typeInfo(@TypeOf(root.build)).Fn.return_type.?)) { .Void => root.build(builder), From 137edcd527e66104a311b2c7243aeb5491e95d03 Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Mon, 26 Sep 2022 22:01:00 +0100 Subject: [PATCH 2/3] use `StringArrayHashMap` to remove duplicate include paths --- src/DocumentStore.zig | 27 +++++++-------------------- src/special/build_runner.zig | 35 +++++++++++++++-------------------- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/src/DocumentStore.zig b/src/DocumentStore.zig index 6d685ee..6dce261 100644 --- a/src/DocumentStore.zig +++ b/src/DocumentStore.zig @@ -32,7 +32,7 @@ const BuildFile = struct { pub const BuildFileConfig = struct { packages: []Pkg, - include_dirs: []IncludeDir, + include_dirs: []const []const u8, pub fn deinit(self: BuildFileConfig, allocator: std.mem.Allocator) void { for (self.packages) |pkg| { @@ -42,7 +42,7 @@ pub const BuildFileConfig = struct { allocator.free(self.packages); for (self.include_dirs) |dir| { - allocator.free(dir.path); + allocator.free(dir); } allocator.free(self.include_dirs); } @@ -51,8 +51,6 @@ pub const BuildFileConfig = struct { name: []const u8, uri: []const u8, }; - - pub const IncludeDir = BuildConfig.IncludeDir; }; pub const Handle = struct { @@ -223,10 +221,10 @@ fn loadBuildConfiguration(context: LoadBuildConfigContext) !void { packages.deinit(allocator); } - var include_dirs = try std.ArrayListUnmanaged(BuildFileConfig.IncludeDir).initCapacity(allocator, config.include_dirs.len); + var include_dirs = try std.ArrayListUnmanaged([]const u8).initCapacity(allocator, config.include_dirs.len); errdefer { for (include_dirs.items) |dir| { - allocator.free(dir.path); + allocator.free(dir); } include_dirs.deinit(allocator); } @@ -245,10 +243,10 @@ fn loadBuildConfiguration(context: LoadBuildConfigContext) !void { } for (config.include_dirs) |dir| { - const path = try allocator.dupe(u8, dir.path); + const path = try allocator.dupe(u8, dir); errdefer allocator.free(path); - include_dirs.appendAssumeCapacity(.{ .path = path, .system = dir.system }); + include_dirs.appendAssumeCapacity(path); } build_file.config = .{ @@ -655,18 +653,7 @@ fn collectCIncludes(self: *DocumentStore, handle: *Handle) ![]CImportHandle { } fn translate(self: *DocumentStore, handle: *Handle, source: []const u8) error{OutOfMemory}!?translate_c.Result { - const dirs: []BuildConfig.IncludeDir = if (handle.associated_build_file) |build_file| build_file.config.include_dirs else &.{}; - const include_dirs = blk: { - var result = try self.allocator.alloc([]const u8, dirs.len); - errdefer self.allocator.free(result); - - for (dirs) |dir, i| { - result[i] = dir.path; - } - - break :blk result; - }; - defer self.allocator.free(include_dirs); + const include_dirs: []const []const u8 = if (handle.associated_build_file) |build_file| build_file.config.include_dirs else &.{}; const maybe_result = try translate_c.translate( self.allocator, diff --git a/src/special/build_runner.zig b/src/special/build_runner.zig index 1389746..baa69ee 100644 --- a/src/special/build_runner.zig +++ b/src/special/build_runner.zig @@ -8,17 +8,12 @@ const LibExeObjStep = std.build.LibExeObjStep; pub const BuildConfig = struct { packages: []Pkg, - include_dirs: []IncludeDir, + include_dirs: []const []const u8, pub const Pkg = struct { name: []const u8, path: []const u8, }; - - pub const IncludeDir = struct { - path: []const u8, - system: bool, - }; }; ///! This is a modified build runner to extract information out of build.zig @@ -68,7 +63,7 @@ pub fn main() !void { var packages = std.ArrayListUnmanaged(BuildConfig.Pkg){}; defer packages.deinit(allocator); - var include_dirs = std.ArrayListUnmanaged(BuildConfig.IncludeDir){}; + var include_dirs: std.StringArrayHashMapUnmanaged(void) = .{}; defer include_dirs.deinit(allocator); // TODO: We currently add packages from every LibExeObj step that the install step depends on. @@ -83,7 +78,7 @@ pub fn main() !void { try std.json.stringify( BuildConfig{ .packages = packages.items, - .include_dirs = include_dirs.items, + .include_dirs = include_dirs.keys(), }, .{ .whitespace = .{} }, std.io.getStdOut().writer(), @@ -93,7 +88,7 @@ pub fn main() !void { fn processStep( allocator: std.mem.Allocator, packages: *std.ArrayListUnmanaged(BuildConfig.Pkg), - include_dirs: *std.ArrayListUnmanaged(BuildConfig.IncludeDir), + include_dirs: *std.StringArrayHashMapUnmanaged(void), step: *std.build.Step, ) anyerror!void { if (step.cast(InstallArtifactStep)) |install_exe| { @@ -143,29 +138,27 @@ fn processPackage( fn processIncludeDirs( allocator: std.mem.Allocator, - include_dirs: *std.ArrayListUnmanaged(BuildConfig.IncludeDir), + include_dirs: *std.StringArrayHashMapUnmanaged(void), dirs: []std.build.LibExeObjStep.IncludeDir, ) !void { try include_dirs.ensureUnusedCapacity(allocator, dirs.len); - outer: for (dirs) |dir| { - const candidate: BuildConfig.IncludeDir = switch (dir) { - .raw_path => |path| .{ .path = path, .system = false }, - .raw_path_system => |path| .{ .path = path, .system = true }, + for (dirs) |dir| { + const candidate: []const u8 = switch (dir) { + .raw_path => |path| path, + .raw_path_system => |path| path, else => continue, }; - for (include_dirs.items) |include_dir| { - if (std.mem.eql(u8, candidate.path, include_dir.path)) continue :outer; - } + if (include_dirs.contains(candidate)) continue; - include_dirs.appendAssumeCapacity(candidate); + include_dirs.putAssumeCapacityNoClobber(candidate, {}); } } fn processPkgConfig( allocator: std.mem.Allocator, - include_dirs: *std.ArrayListUnmanaged(BuildConfig.IncludeDir), + include_dirs: *std.StringArrayHashMapUnmanaged(void), exe: *std.build.LibExeObjStep, ) !void { for (exe.link_objects.items) |link_object| { @@ -177,7 +170,9 @@ fn processPkgConfig( if (exe.runPkgConfig(system_lib.name)) |args| { for (args) |arg| { if (std.mem.startsWith(u8, arg, "-I")) { - try include_dirs.append(allocator, .{ .path = arg[2..], .system = true }); + const candidate = arg[2..]; + if (include_dirs.contains(candidate)) continue; + try include_dirs.putNoClobber(allocator, candidate, {}); } } } else |err| switch (err) { From 58d8c1434d578d652dd31774c11d6bd15f4a7a82 Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Tue, 27 Sep 2022 19:49:59 +0100 Subject: [PATCH 3/3] cleanup `processPkgConfig` --- src/special/build_runner.zig | 74 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/special/build_runner.zig b/src/special/build_runner.zig index baa69ee..fe17799 100644 --- a/src/special/build_runner.zig +++ b/src/special/build_runner.zig @@ -150,9 +150,7 @@ fn processIncludeDirs( else => continue, }; - if (include_dirs.contains(candidate)) continue; - - include_dirs.putAssumeCapacityNoClobber(candidate, {}); + include_dirs.putAssumeCapacity(candidate, {}); } } @@ -162,45 +160,47 @@ fn processPkgConfig( exe: *std.build.LibExeObjStep, ) !void { for (exe.link_objects.items) |link_object| { - switch (link_object) { - .system_lib => |system_lib| { - switch (system_lib.use_pkg_config) { - .no => {}, - .yes, .force => { - if (exe.runPkgConfig(system_lib.name)) |args| { - for (args) |arg| { - if (std.mem.startsWith(u8, arg, "-I")) { - const candidate = arg[2..]; - if (include_dirs.contains(candidate)) continue; - try include_dirs.putNoClobber(allocator, candidate, {}); - } - } - } else |err| switch (err) { - error.PkgConfigInvalidOutput, - error.PkgConfigCrashed, - error.PkgConfigFailed, - error.PkgConfigNotInstalled, - error.PackageNotFound, - => switch (system_lib.use_pkg_config) { - .yes => { - // pkg-config failed, so zig will not add any include paths - }, - .force => { - log.warn("pkg-config failed for library {s}", .{system_lib.name}); - }, - .no => unreachable, - }, + if (link_object != .system_lib) continue; + const system_lib = link_object.system_lib; - else => |e| return e, - } - }, - } + if (system_lib.use_pkg_config == .no) continue; + + getPkgConfigIncludes(allocator, include_dirs, exe, system_lib.name) catch |err| switch (err) { + error.PkgConfigInvalidOutput, + error.PkgConfigCrashed, + error.PkgConfigFailed, + error.PkgConfigNotInstalled, + error.PackageNotFound, + => switch (system_lib.use_pkg_config) { + .yes => { + // pkg-config failed, so zig will not add any include paths + }, + .force => { + log.warn("pkg-config failed for library {s}", .{system_lib.name}); + }, + .no => unreachable, }, - else => {}, - } + else => |e| return e, + }; } } +fn getPkgConfigIncludes( + allocator: std.mem.Allocator, + include_dirs: *std.StringArrayHashMapUnmanaged(void), + exe: *std.build.LibExeObjStep, + name: []const u8, +) !void { + if (exe.runPkgConfig(name)) |args| { + for (args) |arg| { + if (std.mem.startsWith(u8, arg, "-I")) { + const candidate = arg[2..]; + try include_dirs.put(allocator, candidate, {}); + } + } + } else |err| return err; +} + fn runBuild(builder: *Builder) anyerror!void { switch (@typeInfo(@typeInfo(@TypeOf(root.build)).Fn.return_type.?)) { .Void => root.build(builder),