Merge pull request #675 from leecannon/pkgconfig

support pkgconfig
This commit is contained in:
Lee Cannon 2022-09-27 20:12:33 +01:00 committed by GitHub
commit ecf4e112a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 66 additions and 39 deletions

View File

@ -32,7 +32,7 @@ const BuildFile = struct {
pub const BuildFileConfig = struct { pub const BuildFileConfig = struct {
packages: []Pkg, packages: []Pkg,
include_dirs: []IncludeDir, include_dirs: []const []const u8,
pub fn deinit(self: BuildFileConfig, allocator: std.mem.Allocator) void { pub fn deinit(self: BuildFileConfig, allocator: std.mem.Allocator) void {
for (self.packages) |pkg| { for (self.packages) |pkg| {
@ -42,7 +42,7 @@ pub const BuildFileConfig = struct {
allocator.free(self.packages); allocator.free(self.packages);
for (self.include_dirs) |dir| { for (self.include_dirs) |dir| {
allocator.free(dir.path); allocator.free(dir);
} }
allocator.free(self.include_dirs); allocator.free(self.include_dirs);
} }
@ -51,8 +51,6 @@ pub const BuildFileConfig = struct {
name: []const u8, name: []const u8,
uri: []const u8, uri: []const u8,
}; };
pub const IncludeDir = BuildConfig.IncludeDir;
}; };
pub const Handle = struct { pub const Handle = struct {
@ -223,10 +221,10 @@ fn loadBuildConfiguration(context: LoadBuildConfigContext) !void {
packages.deinit(allocator); 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 { errdefer {
for (include_dirs.items) |dir| { for (include_dirs.items) |dir| {
allocator.free(dir.path); allocator.free(dir);
} }
include_dirs.deinit(allocator); include_dirs.deinit(allocator);
} }
@ -245,10 +243,10 @@ fn loadBuildConfiguration(context: LoadBuildConfigContext) !void {
} }
for (config.include_dirs) |dir| { for (config.include_dirs) |dir| {
const path = try allocator.dupe(u8, dir.path); const path = try allocator.dupe(u8, dir);
errdefer allocator.free(path); errdefer allocator.free(path);
include_dirs.appendAssumeCapacity(.{ .path = path, .system = dir.system }); include_dirs.appendAssumeCapacity(path);
} }
build_file.config = .{ 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 { 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: []const []const u8 = 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 maybe_result = try translate_c.translate( const maybe_result = try translate_c.translate(
self.allocator, self.allocator,

View File

@ -8,17 +8,12 @@ const LibExeObjStep = std.build.LibExeObjStep;
pub const BuildConfig = struct { pub const BuildConfig = struct {
packages: []Pkg, packages: []Pkg,
include_dirs: []IncludeDir, include_dirs: []const []const u8,
pub const Pkg = struct { pub const Pkg = struct {
name: []const u8, name: []const u8,
path: []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 ///! 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){}; var packages = std.ArrayListUnmanaged(BuildConfig.Pkg){};
defer packages.deinit(allocator); defer packages.deinit(allocator);
var include_dirs = std.ArrayListUnmanaged(BuildConfig.IncludeDir){}; var include_dirs: std.StringArrayHashMapUnmanaged(void) = .{};
defer include_dirs.deinit(allocator); defer include_dirs.deinit(allocator);
// TODO: We currently add packages from every LibExeObj step that the install step depends on. // 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( try std.json.stringify(
BuildConfig{ BuildConfig{
.packages = packages.items, .packages = packages.items,
.include_dirs = include_dirs.items, .include_dirs = include_dirs.keys(),
}, },
.{ .whitespace = .{} }, .{ .whitespace = .{} },
std.io.getStdOut().writer(), std.io.getStdOut().writer(),
@ -93,16 +88,18 @@ pub fn main() !void {
fn processStep( fn processStep(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
packages: *std.ArrayListUnmanaged(BuildConfig.Pkg), packages: *std.ArrayListUnmanaged(BuildConfig.Pkg),
include_dirs: *std.ArrayListUnmanaged(BuildConfig.IncludeDir), include_dirs: *std.StringArrayHashMapUnmanaged(void),
step: *std.build.Step, step: *std.build.Step,
) anyerror!void { ) anyerror!void {
if (step.cast(InstallArtifactStep)) |install_exe| { if (step.cast(InstallArtifactStep)) |install_exe| {
try processIncludeDirs(allocator, include_dirs, install_exe.artifact.include_dirs.items); 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| { for (install_exe.artifact.packages.items) |pkg| {
try processPackage(allocator, packages, pkg); try processPackage(allocator, packages, pkg);
} }
} else if (step.cast(LibExeObjStep)) |exe| { } else if (step.cast(LibExeObjStep)) |exe| {
try processIncludeDirs(allocator, include_dirs, exe.include_dirs.items); try processIncludeDirs(allocator, include_dirs, exe.include_dirs.items);
try processPkgConfig(allocator, include_dirs, exe);
for (exe.packages.items) |pkg| { for (exe.packages.items) |pkg| {
try processPackage(allocator, packages, pkg); try processPackage(allocator, packages, pkg);
} }
@ -141,26 +138,69 @@ fn processPackage(
fn processIncludeDirs( fn processIncludeDirs(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
include_dirs: *std.ArrayListUnmanaged(BuildConfig.IncludeDir), include_dirs: *std.StringArrayHashMapUnmanaged(void),
dirs: []std.build.LibExeObjStep.IncludeDir, dirs: []std.build.LibExeObjStep.IncludeDir,
) !void { ) !void {
try include_dirs.ensureUnusedCapacity(allocator, dirs.len); try include_dirs.ensureUnusedCapacity(allocator, dirs.len);
outer: for (dirs) |dir| { for (dirs) |dir| {
const candidate: BuildConfig.IncludeDir = switch (dir) { const candidate: []const u8 = switch (dir) {
.raw_path => |path| .{ .path = path, .system = false }, .raw_path => |path| path,
.raw_path_system => |path| .{ .path = path, .system = true }, .raw_path_system => |path| path,
else => continue, else => continue,
}; };
for (include_dirs.items) |include_dir| { include_dirs.putAssumeCapacity(candidate, {});
if (std.mem.eql(u8, candidate.path, include_dir.path)) continue :outer;
} }
}
include_dirs.appendAssumeCapacity(candidate); fn processPkgConfig(
allocator: std.mem.Allocator,
include_dirs: *std.StringArrayHashMapUnmanaged(void),
exe: *std.build.LibExeObjStep,
) !void {
for (exe.link_objects.items) |link_object| {
if (link_object != .system_lib) continue;
const system_lib = link_object.system_lib;
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 => |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 { fn runBuild(builder: *Builder) anyerror!void {
switch (@typeInfo(@typeInfo(@TypeOf(root.build)).Fn.return_type.?)) { switch (@typeInfo(@typeInfo(@TypeOf(root.build)).Fn.return_type.?)) {
.Void => root.build(builder), .Void => root.build(builder),