Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ jobs:
- name: Set up Zig
uses: goto-bus-stop/setup-zig@v2
with:
version: '0.12.1'
version: '0.14.1'
- name: Lint
run: ./tools/fmt-check.sh
- name: Test
run: zig build test
- name: Build SDL2
run: |
sudo apt-get install -y libsdl2-dev
zig build -Ddriver=sdl2
# - name: Build SDL2
# run: |
# sudo apt-get install -y libsdl2-dev
# zig build -Ddriver=sdl2
- name: Build X11
run: zig build -Ddriver=x11
run: |
sudo apt-get install -y libx11-dev
zig build -Ddriver=x11
- name: Build Aarch64
run: |
zig build -Ddriver=fbev -Dtarget=aarch64-linux-musl -Doptimize=ReleaseSafe -Dstrip
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
.ccls-cache
.zig-cache
zig-cache
zig-out
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ with `zig build`. otherwise, for macOS or non-X11 platforms use SDL2:

## local development

you'll need [zig v0.12.x](https://ziglang.org/download/).
you'll need [zig v0.14.x](https://ziglang.org/download/).
if working on the gui using sdl2 driver, also [SDL2](https://www.libsdl.org/).

note that compiling the daemon on macOS is currently unsupported since
Expand Down
121 changes: 69 additions & 52 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,37 @@ pub fn build(b: *std.Build) void {
};

// gui build
const ngui = b.addExecutable(.{
.name = "ngui",
const ngui = b.createModule(.{
.root_source_file = b.path("src/ngui.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
.strip = strip,
});
ngui.pie = true;
ngui.root_module.addImport("build_options", buildopts_mod);
ngui.addIncludePath(b.path("lib"));
ngui.addIncludePath(b.path("src/ui/c"));
const ngui_exe = b.addExecutable(.{
.name = "ngui",
.root_module = ngui,
});
ngui_exe.pie = true;
ngui_exe.root_module.addImport("build_options", buildopts_mod);
ngui_exe.addIncludePath(b.path("lib"));
ngui_exe.addIncludePath(b.path("src/ui/c"));

const lvgl_flags = .{
"-std=c11",
"-fstack-protector",
"-Wformat",
"-Wformat-security",
} ++ common_cflags;
ngui.addCSourceFiles(.{ .files = lvgl_generic_src, .flags = &lvgl_flags });
ngui_exe.addCSourceFiles(.{ .files = lvgl_generic_src, .flags = &lvgl_flags });

const ngui_cflags = .{
"-std=c11",
"-Wshadow",
"-Wunused-parameter",
"-Werror",
} ++ common_cflags;
ngui.addCSourceFiles(.{
ngui_exe.addCSourceFiles(.{
.root = b.path("src/ui/c"),
.files = &.{
"ui.c",
Expand All @@ -69,69 +72,77 @@ pub fn build(b: *std.Build) void {
.flags = &ngui_cflags,
});

ngui.root_module.addCMacro("NM_DISP_HOR", b.fmt("{d}", .{disp_horiz}));
ngui.root_module.addCMacro("NM_DISP_VER", b.fmt("{d}", .{disp_vert}));
ngui.defineCMacro("LV_CONF_INCLUDE_SIMPLE", "1");
ngui.defineCMacro("LV_LOG_LEVEL", lvgl_loglevel.text());
ngui.defineCMacro("LV_TICK_CUSTOM", "1");
ngui.defineCMacro("LV_TICK_CUSTOM_INCLUDE", "\"lv_custom_tick.h\"");
ngui.defineCMacro("LV_TICK_CUSTOM_SYS_TIME_EXPR", "(nm_get_curr_tick())");
ngui_exe.root_module.addCMacro("NM_DISP_HOR", b.fmt("{d}", .{disp_horiz}));
ngui_exe.root_module.addCMacro("NM_DISP_VER", b.fmt("{d}", .{disp_vert}));
ngui_exe.root_module.addCMacro("LV_CONF_INCLUDE_SIMPLE", "1");
ngui_exe.root_module.addCMacro("LV_LOG_LEVEL", lvgl_loglevel.text());
ngui_exe.root_module.addCMacro("LV_TICK_CUSTOM", "1");
ngui_exe.root_module.addCMacro("LV_TICK_CUSTOM_INCLUDE", "\"lv_custom_tick.h\"");
ngui_exe.root_module.addCMacro("LV_TICK_CUSTOM_SYS_TIME_EXPR", "(nm_get_curr_tick())");
switch (drv) {
.sdl2 => {
ngui.addCSourceFiles(.{ .files = lvgl_sdl2_src, .flags = &lvgl_flags });
ngui.addCSourceFile(.{ .file = b.path("src/ui/c/drv_sdl2.c"), .flags = &ngui_cflags });
ngui.defineCMacro("USE_SDL", "1");
ngui.linkSystemLibrary("SDL2");
ngui_exe.addCSourceFiles(.{ .files = lvgl_sdl2_src, .flags = &lvgl_flags });
ngui_exe.addCSourceFile(.{ .file = b.path("src/ui/c/drv_sdl2.c"), .flags = &ngui_cflags });
ngui_exe.root_module.addCMacro("USE_SDL", "1");
ngui_exe.linkSystemLibrary("SDL2");
},
.x11 => {
ngui.addCSourceFiles(.{ .files = lvgl_x11_src, .flags = &lvgl_flags });
ngui.addCSourceFiles(.{
ngui_exe.addCSourceFiles(.{ .files = lvgl_x11_src, .flags = &lvgl_flags });
ngui_exe.addCSourceFiles(.{
.files = &.{
"src/ui/c/drv_x11.c",
"src/ui/c/mouse_cursor_icon.c",
},
.flags = &ngui_cflags,
});
ngui.defineCMacro("USE_X11", "1");
ngui.linkSystemLibrary("X11");
ngui_exe.root_module.addCMacro("USE_X11", "1");
ngui_exe.linkSystemLibrary("X11");
},
.fbev => {
ngui.addCSourceFiles(.{ .files = lvgl_fbev_src, .flags = &lvgl_flags });
ngui.addCSourceFile(.{ .file = b.path("src/ui/c/drv_fbev.c"), .flags = &ngui_cflags });
ngui.defineCMacro("USE_FBDEV", "1");
ngui.defineCMacro("USE_EVDEV", "1");
ngui_exe.addCSourceFiles(.{ .files = lvgl_fbev_src, .flags = &lvgl_flags });
ngui_exe.addCSourceFile(.{ .file = b.path("src/ui/c/drv_fbev.c"), .flags = &ngui_cflags });
ngui_exe.root_module.addCMacro("USE_FBDEV", "1");
ngui_exe.root_module.addCMacro("USE_EVDEV", "1");
},
}

const ngui_build_step = b.step("ngui", "build ngui (nakamochi gui)");
ngui_build_step.dependOn(&b.addInstallArtifact(ngui, .{}).step);
ngui_build_step.dependOn(&b.addInstallArtifact(ngui_exe, .{}).step);

// daemon build
const nd = b.addExecutable(.{
.name = "nd",
const nd = b.createModule(.{
.root_source_file = b.path("src/nd.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
.strip = strip,
});
nd.pie = true;
nd.root_module.addImport("build_options", buildopts_mod);
nd.root_module.addImport("nif", libnif_dep.module("nif"));
nd.root_module.addImport("ini", libini_dep.module("ini"));
nd.linkLibrary(libnif);
const nd_exe = b.addExecutable(.{
.name = "nd",
.root_module = nd,
});
nd_exe.pie = true;
nd_exe.root_module.addImport("build_options", buildopts_mod);
nd_exe.root_module.addImport("nif", libnif_dep.module("nif"));
nd_exe.root_module.addImport("ini", libini_dep.module("ini"));
nd_exe.linkLibrary(libnif);

const nd_build_step = b.step("nd", "build nd (nakamochi daemon)");
nd_build_step.dependOn(&b.addInstallArtifact(nd, .{}).step);
nd_build_step.dependOn(&b.addInstallArtifact(nd_exe, .{}).step);

// automated tests
{
const tests = b.addTest(.{
const mod_tests = b.createModule(.{
.root_source_file = b.path("src/test.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
.filter = b.option([]const u8, "test-filter", "run tests matching the filter"),
});
const tests = b.addTest(.{
.root_module = mod_tests,
.filters = &.{b.option([]const u8, "test-filter", "run tests matching the filter") orelse ""},
});

tests.root_module.addImport("build_options", buildopts_mod);
tests.root_module.addImport("nif", libnif_dep.module("nif"));
tests.root_module.addImport("ini", libini_dep.module("ini"));
Expand All @@ -144,47 +155,53 @@ pub fn build(b: *std.Build) void {

// GUI playground
{
const guiplay = b.addExecutable(.{
.name = "guiplay",
const guiplay = b.createModule(.{
.root_source_file = b.path("src/test/guiplay.zig"),
.target = target,
.optimize = optimize,
});
guiplay.root_module.addImport("comm", b.createModule(.{ .root_source_file = b.path("src/comm.zig") }));
const guiplay_exe = b.addExecutable(.{
.name = "guiplay",
.root_module = guiplay,
});
guiplay_exe.root_module.addImport("comm", b.createModule(.{ .root_source_file = b.path("src/comm.zig") }));

const guiplay_build_step = b.step("guiplay", "build GUI playground");
guiplay_build_step.dependOn(&b.addInstallArtifact(guiplay, .{}).step);
guiplay_build_step.dependOn(&b.addInstallArtifact(guiplay_exe, .{}).step);
guiplay_build_step.dependOn(ngui_build_step);
}

// bitcoind RPC client playground
{
const btcrpc = b.addExecutable(.{
.name = "btcrpc",
const btcrpc = b.createModule(.{
.root_source_file = b.path("src/test/btcrpc.zig"),
.target = target,
.optimize = optimize,
.strip = strip,
});
btcrpc.root_module.addImport("bitcoindrpc", b.createModule(.{ .root_source_file = b.path("src/bitcoindrpc.zig") }));
const btcrpc_exe = b.addExecutable(.{
.name = "btcrpc",
.root_module = btcrpc,
});
btcrpc_exe.root_module.addImport("bitcoindrpc", b.createModule(.{ .root_source_file = b.path("src/bitcoindrpc.zig") }));

const btcrpc_build_step = b.step("btcrpc", "bitcoind RPC client playground");
btcrpc_build_step.dependOn(&b.addInstallArtifact(btcrpc, .{}).step);
btcrpc_build_step.dependOn(&b.addInstallArtifact(btcrpc_exe, .{}).step);
}

// lnd HTTP API client playground
{
const lndhc = b.addExecutable(.{
.name = "lndhc",
const lndhc = b.createModule(.{
.root_source_file = b.path("src/test/lndhc.zig"),
.target = target,
.optimize = optimize,
.strip = strip,
});
lndhc.root_module.addImport("lightning", b.createModule(.{ .root_source_file = b.path("src/lightning.zig") }));
const lndhc_exe = b.addExecutable(.{ .name = "lndhc", .root_module = lndhc });
lndhc_exe.root_module.addImport("lightning", b.createModule(.{ .root_source_file = b.path("src/lightning.zig") }));

const lndhc_build_step = b.step("lndhc", "lnd HTTP API client playground");
lndhc_build_step.dependOn(&b.addInstallArtifact(lndhc, .{}).step);
lndhc_build_step.dependOn(&b.addInstallArtifact(lndhc_exe, .{}).step);
}

// default build step
Expand Down Expand Up @@ -376,7 +393,7 @@ const LVGLLogLevel = enum {
none,

/// returns default mode based on the compiler optimization flags.
fn default(mode: std.builtin.Mode) @This() {
fn default(mode: std.builtin.OptimizeMode) @This() {
return switch (mode) {
.Debug => .warn,
.ReleaseSafe => .warn,
Expand Down Expand Up @@ -427,7 +444,7 @@ const VersionStep = struct {
return &vstep.step;
}

fn make(step: *std.Build.Step, _: *std.Progress.Node) anyerror!void {
fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) anyerror!void {
const self: *@This() = @fieldParentPtr("step", step);
const semver = try self.eval();
std.log.info("build version: {any}", .{semver});
Expand Down
3 changes: 2 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.{
.name = "ndg",
.name = .ndg,
.fingerprint = 0x6f4f65601db92599,
.version = "0.8.1",
.dependencies = .{
.nif = .{
Expand Down
2 changes: 1 addition & 1 deletion lib/ini
Submodule ini updated 2 files
+1 −1 .gitignore
+9 −13 build.zig
12 changes: 8 additions & 4 deletions lib/nif/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ pub fn build(b: *std.Build) void {

const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const lib = b.addStaticLibrary(.{
.name = "nif",
const lib_mod = b.createModule(.{
.root_source_file = b.path("nif.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
lib.defineCMacro("CONFIG_CTRL_IFACE", null);
lib.defineCMacro("CONFIG_CTRL_IFACE_UNIX", null);
const lib = b.addLibrary(.{
.linkage = .static,
.name = "nif",
.root_module = lib_mod,
});
lib.root_module.addCMacro("CONFIG_CTRL_IFACE", "");
lib.root_module.addCMacro("CONFIG_CTRL_IFACE_UNIX", "");
lib.addIncludePath(b.path("wpa_supplicant"));
lib.addCSourceFiles(.{
.files = &.{
Expand Down
4 changes: 2 additions & 2 deletions src/lightning/LndConf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ test "lnd: conf load dump" {

var tmp = try tt.TempDir.create();
defer tmp.cleanup();
try tmp.dir.writeFile("conf.ini",
try tmp.dir.writeFile(.{ .sub_path = "conf.ini", .data =
\\; top comment
\\[application options]
\\foo = bar
Expand All @@ -239,7 +239,7 @@ test "lnd: conf load dump" {
\\
\\[AutopiloT]
\\autopilot.active=false
);
});
const clean_conf =
\\[application options]
\\foo=bar
Expand Down
6 changes: 3 additions & 3 deletions src/nd.zig
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ pub fn main() !void {
if (conf.data.slock != null) {
try ngui_args.append("-slock");
}
var ngui = std.ChildProcess.init(ngui_args.items, gpa);
var ngui = std.process.Child.init(ngui_args.items, gpa);
ngui.stdin_behavior = .Pipe;
ngui.stdout_behavior = .Pipe;
ngui.stderr_behavior = .Inherit;
Expand Down Expand Up @@ -224,8 +224,8 @@ pub fn main() !void {
.mask = posix.empty_sigset,
.flags = 0,
};
try posix.sigaction(posix.SIG.INT, &sa, null);
try posix.sigaction(posix.SIG.TERM, &sa, null);
posix.sigaction(posix.SIG.INT, &sa, null);
posix.sigaction(posix.SIG.TERM, &sa, null);
sigquit.wait();
Comment on lines +227 to 229
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Handle sigaction errors instead of ignoring them

Same concern as ngui: if handler install fails, graceful shutdown may be skipped. Log failures.

-    posix.sigaction(posix.SIG.INT, &sa, null);
-    posix.sigaction(posix.SIG.TERM, &sa, null);
+    posix.sigaction(posix.SIG.INT, &sa, null) catch |err| {
+        logger.warn("sigaction INT failed: {any}", .{err});
+    };
+    posix.sigaction(posix.SIG.TERM, &sa, null) catch |err| {
+        logger.warn("sigaction TERM failed: {any}", .{err});
+    };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
posix.sigaction(posix.SIG.INT, &sa, null);
posix.sigaction(posix.SIG.TERM, &sa, null);
sigquit.wait();
// Install SIGINT handler, logging if it fails
posix.sigaction(posix.SIG.INT, &sa, null) catch |err| {
logger.warn("sigaction INT failed: {any}", .{err});
};
// Install SIGTERM handler, logging if it fails
posix.sigaction(posix.SIG.TERM, &sa, null) catch |err| {
logger.warn("sigaction TERM failed: {any}", .{err});
};
sigquit.wait();
🤖 Prompt for AI Agents
In src/nd.zig around lines 227-229, the two posix.sigaction calls are used but
their return values are ignored; if installing a signal handler fails the
program may skip graceful shutdown. Change each posix.sigaction call to capture
its return/error, and when it indicates failure log the error (include
errno/strerror or Zig's error detail) via the existing logger or std.debug.warn
with clear context (e.g., "failed to install SIGINT handler: <err>"), then
decide a safe fallback (continue running with logging or initiate shutdown)
rather than silently ignoring the failure.

logger.info("sigquit: terminating ...", .{});

Expand Down
Loading
Loading