-
-
Notifications
You must be signed in to change notification settings - Fork 314
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Experiment with making ZLS a build step
- Loading branch information
1 parent
b328500
commit 4f0e4be
Showing
6 changed files
with
269 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
//! Build step to extract build info | ||
|
||
const ExtractBuildInfo = @This(); | ||
const std = @import("std"); | ||
const Build = std.Build; | ||
const Step = Build.Step; | ||
const fs = std.fs; | ||
const mem = std.mem; | ||
const BuildConfig = @import("BuildConfig.zig"); | ||
const Packages = @import("Packages.zig"); | ||
|
||
const build_runner = @import("root"); | ||
const dependencies = build_runner.dependencies; | ||
|
||
pub const Mode = enum { | ||
/// Entire build graph; hacky and you shouldn't use it if you can avoid it | ||
/// TODO implement this | ||
all, | ||
/// Steps this step depends on | ||
dependencies, | ||
}; | ||
|
||
step: Step, | ||
mode: Mode, | ||
|
||
pub const base_id = .custom; | ||
|
||
pub const Options = struct { | ||
mode: Mode = .dependencies, | ||
}; | ||
|
||
pub fn create( | ||
owner: *Build, | ||
options: Options, | ||
) *ExtractBuildInfo { | ||
const self = owner.allocator.create(ExtractBuildInfo) catch @panic("OOM"); | ||
self.* = .{ | ||
.step = Step.init(.{ | ||
.id = base_id, | ||
.name = "ExtractBuildInfo", | ||
.owner = owner, | ||
.makeFn = make, | ||
}), | ||
.mode = options.mode, | ||
}; | ||
return self; | ||
} | ||
|
||
fn processStep( | ||
builder: *std.Build, | ||
packages: *Packages, | ||
include_dirs: *std.StringArrayHashMapUnmanaged(void), | ||
step: *Build.Step, | ||
) anyerror!void { | ||
for (step.dependencies.items) |dependant_step| { | ||
try processStep(builder, packages, include_dirs, dependant_step); | ||
} | ||
|
||
const exe = blk: { | ||
if (step.cast(Build.Step.InstallArtifact)) |install_exe| break :blk install_exe.artifact; | ||
if (step.cast(Build.Step.Compile)) |exe| break :blk exe; | ||
return; | ||
}; | ||
|
||
if (exe.root_src) |src| { | ||
_ = try packages.addPackage("root", src.getPath(builder)); | ||
} | ||
try processIncludeDirs(builder, include_dirs, exe.include_dirs.items); | ||
// TODO // try processPkgConfig(builder.allocator, include_dirs, exe); | ||
try processModules(builder, packages, exe.modules); | ||
} | ||
|
||
fn processIncludeDirs( | ||
builder: *Build, | ||
include_dirs: *std.StringArrayHashMapUnmanaged(void), | ||
dirs: []Build.Step.Compile.IncludeDir, | ||
) !void { | ||
for (dirs) |dir| { | ||
switch (dir) { | ||
.path, .path_system, .path_after => |path| { | ||
try include_dirs.put(builder.allocator, path.getPath(builder), {}); | ||
}, | ||
.other_step => |other_step| { | ||
if (other_step.generated_h) |header| { | ||
if (header.path) |path| { | ||
try include_dirs.put(builder.allocator, std.fs.path.dirname(path).?, {}); | ||
} | ||
} | ||
if (other_step.installed_headers.items.len > 0) { | ||
const path = builder.pathJoin(&.{ | ||
other_step.step.owner.install_prefix, "include", | ||
}); | ||
try include_dirs.put(builder.allocator, path, {}); | ||
} | ||
}, | ||
.config_header_step => |config_header| { | ||
const full_file_path = config_header.output_file.path orelse continue; | ||
const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len]; | ||
try include_dirs.put(builder.allocator, header_dir_path, {}); | ||
}, | ||
.framework_path, .framework_path_system => {}, | ||
} | ||
} | ||
} | ||
|
||
fn processModules( | ||
builder: *Build, | ||
packages: *Packages, | ||
modules: std.StringArrayHashMap(*Build.Module), | ||
) !void { | ||
for (modules.keys(), modules.values()) |name, mod| { | ||
const already_added = try packages.addPackage(name, mod.source_file.getPath(mod.builder)); | ||
// if the package has already been added short circuit here or recursive modules will ruin us | ||
if (already_added) continue; | ||
|
||
try processModules(builder, packages, mod.dependencies); | ||
} | ||
} | ||
|
||
fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ||
_ = prog_node; | ||
const b = step.owner; | ||
const self = @fieldParentPtr(ExtractBuildInfo, "step", step); | ||
|
||
var packages = Packages{ .allocator = b.allocator }; | ||
var include_dirs: std.StringArrayHashMapUnmanaged(void) = .{}; | ||
|
||
var deps_build_roots: std.ArrayListUnmanaged(BuildConfig.DepsBuildRoots) = .{}; | ||
for (dependencies.root_deps) |root_dep| { | ||
inline for (@typeInfo(dependencies.packages).Struct.decls) |package| { | ||
if (std.mem.eql(u8, package.name, root_dep[1])) { | ||
const package_info = @field(dependencies.packages, package.name); | ||
if (!@hasDecl(package_info, "build_root")) continue; | ||
try deps_build_roots.append(b.allocator, .{ | ||
.name = root_dep[0], | ||
// XXX Check if it exists? | ||
.path = try std.fs.path.resolve(b.allocator, &[_][]const u8{ package_info.build_root, "./build.zig" }), | ||
}); | ||
} | ||
} | ||
} | ||
|
||
switch (self.mode) { | ||
.all => @panic("TODO :/"), | ||
.dependencies => try processStep(step.owner, &packages, &include_dirs, step), | ||
} | ||
|
||
var out = try std.fs.createFileAbsolute(try b.cache_root.join(b.allocator, &.{"zls-build-info.json"}), .{}); | ||
defer out.close(); | ||
|
||
var bufw = std.io.bufferedWriter(out.writer()); | ||
|
||
try std.json.stringify( | ||
BuildConfig{ | ||
.deps_build_roots = try deps_build_roots.toOwnedSlice(b.allocator), | ||
.packages = try packages.toPackageList(), | ||
.include_dirs = include_dirs.keys(), | ||
}, | ||
.{ | ||
.whitespace = .indent_1, | ||
}, | ||
bufw.writer(), | ||
); | ||
try bufw.flush(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
const std = @import("std"); | ||
const BuildConfig = @import("BuildConfig.zig"); | ||
|
||
const Packages = @This(); | ||
|
||
allocator: std.mem.Allocator, | ||
|
||
/// Outer key is the package name, inner key is the file path. | ||
packages: std.StringArrayHashMapUnmanaged(std.StringArrayHashMapUnmanaged(void)) = .{}, | ||
|
||
/// Returns true if the package was already present. | ||
pub fn addPackage(self: *Packages, name: []const u8, path: []const u8) !bool { | ||
const name_gop_result = try self.packages.getOrPut(self.allocator, name); | ||
if (!name_gop_result.found_existing) { | ||
name_gop_result.value_ptr.* = .{}; | ||
} | ||
|
||
const path_gop_result = try name_gop_result.value_ptr.getOrPut(self.allocator, path); | ||
return path_gop_result.found_existing; | ||
} | ||
|
||
pub fn toPackageList(self: *Packages) ![]BuildConfig.Pkg { | ||
var result: std.ArrayListUnmanaged(BuildConfig.Pkg) = .{}; | ||
errdefer result.deinit(self.allocator); | ||
|
||
var name_iter = self.packages.iterator(); | ||
while (name_iter.next()) |path_hashmap| { | ||
var path_iter = path_hashmap.value_ptr.iterator(); | ||
while (path_iter.next()) |path| { | ||
try result.append(self.allocator, .{ .name = path_hashmap.key_ptr.*, .path = path.key_ptr.* }); | ||
} | ||
} | ||
|
||
return try result.toOwnedSlice(self.allocator); | ||
} | ||
|
||
pub fn deinit(self: *Packages) void { | ||
var outer_iter = self.packages.iterator(); | ||
while (outer_iter.next()) |inner| { | ||
inner.value_ptr.deinit(self.allocator); | ||
} | ||
self.packages.deinit(self.allocator); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters