From 5556e46cc453c024defa833b964648465ddc9e39 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Sat, 2 May 2026 16:41:33 +0200 Subject: build(zig): link statically typst --- build.zig | 50 +++++++++++++++++++-------------------- build.zig.zon | 32 +++---------------------- go/build.zig | 14 +++++------ go/typdown.go | 25 ++++++++++++++++++-- go/typdown_test.go | 9 +++++-- lib/typst/include/typdown_typst.h | 4 ++++ lib/typst/typdown_typst.h | 4 ---- 7 files changed, 68 insertions(+), 70 deletions(-) create mode 100644 lib/typst/include/typdown_typst.h delete mode 100644 lib/typst/typdown_typst.h diff --git a/build.zig b/build.zig index 5669a1d..a934bbc 100644 --- a/build.zig +++ b/build.zig @@ -1,9 +1,5 @@ const std = @import("std"); -const TYPST = "lib/typst"; -const TYPST_DEBUG = TYPST ++ "/target/debug"; -const TYPST_RELEASE = TYPST ++ "/target/release"; - pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); @@ -15,23 +11,30 @@ pub fn build(b: *std.Build) void { const install = b.getInstallStep(); + const typst_dep = b.dependency("typst", .{}); + // build typst module const build_typst = b.addSystemCommand(&[_][]const u8{ "cargo", "build", }); - build_typst.setCwd(b.path(TYPST)); + build_typst.setCwd(typst_dep.path("")); if (no_embed_fonts) build_typst.addArg("--no-default-features"); + var folder: []const u8 = "debug"; switch (optimize) { .ReleaseSmall => { build_typst.addArg("--profile"); build_typst.addArg("small"); + folder = "small"; + }, + .ReleaseFast, .ReleaseSafe => { + build_typst.addArg("--release"); + folder = "release"; }, - .ReleaseFast, .ReleaseSafe => build_typst.addArg("--release"), else => {}, } const typst = b.addTranslateC(.{ - .root_source_file = b.path(TYPST ++ "/typdown_typst.h"), + .root_source_file = typst_dep.path("include/typdown_typst.h"), .link_libc = true, .target = target, .optimize = optimize, @@ -41,20 +44,18 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, - .imports = &.{ - .{ .name = "typst", .module = typst.createModule() }, - }, + .link_libc = !target.result.isWasiLibC(), + .strip = optimize != .Debug, }); - if (!target.result.isWasiLibC()) mod.link_libc = true; - if (optimize != .Debug) mod.strip = true; mod.addOptions("config", options); // find typst module - mod.linkSystemLibrary("typdown_typst", .{ .preferred_link_mode = .static }); - mod.addLibraryPath(if (optimize == .Debug) b.path(TYPST_DEBUG) else b.path(TYPST_RELEASE)); + //mod.linkSystemLibrary("typdown_typst", .{ .preferred_link_mode = .static }); + mod.addObjectFile(typst_dep.path("target").path(b, folder).path(b, "libtypdown_typst.so")); + mod.addImport("typst", typst.createModule()); const lib = b.addLibrary(.{ .name = "typdown", - .linkage = .static, + .linkage = .dynamic, .root_module = mod, .use_llvm = true, // zig internal backend crashes during linking (for 0.15.2) }); @@ -64,6 +65,8 @@ pub fn build(b: *std.Build) void { // when emitting headers will be fixed //installed_lib.emitted_h = lib.getEmittedH(); + install.dependOn(&installed_lib.step); + const example_mod = b.createModule(.{ .target = target, .optimize = optimize, @@ -74,16 +77,6 @@ pub fn build(b: *std.Build) void { }); example_mod.linkLibrary(lib); example_mod.addIncludePath(b.path("include")); - example_mod.linkSystemLibrary("typdown_typst", .{ .preferred_link_mode = .static }); - example_mod.addLibraryPath(if (optimize == .Debug) b.path(TYPST_DEBUG) else b.path(TYPST_RELEASE)); - - const example = b.addExecutable(.{ - .name = "example", - .root_module = example_mod, - }); - example.step.dependOn(install); - - install.dependOn(&installed_lib.step); const fmt = b.addFmt(.{ .paths = &.{ @@ -106,6 +99,13 @@ pub fn build(b: *std.Build) void { test_step.dependOn(&run_mod_tests.step); const examples_step = b.step("examples", "Run examples"); + + const example = b.addExecutable(.{ + .name = "example", + .root_module = example_mod, + }); + example.step.dependOn(install); + const example_run = b.addRunArtifact(example); examples_step.dependOn(&example_run.step); diff --git a/build.zig.zon b/build.zig.zon index 18cf50d..4d33f06 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -4,35 +4,9 @@ .fingerprint = 0x6d0fd8a73f35fe5b, // Changing this has security and trust implications. .minimum_zig_version = "0.15.2", .dependencies = .{ - // See `zig fetch --save ` for a command-line interface for adding dependencies. - //.example = .{ - // // When updating this field to a new URL, be sure to delete the corresponding - // // `hash`, otherwise you are communicating that you expect to find the old hash at - // // the new URL. If the contents of a URL change this will result in a hash mismatch - // // which will prevent zig from using it. - // .url = "https://example.com/foo.tar.gz", - // - // // This is computed from the file contents of the directory of files that is - // // obtained after fetching `url` and applying the inclusion rules given by - // // `paths`. - // // - // // This field is the source of truth; packages do not come from a `url`; they - // // come from a `hash`. `url` is just one of many possible mirrors for how to - // // obtain a package matching this `hash`. - // // - // // Uses the [multihash](https://multiformats.io/multihash/) format. - // .hash = "...", - // - // // When this is provided, the package is found in a directory relative to the - // // build root. In this case the package's hash is irrelevant and therefore not - // // computed. This field and `url` are mutually exclusive. - // .path = "foo", - // - // // When this is set to `true`, a package is declared to be lazily - // // fetched. This makes the dependency only get fetched if it is - // // actually used. - // .lazy = false, - //}, + .typst = .{ + .path = "lib/typst", + }, }, .paths = .{ "build.zig", diff --git a/go/build.zig b/go/build.zig index 6517786..6399042 100644 --- a/go/build.zig +++ b/go/build.zig @@ -4,6 +4,8 @@ pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const install_step = b.getInstallStep(); + const typdown = b.dependency("typdown", .{ .optimize = optimize, .target = target, @@ -11,15 +13,10 @@ pub fn build(b: *std.Build) !void { const lib = b.addLibrary(.{ .name = "typdown", .root_module = typdown, - .linkage = .static, }); //lib.bundle_compiler_rt = true; //lib.pie = true; - const install = b.addInstallArtifact(lib, .{}); - // when emitting headers will be fixed - // currently, we have to use a symlink/copy to get it - //installed.emitted_h = lib.getEmittedH(); - b.getInstallStep().dependOn(&install.step); + const install_lib = b.addInstallArtifact(lib, .{}); var flags = try std.ArrayList(u8).initCapacity(b.allocator, 2); try flags.appendSlice(b.allocator, "-linkmode external -extldflags -static"); @@ -29,7 +26,8 @@ pub fn build(b: *std.Build) !void { "-ldflags", flags.items, ".", }); - b.getInstallStep().dependOn(&go_build.step); + go_build.step.dependOn(&install_lib.step); + install_step.dependOn(&go_build.step); const test_step = b.step("test", "Run tests"); test_step.dependOn(b.getInstallStep()); @@ -42,5 +40,5 @@ pub fn build(b: *std.Build) !void { if (race) go_test.addArg("-race"); go_test.addArg("./..."); - test_step.dependOn(&go_test.step); + test_step.dependOn(install_step); } diff --git a/go/typdown.go b/go/typdown.go index 386b779..d4bf569 100644 --- a/go/typdown.go +++ b/go/typdown.go @@ -28,7 +28,11 @@ var ( ErrInvalidLink = errors.New("invalid link") ) -func Parse(content string) (template.HTML, error) { +type Document struct { + ptr unsafe.Pointer +} + +func Parse(content string) (*Document, error) { code := C.uchar(0) conv := C.CString(content) raw := C.typdown_parse(conv, &code) @@ -38,8 +42,25 @@ func Parse(content string) (template.HTML, error) { if code == 1 { panic(err) } - return "", err + return nil, err } + return &Document{raw}, nil +} + +func (d *Document) Deinit() { + C.typdown_free(d.ptr) +} + +func (d *Document) RenderHTML() (template.HTML, error) { + code := C.uchar(0) + raw := C.typdown_renderHTML(d.ptr, &code) defer C.free(unsafe.Pointer(raw)) + if code > 0 { + err := codeErrors[uint8(code)] + if code == 1 { + panic(err) + } + return "", err + } return template.HTML(C.GoString(raw)), nil } diff --git a/go/typdown_test.go b/go/typdown_test.go index c1d8985..974f661 100644 --- a/go/typdown_test.go +++ b/go/typdown_test.go @@ -7,7 +7,12 @@ func TestParse(t *testing.T) { if err != nil { t.Fatal(err) } - if res != `

hello world

` { - t.Errorf("invalid result: %s", res) + defer res.Deinit() + got, err := res.RenderHTML() + if err != nil { + t.Fatal(err) + } + if got != `

hello world

` { + t.Errorf("invalid result: %s", got) } } diff --git a/lib/typst/include/typdown_typst.h b/lib/typst/include/typdown_typst.h new file mode 100644 index 0000000..755314a --- /dev/null +++ b/lib/typst/include/typdown_typst.h @@ -0,0 +1,4 @@ +extern const char *typst_generateSVG(const char*); +extern const char *typst_escapeMath(const char*); + +extern void typst_freeString(const char*); diff --git a/lib/typst/typdown_typst.h b/lib/typst/typdown_typst.h deleted file mode 100644 index 755314a..0000000 --- a/lib/typst/typdown_typst.h +++ /dev/null @@ -1,4 +0,0 @@ -extern const char *typst_generateSVG(const char*); -extern const char *typst_escapeMath(const char*); - -extern void typst_freeString(const char*); -- cgit v1.2.3