holy crap it builds

This commit is contained in:
Emil Lerch 2025-09-17 15:17:42 -07:00
parent f656760721
commit 66e8ae3495
Signed by: lobo
GPG key ID: A7B62D657EF764F8
2 changed files with 139 additions and 6 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Emil Lerch
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

124
build.zig
View file

@ -22,8 +22,57 @@ pub fn build(b: *std.Build) void {
// in this directory.
// We need to use curl for this as the domain doesn't work with zig TLS
const model_step = DownloadStep("https://www.link.cs.cmu.edu/link/ftp-site/link-grammar/link-4.1b/unix/link-4.1b.tar.gz").create(b);
const download_link_step = DownloadStep("https://www.link.cs.cmu.edu/link/ftp-site/link-grammar/link-4.1b/unix/link-4.1b.tar.gz").create(b);
const upstream = download_link_step.dependency(b, .{});
const lib = b.addLibrary(.{
.name = "link",
.linkage = .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
lib.addIncludePath(upstream.path("include"));
lib.addCSourceFiles(.{
.root = upstream.path("src"),
.files = &.{
"analyze-linkage.c",
"and.c",
"api-example.c",
"api.c",
"build-disjuncts.c",
"command-line.c",
"constituents.c",
"count.c",
"error.c",
"extract-links.c",
"fast-match.c",
"idiom.c",
"linkset.c",
"massage.c",
"parse.c",
"post-process.c",
"pp_knowledge.c",
"pp_lexer.c",
"pp_linkset.c",
"preparation.c",
"print-util.c",
"print.c",
"prune.c",
"read-dict.c",
"resources.c",
"string-set.c",
"tokenize.c",
"utilities.c",
"word-file.c",
"www-parse.c",
},
});
// This creates a module, which represents a collection of source files alongside
// some compilation options, such as optimization mode and linked system libraries.
// Zig modules are the preferred way of making Zig code available to consumers.
@ -43,6 +92,8 @@ pub fn build(b: *std.Build) void {
// which requires us to specify a target.
.target = target,
});
mod.linkLibrary(lib);
mod.addIncludePath(upstream.path("include"));
// Here we define an executable. An executable needs to have a root module
// which needs to expose a `main` function. While we could add a main function
@ -86,7 +137,7 @@ pub fn build(b: *std.Build) void {
}),
});
exe.step.dependOn(&model_step.step);
exe.step.dependOn(&download_link_step.step);
// This declares intent for the executable to be installed into the
// install prefix when running `zig build` (i.e. when executing the default
// step). By default the install prefix is `zig-out/` but can be overridden
@ -125,7 +176,7 @@ pub fn build(b: *std.Build) void {
const mod_tests = b.addTest(.{
.root_module = mod,
});
exe.step.dependOn(&model_step.step);
mod_tests.step.dependOn(&download_link_step.step);
// A run step that will run the test executable.
const run_mod_tests = b.addRunArtifact(mod_tests);
@ -174,6 +225,23 @@ fn DownloadStep(comptime link: []const u8) type {
const Self = @This();
const Dependency = struct {
build_root: []const u8,
build: *std.Build,
download: *Self,
pub fn path(self: Dependency, sub_path: []const u8) std.Build.LazyPath {
const cache_path = (self.download.getOutputPath() catch @panic("OOM")).path;
const full_path = std.fs.path.join(self.build.allocator, &.{ cache_path, sub_path }) catch @panic("OOM");
return .{
.src_path = .{
.owner = self.build,
.sub_path = full_path,
},
};
}
};
fn fileName(uri: std.Uri) []const u8 {
const path = switch (uri.path) {
.raw => |r| r,
@ -205,7 +273,7 @@ fn DownloadStep(comptime link: []const u8) type {
return self;
}
pub fn getOutputPath(self: *Self) std.Build.LazyPath {
pub fn getOutputPath(self: *Self) !struct { path: []const u8, hash: u64 } {
var hasher = std.hash.Wyhash.init(0);
hasher.update(download_link);
const cache_hash = hasher.final();
@ -213,7 +281,10 @@ fn DownloadStep(comptime link: []const u8) type {
var cache_dir_buf: [std.fs.max_path_bytes]u8 = undefined;
const cache_dir = std.fmt.bufPrint(&cache_dir_buf, "{s}/o/{x}/{s}", .{ self.builder.cache_root.path.?, cache_hash, fileNameNoExtension() }) catch @panic("path too long");
return .{ .cwd_relative = self.builder.allocator.dupe(u8, cache_dir) catch @panic("OOM") };
return .{
.path = try self.builder.allocator.dupe(u8, cache_dir),
.hash = cache_hash,
};
}
fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) anyerror!void {
@ -277,9 +348,50 @@ fn DownloadStep(comptime link: []const u8) type {
step.result_cached = false;
},
.targz => {
@compileError("tar.gz extraction not yet implemented");
var archive_file = std.fs.cwd().openFile(archive, .{}) catch return error.ExtractFailed;
defer archive_file.close();
var buf: [4096]u8 = undefined;
var file_reader = archive_file.reader(&buf);
const reader = &file_reader.interface;
var cache_dir_handle = std.fs.cwd().openDir(cache_dir, .{}) catch return error.ExtractFailed;
defer cache_dir_handle.close();
var gz_buf: [std.compress.flate.max_window_len]u8 = undefined;
var decompress = std.compress.flate.Decompress.init(reader, .gzip, &gz_buf);
std.tar.pipeToFileSystem(
cache_dir_handle,
&decompress.reader,
.{ .mode_mode = .ignore },
) catch return error.ExtractFailed;
},
}
}
pub fn dependency(
self: *Self,
b: *std.Build,
args: anytype,
) *Dependency {
_ = args;
const output = self.getOutputPath() catch @panic("cannot get output path");
const dep = b.allocator.create(Dependency) catch @panic("OOM");
dep.* = .{
.download = self,
.build = b,
.build_root = output.path,
};
return dep;
}
const UserValue = union(enum) {
flag: void,
scalar: []const u8,
list: std.array_list.Managed([]const u8),
map: std.StringHashMap(*const UserValue),
lazy_path: std.Build.LazyPath,
lazy_path_list: std.array_list.Managed(std.Build.LazyPath),
};
};
}