From d2acc696446392e0ddf30a70ed9da9b370d25516 Mon Sep 17 00:00:00 2001 From: Chinmay Dalal <~chinmay/public-inbox@lists.sr.ht> Date: Sat, 28 Mar 2026 21:04:42 -0400 Subject: [PATCH 1/2] build(zig): add formatc and lintc steps problem: build.zig does not have formatc and lintc steps solution: add formatc and lintc step to build.zig --- .clang-tidy | 1 + .clangd | 2 - .github/workflows/test.yml | 46 ++++++++--- MAINTAIN.md | 2 + build.zig | 13 +++ build.zig.zon | 8 ++ src/lint.zig | 160 +++++++++++++++++++++++++++++++++++++ 7 files changed, 218 insertions(+), 14 deletions(-) create mode 100644 src/lint.zig diff --git a/.clang-tidy b/.clang-tidy index 57d7e39bde..caab023700 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -28,6 +28,7 @@ Checks: > -cert-err34-c, -concurrency-mt-unsafe, -cppcoreguidelines-narrowing-conversions, + -clang-diagnostic-unused-command-line-argument, Warnings that may be useful, but are too inconsistent to enable by default May yield useful results with some manual triaging, diff --git a/.clangd b/.clangd index 9a99bd1d04..ff46ebffb8 100644 --- a/.clangd +++ b/.clangd @@ -1,5 +1,3 @@ -CompileFlags: - CompilationDatabase: build/ # Search build/ directory for compile_commands.json Diagnostics: UnusedIncludes: None Documentation: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e3011d3c40..3bda89b00f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,40 @@ env: # TEST_FILTER: foo jobs: + lintc: + runs-on: ubuntu-24.04 + timeout-minutes: 20 + env: + NVIM_LOG_FILE: ${{ github.workspace }}/zig-out/nvim.log + OPTS: -Doptimize=ReleaseFast -Dci-build + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - uses: ./.github/actions/setup + + - uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2.2.1 + with: + version: 0.16.0 + - run: sudo apt-get install -y inotify-tools + + - name: nvim_bin + id: nvim_bin + run: zig build nvim_bin $OPTS + + - if: success() || failure() && steps.nvim_bin.outcome == 'success' + name: clint.lua + run: zig build lintc-clint $OPTS + + - if: success() || failure() && steps.nvim_bin.outcome == 'success' + name: clang-tidy + run: zig build lintc-clang-tidy $OPTS + + - if: success() || failure() && steps.nvim_bin.outcome == 'success' + name: uncrustify + run: zig build lintc-uncrustify $OPTS + lint: runs-on: ubuntu-24.04-arm timeout-minutes: 10 @@ -82,18 +116,6 @@ jobs: name: lintquery run: cmake --build build --target lintquery - - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: clint.lua - run: cmake --build build --target lintc-clint - - - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: clang-tidy - run: cmake --build build --target lintc-clang-tidy - - - if: success() || failure() && steps.abort_job.outputs.status == 'success' - name: uncrustify - run: cmake --build build --target lintc-uncrustify - clang-analyzer: runs-on: ubuntu-24.04-arm timeout-minutes: 20 diff --git a/MAINTAIN.md b/MAINTAIN.md index 57f8dba183..0ca4a59a4f 100644 --- a/MAINTAIN.md +++ b/MAINTAIN.md @@ -140,6 +140,8 @@ Some can be auto-bumped by `scripts/bump_deps.lua`. * (Deprecated) [unibilium](https://github.com/neovim/unibilium) * The original project [was abandoned](https://github.com/neovim/neovim/issues/10302), so the [neovim/unibilium](https://github.com/neovim/unibilium) fork is considered "upstream" and is maintained on the `master` branch. * **Note:** unibilium is NOT required. See [BUILD.md](./BUILD.md#build-without-unibilium) to build Nvim without unibilium. +* [uncrustify](https://github.com/uncrustify/uncrustify) + * Requires a PR to update the update the [Zig build files](https://github.com/neovim/neovim/tree/master/deps/uncrustify) first. ### Vendored dependencies diff --git a/build.zig b/build.zig index 3e7f285214..00720fc668 100644 --- a/build.zig +++ b/build.zig @@ -5,6 +5,8 @@ const build_lua = @import("src/build_lua.zig"); const gen = @import("src/gen/gen_steps.zig"); const runtime = @import("runtime/gen_runtime.zig"); const tests = @import("test/run_tests.zig"); +const zcc = @import("compile_commands"); +const lint = @import("src/lint.zig"); const version = struct { const major = 0; @@ -103,6 +105,7 @@ pub fn build(b: *std.Build) !void { .utf8proc = b.systemIntegrationOption("utf8proc", .{}), .uv = b.systemIntegrationOption("uv", .{}), }; + const ci_build = b.option(bool, "ci-build", "CI build") orelse false; const ziglua = b.dependency("zlua", .{ .target = target, @@ -735,6 +738,16 @@ pub fn build(b: *std.Build) !void { test_config_step.getDirectory(), unit_headers, ); + + // compile_commands.json + var cdb_targets: std.ArrayListUnmanaged(*std.Build.Step.Compile) = try .initCapacity(b.allocator, 0); + try cdb_targets.append(b.allocator, nvim_exe); + try cdb_targets.append(b.allocator, tee_exe); + try cdb_targets.append(b.allocator, xxd_exe); + const cdb_step = zcc.createStep(b, "cdb", cdb_targets.items); + for (cdb_targets.items) |ct| cdb_step.dependOn(&ct.step); + + try lint.addSteps(b, target, cdb_step, nvim_exe_install, nvim_sources, nvim_headers, ci_build); } pub fn test_fixture( diff --git a/build.zig.zon b/build.zig.zon index 73a47e2636..b2294b1556 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -36,6 +36,10 @@ }, .utf8proc = .{ .path = "./deps/utf8proc/", .lazy = true }, .unibilium = .{ .path = "./deps/unibilium/", .lazy = true }, + .uncrustify = .{ + .url = "git+https://codeberg.org/allyourcodebase/uncrustify#2cdf880e4ffbe438a7946368cd45fca2df9f0f7a", + .hash = "uncrustify-0.83.0-qkVd7cVCAADAg1kS3ctVBhY2gkxEIs-W8wgurLadbgC-", + }, .libiconv = .{ .url = "git+https://github.com/allyourcodebase/libiconv#9def4c8a1743380e85bcedb80f2c15b455e236f3", .hash = "libiconv-1.18.0-p9sJwWnqAACzVYeWgXB5r5lOQ74XwTPlptixV0JPRO28", @@ -65,6 +69,10 @@ .url = "git+https://github.com/tree-sitter-grammars/tree-sitter-query?ref=v0.8.0#a225e21d81201be77da58de614e2b7851735677a", .hash = "N-V-__8AAMR5AwAzZ5_8S2p2COTEf5usBeeT4ORzh-lBGkWy", }, + .compile_commands = .{ + .url = "https://github.com/the-argus/zig-compile-commands/archive/9400cd1963ea6bb58fe47ba7d9700075b808cdd2.tar.gz", + .hash = "zig_compile_commands-0.0.1-OZg5-e_JAAAGg1WHAePtq4l4Uvjs34BexnFFCZk63EaG", + }, }, .paths = .{ // TODO(bfredl): explicitly list the subdirs which actually are used diff --git a/src/lint.zig b/src/lint.zig new file mode 100644 index 0000000000..e594bc3e1c --- /dev/null +++ b/src/lint.zig @@ -0,0 +1,160 @@ +const std = @import("std"); +const gen = @import("gen/gen_steps.zig"); + +pub fn lintSources( + b: *std.Build, + nvim_sources: std.ArrayList(gen.SourceItem), + nvim_headers: std.ArrayList([]u8), +) !std.ArrayList([]const u8) { + var lint_sources: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 0); + for (nvim_sources.items) |source| { + try lint_sources.append(b.allocator, b.fmt("src/nvim/{s}", .{source.name})); + } + for (nvim_headers.items) |header| { + try lint_sources.append(b.allocator, b.fmt("src/nvim/{s}", .{header})); + } + try lint_sources.append(b.allocator, "src/tee/tee.c"); + try lint_sources.append(b.allocator, "src/xxd/xxd.c"); + return lint_sources; +} + +pub fn addSteps( + b: *std.Build, + target: std.Build.ResolvedTarget, + cdb_step: *std.Build.Step, + nvim_exe_install: *std.Build.Step.InstallArtifact, + nvim_sources: std.ArrayList(gen.SourceItem), + nvim_headers: std.ArrayList([]u8), + ci_build: bool, +) !void { + const lintc = b.step("lintc", "Lint C source"); + var lint_sources = try lintSources(b, nvim_sources, nvim_headers); + defer lint_sources.deinit(b.allocator); + const lintc_uncrustify = addLintcUncrustifyStep(b, lint_sources); + lintc.dependOn(lintc_uncrustify); + const lintc_clint = addLintcClintStep(b, nvim_exe_install, lint_sources, ci_build); + lintc.dependOn(lintc_clint); + const lintc_clang_tidy = try addLintcClangtidyStep(b, cdb_step, nvim_exe_install, target, lint_sources); + lintc.dependOn(lintc_clang_tidy); + try addFormatcStep(b, lint_sources); +} + +fn addLintcUncrustifyStep( + b: *std.Build, + lint_sources: std.ArrayList([]const u8), +) *std.Build.Step { + const lintc_uncrustify = b.step("lintc-uncrustify", "Check formatting of C source with uncrustify"); + const uncrustify = b.dependency("uncrustify", .{ + .target = b.graph.host, + .optimize = .ReleaseFast, + }); + const uncrustify_exe = uncrustify.artifact("uncrustify"); + for (lint_sources.items) |file| { + const run = b.addRunArtifact(uncrustify_exe); + run.addArgs(&.{ "-c", "src/uncrustify.cfg", "-q", "--check" }); + run.addFileArg(b.path(file)); + run.expectExitCode(0); + lintc_uncrustify.dependOn(&run.step); + } + return lintc_uncrustify; +} + +fn addLintcClangtidyStep( + b: *std.Build, + cdb_step: *std.Build.Step, + nvim_exe_install: *std.Build.Step.InstallArtifact, + target: std.Build.ResolvedTarget, + lint_sources: std.ArrayList([]const u8), +) !*std.Build.Step { + const lintc_clang_tidy = b.step("lintc-clang-tidy", "Lint C source with clang-tidy"); + var exclusions: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 0); + defer exclusions.deinit(b.allocator); + try exclusions.appendSlice(b.allocator, &.{ + "src/nvim/eval/typval_encode.c.h", + "src/nvim/api/ui_events.in.h", + "src/xxd/xxd.c", + }); + if (target.result.os.tag == .windows) { + try exclusions.appendSlice(b.allocator, &.{ + "src/nvim/os/pty_proc_unix.h", + "src/nvim/os/unix_defs.h", + }); + } else { + try exclusions.appendSlice(b.allocator, &.{ + "src/nvim/os/win_defs.h", + "src/nvim/os/pty_proc_win.h", + "src/nvim/os/pty_conpty_win.h", + "src/nvim/os/os_win_console.h", + }); + } + + outer: for (lint_sources.items) |file| { + for (exclusions.items) |exclusion| { + if (std.mem.eql(u8, exclusion, file)) continue :outer; + } + const run = b.addSystemCommand(&.{"clang-tidy"}); + run.step.dependOn(cdb_step); + run.step.dependOn(&nvim_exe_install.step); + run.addFileArg(b.path(file)); + run.addArg("--quiet"); + run.expectStdOutEqual(""); + lintc_clang_tidy.dependOn(&run.step); + } + return lintc_clang_tidy; +} + +fn addLintcClintStep( + b: *std.Build, + // use InstallArtifact instead of nvim_exe so that cache is not busted + // for every file to be linted + nvim_exe_install: *std.Build.Step.InstallArtifact, + lint_sources: std.ArrayList([]const u8), + ci_build: bool, +) *std.Build.Step { + const lintc_clint = b.step("lintc-clint", "Lint C source with clint"); + const exclusions = [_][]const u8{ "src/nvim/tui/terminfo_defs.h", "src/xxd/xxd.c" }; + const nvim_path = b.getInstallPath(.bin, nvim_exe_install.artifact.out_filename); + + outer: for (lint_sources.items) |file| { + for (exclusions) |exclusion| { + if (std.mem.endsWith(u8, file, exclusion)) continue :outer; + } + const run = b.addSystemCommand(&.{nvim_path}); + run.step.dependOn(&nvim_exe_install.step); + run.addArgs(&.{ "-u", "NONE", "-l" }); + run.addFileArg(b.path("src/clint.lua")); + if (ci_build) { + run.addArg("--output=gh_action"); + } else { + run.addArg("--output=vs7"); + } + run.addFileArg(b.path(file)); + run.expectStdOutEqual(""); + lintc_clint.dependOn(&run.step); + } + return lintc_clint; +} + +fn addFormatcStep( + b: *std.Build, + lint_sources: std.ArrayList([]const u8), +) !void { + const formatc = b.step("formatc", "Format C source with uncrustify"); + const uncrustify = b.dependency("uncrustify", .{ + .target = b.graph.host, + .optimize = .ReleaseFast, + }); + const uncrustify_exe = uncrustify.artifact("uncrustify"); + + const update = b.addUpdateSourceFiles(); + for (lint_sources.items) |file| { + const run = b.addRunArtifact(uncrustify_exe); + run.addArgs(&.{ "-c", "src/uncrustify.cfg", "-f" }); + run.addFileArg(b.path(file)); + run.addArg("-o"); + const output_name = try std.mem.replaceOwned(u8, b.allocator, file, "/", "-"); + const output = run.addOutputFileArg(output_name); + update.addCopyFileToSource(output, file); + } + formatc.dependOn(&update.step); +} From 637c4422d8cb131481110440916e077b73df08f4 Mon Sep 17 00:00:00 2001 From: Chinmay Dalal <~chinmay/public-inbox@lists.sr.ht> Date: Sat, 2 May 2026 23:52:55 -0400 Subject: [PATCH 2/2] build(zig): use LLVM for building nlua0 problem: https://codeberg.org/ziglang/zig/issues/31272 solution: set `.use_llvm = true` until the next zig release --- src/build_lua.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/build_lua.zig b/src/build_lua.zig index a1896c40e9..3646412406 100644 --- a/src/build_lua.zig +++ b/src/build_lua.zig @@ -23,6 +23,7 @@ pub fn build_nlua0( .optimize = optimize, .link_libc = true, }), + .use_llvm = true, }); const nlua0_mod = nlua0_exe.root_module;