feat(build.zig): add option to use system dependencies

Problem:
build.zig always downloads dependencies and statically links them,
which is frowned upon by distro packagers.

Solution:
Add option to use system libraries.
This commit is contained in:
Chinmay Dalal
2025-12-20 00:11:05 -05:00
parent dddc359213
commit 6d9031390c
7 changed files with 331 additions and 120 deletions

257
build.zig
View File

@@ -1,5 +1,6 @@
const std = @import("std");
const LazyPath = std.Build.LazyPath;
const Compile = std.Build.Step.Compile;
const build_lua = @import("src/build_lua.zig");
const gen = @import("src/gen/gen_steps.zig");
const runtime = @import("runtime/gen_runtime.zig");
@@ -16,6 +17,15 @@ const version = struct {
const api_prerelease = true;
};
pub const SystemIntegrationOptions = packed struct {
lpeg: bool,
lua: bool,
tree_sitter: bool,
unibilium: bool,
utf8proc: bool,
uv: bool,
};
// TODO(bfredl): this is for an upstream issue
pub fn lazyArtifact(d: *std.Build.Dependency, name: []const u8) ?*std.Build.Step.Compile {
var found: ?*std.Build.Step.Compile = null;
@@ -54,51 +64,68 @@ pub fn build(b: *std.Build) !void {
const arch = t.cpu.arch;
const default_luajit = (is_linux and arch == .x86_64) or (is_darwin and arch == .aarch64);
const use_luajit = b.option(bool, "luajit", "use luajit") orelse default_luajit;
const lualib_name = if (use_luajit) "luajit" else "lua5.1";
const host_use_luajit = if (cross_compiling) false else use_luajit;
const E = enum { luajit, lua51 };
const system_integration_options = SystemIntegrationOptions{
.lpeg = b.systemIntegrationOption("lpeg", .{}),
.lua = b.systemIntegrationOption("lua", .{}),
.tree_sitter = b.systemIntegrationOption("tree-sitter", .{}),
.unibilium = b.systemIntegrationOption("unibilium", .{}),
.utf8proc = b.systemIntegrationOption("utf8proc", .{}),
.uv = b.systemIntegrationOption("uv", .{}),
};
const ziglua = b.dependency("zlua", .{
.target = target,
.optimize = optimize_lua,
.lang = if (use_luajit) E.luajit else E.lua51,
.shared = false,
.system_lua = system_integration_options.lua,
});
const ziglua_host = if (cross_compiling) b.dependency("zlua", .{
.target = target_host,
.optimize = .ReleaseSmall,
.lang = if (host_use_luajit) E.luajit else E.lua51,
.system_lua = system_integration_options.lua,
.shared = false,
}) else ziglua;
var lua: ?*Compile = null;
var libuv: ?*Compile = null;
var libluv: ?*Compile = null;
var libluv_host: ?*Compile = null;
if (!system_integration_options.lua) {
// this is currently not necessary, as ziglua currently doesn't use lazy dependencies
// to circumvent ziglua.artifact() failing in a bad way.
lua = lazyArtifact(ziglua, "lua") orelse return;
if (cross_compiling) {
_ = lazyArtifact(ziglua_host, "lua") orelse return;
}
}
if (!system_integration_options.uv) {
if (b.lazyDependency("libuv", .{ .target = target, .optimize = optimize })) |dep| {
libuv = dep.artifact("uv");
libluv = try build_lua.build_libluv(b, target, optimize, lua, libuv.?, use_luajit);
const lpeg = b.dependency("lpeg", .{});
libluv_host = if (cross_compiling) libluv_host: {
const libuv_dep_host = b.lazyDependency("libuv", .{ .target = target_host, .optimize = optimize_host });
const libuv_host = libuv_dep_host.?.artifact("uv");
break :libluv_host try build_lua.build_libluv(b, target_host, optimize_host, ziglua_host.artifact("lua"), libuv_host, host_use_luajit);
} else libluv;
}
}
const lpeg = if (system_integration_options.lpeg) null else b.lazyDependency("lpeg", .{});
const iconv = if (is_windows or is_darwin) b.lazyDependency("libiconv", .{ .target = target, .optimize = optimize }) else null;
// this is currently not necessary, as ziglua currently doesn't use lazy dependencies
// to circumvent ziglua.artifact() failing in a bad way.
const lua = lazyArtifact(ziglua, "lua") orelse return;
if (cross_compiling) {
_ = lazyArtifact(ziglua_host, "lua") orelse return;
}
// const lua = ziglua.artifact("lua");
const libuv_dep = b.dependency("libuv", .{ .target = target, .optimize = optimize });
const libuv = libuv_dep.artifact("uv");
const libluv = try build_lua.build_libluv(b, target, optimize, lua, libuv);
const libluv_host = if (cross_compiling) libluv_host: {
const libuv_dep_host = b.dependency("libuv", .{ .target = target_host, .optimize = optimize_host });
const libuv_host = libuv_dep_host.artifact("uv");
break :libluv_host try build_lua.build_libluv(b, target_host, optimize_host, ziglua_host.artifact("lua"), libuv_host);
} else libluv;
const utf8proc = b.dependency("utf8proc", .{ .target = target, .optimize = optimize });
const unibilium = if (use_unibilium) b.lazyDependency("unibilium", .{ .target = target, .optimize = optimize }) else null;
const utf8proc = if (system_integration_options.utf8proc) null else b.lazyDependency("utf8proc", .{ .target = target, .optimize = optimize });
const unibilium = if (use_unibilium and !system_integration_options.unibilium) b.lazyDependency("unibilium", .{ .target = target, .optimize = optimize }) else null;
// TODO(bfredl): fix upstream bugs with UBSAN
const treesitter = b.dependency("treesitter", .{ .target = target, .optimize = .ReleaseFast });
const treesitter = if (system_integration_options.tree_sitter) null else b.lazyDependency("treesitter", .{ .target = target, .optimize = .ReleaseFast });
const nlua0 = build_lua.build_nlua0(b, target_host, optimize_host, host_use_luajit, ziglua_host, lpeg, libluv_host);
const nlua0 = try build_lua.build_nlua0(b, target_host, optimize_host, host_use_luajit, ziglua_host, lpeg, libluv_host, system_integration_options);
// usual caveat emptor: might need to force a rebuild if the only change is
// addition of new .c files, as those are not seen by any hash
@@ -228,6 +255,9 @@ pub fn build(b: *std.Build) !void {
.VTERM_TEST_FILE = "test/vterm_test_output", // TODO(bfredl): revisit when porting libvterm tests
});
const system_install_path = b.option([]const u8, "install-path", "Install path (for packagers)");
const install_path = system_install_path orelse b.install_path;
const lib_dir = if (system_install_path) |path| b.fmt("{s}/lib", .{path}) else b.lib_dir;
_ = gen_config.addCopyFile(sysconfig_step.getOutput(), "auto/config.h"); // run_preprocessor() workaronnd
_ = gen_config.add("auto/pathdef.h", b.fmt(
@@ -235,7 +265,7 @@ pub fn build(b: *std.Build) !void {
\\char *default_vimruntime_dir = "";
\\char *default_lib_dir = "{s}/nvim";
// b.lib_dir is typically b.install_path + "/lib" but may be overridden
, .{ try replace_backslashes(b, b.install_path), try replace_backslashes(b, b.lib_dir) }));
, .{ try replace_backslashes(b, install_path), try replace_backslashes(b, lib_dir) }));
const opt_version_string = b.option([]const u8, "version-string", "Override Neovim version string. Default is to find out with git.");
const version_medium = if (opt_version_string) |version_string| version_string else v: {
@@ -282,17 +312,45 @@ pub fn build(b: *std.Build) !void {
// TODO(zig): using getEmittedIncludeTree() is ugly af. we want unittests
// to reuse the std.build.Module include_path thing
const unittest_include_path = [_]LazyPath{
b.path("src/"),
gen_config.getDirectory(),
lua.getEmittedIncludeTree(),
libuv.getEmittedIncludeTree(),
libluv.getEmittedIncludeTree(),
utf8proc.artifact("utf8proc").getEmittedIncludeTree(),
if (unibilium) |u| u.artifact("unibilium").getEmittedIncludeTree() else b.path("UNUSED_PATH/"), // :p
treesitter.artifact("tree-sitter").getEmittedIncludeTree(),
if (iconv) |dep| dep.artifact("iconv").getEmittedIncludeTree() else b.path("UNUSED_PATH/"),
};
var unittest_include_path: std.ArrayList(LazyPath) = try .initCapacity(b.allocator, 2);
try unittest_include_path.append(b.allocator, b.path("src/"));
try unittest_include_path.append(b.allocator, gen_config.getDirectory());
if (system_integration_options.lua) {
try appendSystemIncludePath(b, &unittest_include_path, lualib_name);
} else if (lua) |compile| {
try unittest_include_path.append(b.allocator, compile.getEmittedIncludeTree());
}
if (system_integration_options.uv) {
try appendSystemIncludePath(b, &unittest_include_path, "libuv");
try appendSystemIncludePath(b, &unittest_include_path, "libluv");
} else {
if (libuv) |compile| {
try unittest_include_path.append(b.allocator, compile.getEmittedIncludeTree());
}
if (libluv) |compile| {
try unittest_include_path.append(b.allocator, compile.getEmittedIncludeTree());
}
}
if (system_integration_options.utf8proc) {
try appendSystemIncludePath(b, &unittest_include_path, "libutf8proc");
} else if (utf8proc) |dep| {
try unittest_include_path.append(b.allocator, dep.artifact("utf8proc").getEmittedIncludeTree());
}
if (use_unibilium) {
if (system_integration_options.unibilium) {
try appendSystemIncludePath(b, &unittest_include_path, "unibilium");
} else if (unibilium) |dep| {
try unittest_include_path.append(b.allocator, dep.artifact("unibilium").getEmittedIncludeTree());
}
}
if (system_integration_options.tree_sitter) {
try appendSystemIncludePath(b, &unittest_include_path, "tree-sitter");
} else if (treesitter) |dep| {
try unittest_include_path.append(b.allocator, dep.artifact("tree-sitter").getEmittedIncludeTree());
}
if (iconv) |dep| {
try unittest_include_path.append(b.allocator, dep.artifact("iconv").getEmittedIncludeTree());
}
const gen_headers, const funcs_data = try gen.nvim_gen_sources(b, nlua0, &nvim_sources, &nvim_headers, &api_headers, versiondef_git, version_lua);
@@ -309,24 +367,50 @@ pub fn build(b: *std.Build) !void {
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
nvim_exe.rdynamic = true; // -E
nvim_exe.linkLibrary(lua);
nvim_exe.linkLibrary(libuv);
nvim_exe.linkLibrary(libluv);
if (system_integration_options.lua) {
nvim_exe.root_module.linkSystemLibrary(lualib_name, .{});
} else if (lua) |compile| {
nvim_exe.root_module.linkLibrary(compile);
}
if (system_integration_options.uv) {
nvim_exe.root_module.linkSystemLibrary("libuv", .{});
nvim_exe.root_module.linkSystemLibrary("libluv", .{});
} else {
if (libuv) |compile|
nvim_exe.root_module.linkLibrary(compile);
if (libluv) |compile|
nvim_exe.root_module.linkLibrary(compile);
}
if (iconv) |dep| nvim_exe.linkLibrary(dep.artifact("iconv"));
nvim_exe.linkLibrary(utf8proc.artifact("utf8proc"));
if (unibilium) |u| nvim_exe.linkLibrary(u.artifact("unibilium"));
nvim_exe.linkLibrary(treesitter.artifact("tree-sitter"));
if (system_integration_options.utf8proc) {
nvim_exe.root_module.linkSystemLibrary("utf8proc", .{});
} else if (utf8proc) |dep| {
nvim_exe.root_module.linkLibrary(dep.artifact("utf8proc"));
}
if (use_unibilium) {
if (system_integration_options.unibilium) {
nvim_exe.root_module.linkSystemLibrary("unibilium", .{});
} else if (unibilium) |dep| {
nvim_exe.root_module.linkLibrary(dep.artifact("unibilium"));
}
}
if (system_integration_options.tree_sitter) {
nvim_exe.root_module.linkSystemLibrary("tree-sitter", .{});
} else if (treesitter) |dep| {
nvim_exe.root_module.linkLibrary(dep.artifact("tree-sitter"));
}
if (is_windows) {
nvim_exe.linkSystemLibrary("netapi32");
}
nvim_exe.addIncludePath(b.path("src"));
nvim_exe.addIncludePath(gen_config.getDirectory());
nvim_exe.addIncludePath(gen_headers.getDirectory());
build_lua.add_lua_modules(nvim_exe.root_module, lpeg, use_luajit, false);
try build_lua.add_lua_modules(b, t, nvim_exe.root_module, lpeg, use_luajit, false, system_integration_options);
var unit_test_sources = try std.ArrayList([]u8).initCapacity(b.allocator, 10);
if (support_unittests) {
@@ -415,12 +499,12 @@ pub fn build(b: *std.Build) !void {
b.installDirectory(.{ .source_dir = b.path("runtime/"), .install_dir = .prefix, .install_subdir = "share/nvim/runtime/" });
b.installDirectory(.{ .source_dir = gen_runtime.getDirectory(), .install_dir = .prefix, .install_subdir = "share/nvim/runtime/" });
test_deps.dependOn(test_fixture(b, "shell-test", null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "tty-test", libuv, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "pwsh-test", null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "printargs-test", null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "printenv-test", null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "streams-test", libuv, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "shell-test", false, false, null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "tty-test", true, system_integration_options.uv, libuv, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "pwsh-test", false, false, null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "printargs-test", false, false, null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "printenv-test", false, false, null, target, optimize, &flags));
test_deps.dependOn(test_fixture(b, "streams-test", true, system_integration_options.uv, libuv, target, optimize, &flags));
// xxd - hex dump utility (vendored from Vim)
const xxd_exe = b.addExecutable(.{
@@ -434,28 +518,39 @@ pub fn build(b: *std.Build) !void {
xxd_exe.linkLibC();
test_deps.dependOn(&b.addInstallArtifact(xxd_exe, .{}).step);
const parser_c = b.dependency("treesitter_c", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "c", parser_c.path("."), false, target, optimize));
const parser_markdown = b.dependency("treesitter_markdown", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "markdown", parser_markdown.path("tree-sitter-markdown/"), true, target, optimize));
test_deps.dependOn(add_ts_parser(b, "markdown_inline", parser_markdown.path("tree-sitter-markdown-inline/"), true, target, optimize));
const parser_vim = b.dependency("treesitter_vim", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "vim", parser_vim.path("."), true, target, optimize));
const parser_vimdoc = b.dependency("treesitter_vimdoc", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "vimdoc", parser_vimdoc.path("."), false, target, optimize));
const parser_lua = b.dependency("treesitter_lua", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "lua", parser_lua.path("."), true, target, optimize));
const parser_query = b.dependency("treesitter_query", .{ .target = target, .optimize = optimize });
test_deps.dependOn(add_ts_parser(b, "query", parser_query.path("."), false, target, optimize));
const unit_headers: ?[]const LazyPath = if (support_unittests) &(unittest_include_path ++ .{gen_headers.getDirectory()}) else null;
if (b.lazyDependency("treesitter_c", .{ .target = target, .optimize = optimize })) |parser| {
test_deps.dependOn(add_ts_parser(b, "c", parser.path("."), false, target, optimize));
}
if (b.lazyDependency("treesitter_markdown", .{ .target = target, .optimize = optimize })) |parser| {
test_deps.dependOn(add_ts_parser(b, "markdown", parser.path("tree-sitter-markdown/"), true, target, optimize));
test_deps.dependOn(add_ts_parser(b, "markdown_inline", parser.path("tree-sitter-markdown-inline/"), true, target, optimize));
}
if (b.lazyDependency("treesitter_vim", .{ .target = target, .optimize = optimize })) |parser| {
test_deps.dependOn(add_ts_parser(b, "vim", parser.path("."), true, target, optimize));
}
if (b.lazyDependency("treesitter_vimdoc", .{ .target = target, .optimize = optimize })) |parser| {
test_deps.dependOn(add_ts_parser(b, "vimdoc", parser.path("."), false, target, optimize));
}
if (b.lazyDependency("treesitter_lua", .{ .target = target, .optimize = optimize })) |parser| {
test_deps.dependOn(add_ts_parser(b, "lua", parser.path("."), true, target, optimize));
}
if (b.lazyDependency("treesitter_query", .{ .target = target, .optimize = optimize })) |parser| {
test_deps.dependOn(add_ts_parser(b, "query", parser.path("."), false, target, optimize));
}
var unit_headers: ?[]const LazyPath = null;
if (support_unittests) {
try unittest_include_path.append(b.allocator, gen_headers.getDirectory());
unit_headers = unittest_include_path.items;
}
try tests.test_steps(b, nvim_exe, test_deps, lua_dev_deps.path("."), test_config_step.getDirectory(), unit_headers);
}
pub fn test_fixture(
b: *std.Build,
name: []const u8,
use_libuv: bool,
use_system_libuv: bool,
libuv: ?*std.Build.Step.Compile,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
@@ -475,7 +570,13 @@ pub fn test_fixture(
fixture.addCSourceFile(.{ .file = b.path(b.fmt("./test/functional/fixtures/{s}.c", .{source})), .flags = flags });
fixture.linkLibC();
if (libuv) |uv| fixture.linkLibrary(uv);
if (use_libuv) {
if (use_system_libuv) {
fixture.root_module.linkSystemLibrary("libuv", .{});
} else if (libuv) |uv| {
fixture.linkLibrary(uv);
}
}
return &b.addInstallArtifact(fixture, .{}).step;
}
@@ -551,3 +652,29 @@ pub fn test_config(b: *std.Build) ![]u8 {
\\return M
, .{ .bin_dir = try replace_backslashes(b, b.install_path), .src_path = try replace_backslashes(b, src_path) });
}
fn appendSystemIncludePath(
b: *std.Build,
path: *std.ArrayList(LazyPath),
system_name: []const u8,
) !void {
var code: u8 = 0;
const stdout = try b.runAllowFail(
&[_][]const u8{ "pkg-config", system_name, "--cflags-only-I", "--keep-system-cflags" },
&code,
.Ignore,
);
if (code != 0) return std.Build.PkgConfigError.PkgConfigFailed;
var arg_it = std.mem.tokenizeAny(u8, stdout, " \r\n\t");
while (arg_it.next()) |arg| {
if (std.mem.eql(u8, arg, "-I")) {
// -I /foo/bar
const dir = arg_it.next() orelse return std.Build.PkgConfigError.PkgConfigInvalidOutput;
try path.append(b.allocator, .{ .cwd_relative = dir });
} else if (std.mem.startsWith(u8, arg, "-I")) {
// -I/foo/bar
const dir = arg[("-I".len)..];
try path.append(b.allocator, .{ .cwd_relative = dir });
}
}
}

View File

@@ -6,30 +6,35 @@
.dependencies = .{
.zlua = .{
.url = "git+https://github.com/natecraddock/ziglua#a4d08d97795c312e63a0f09d456f7c6d280610b4",
.hash = "zlua-0.1.0-hGRpC5c9BQAfU5bkkFfLV9B4a7Prw8N7JPIFAZBbRCkq",
.url = "git+https://github.com/natecraddock/ziglua#dca1800ea46f5a19fc9abf88b2f8c1617f86ac23",
.hash = "zlua-0.1.0-hGRpC1dCBQDf-IqqUifYvyr8B9-4FlYXqY8cl7HIetrC",
},
.lpeg = .{
.url = "https://github.com/neovim/deps/raw/d495ee6f79e7962a53ad79670cb92488abe0b9b4/opt/lpeg-1.1.0.tar.gz",
.hash = "N-V-__8AAMnaAwCEutreuREG3QayBVEZqUTDQFY1Nsrv2OIt",
.lazy = true,
},
.luv = .{
.url = "git+https://github.com/luvit/luv?ref=1.51.0-1#4c9fbc6cf6f3338bb0e0426710cf885ee557b540",
.hash = "N-V-__8AAMlNDwCY07jUoMiq3iORXdZy0uFWKiHsy8MaDBJA",
.lazy = true,
},
.lua_compat53 = .{
.url = "https://github.com/lunarmodules/lua-compat-5.3/archive/v0.13.tar.gz",
.hash = "N-V-__8AADi-AwDnVoXwDCQvv2wcYOmN0bJLqZ44J3lwoQY2",
.lazy = true,
},
.treesitter = .{
.url = "git+https://github.com/tree-sitter/tree-sitter?ref=v0.26.3#cd4b6e2ef996d4baca12caadb78dffc8b55bc869",
.hash = "tree_sitter-0.26.3-Tw2sRwKWCwB6DronNIXBd7Aq5TY4WlnmS4d8PB_M7TIU",
.lazy = true,
},
.libuv = .{
.url = "git+https://github.com/allyourcodebase/libuv#a2dfd385bd2a00d6d290fda85a40a55a9d6cffc5",
.hash = "libuv-1.51.0-htqqv6liAADxBLIBCZT-qUh_3nRRwtNYsOFQOUmrd_sx",
.lazy = true,
},
.utf8proc = .{ .path = "./deps/utf8proc/" },
.utf8proc = .{ .path = "./deps/utf8proc/", .lazy = true },
.unibilium = .{ .path = "./deps/unibilium/", .lazy = true },
.libiconv = .{
.url = "git+https://github.com/allyourcodebase/libiconv#9def4c8a1743380e85bcedb80f2c15b455e236f3",
@@ -43,26 +48,32 @@
.treesitter_c = .{
.url = "git+https://github.com/tree-sitter/tree-sitter-c?ref=v0.24.1#7fa1be1b694b6e763686793d97da01f36a0e5c12",
.hash = "N-V-__8AANxPSABzw3WBTSH_YkwaGAfrK6PBqAMqQedkDDim",
.lazy = true,
},
.treesitter_markdown = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-markdown?ref=v0.5.1#2dfd57f547f06ca5631a80f601e129d73fc8e9f0",
.hash = "N-V-__8AABcZUwBZelO8MiLRwuLD1Wk34qHHbXtS4UW3Khys",
.lazy = true,
},
.treesitter_lua = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-lua?ref=v0.4.1#816840c592ab973500ae9750763c707b447e7fef",
.hash = "N-V-__8AAHCmCAAf-5sa_C1N5Ts8B7V-vTKqUEMJZVnNkq_y",
.lazy = true,
},
.treesitter_vim = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-vim?ref=v0.7.0#3dd4747082d1b717b8978211c06ef7b6cd16125b",
.hash = "N-V-__8AAMArVAB4uo2wg2XRs8HBviQ4Pq366cC_iRolX4Vc",
.lazy = true,
},
.treesitter_vimdoc = .{
.url = "git+https://github.com/neovim/tree-sitter-vimdoc?ref=v4.1.0#f061895a0eff1d5b90e4fb60d21d87be3267031a",
.hash = "N-V-__8AAI7VCgBqRcQ-vIxB8DJJFhmLG42p6rfwCWIdypSJ",
.lazy = true,
},
.treesitter_query = .{
.url = "git+https://github.com/tree-sitter-grammars/tree-sitter-query?ref=v0.8.0#a225e21d81201be77da58de614e2b7851735677a",
.hash = "N-V-__8AAMR5AwAzZ5_8S2p2COTEf5usBeeT4ORzh-lBGkWy",
.lazy = true,
},
},
.paths = .{

View File

@@ -4,7 +4,6 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("unibilium", .{});
const lib = b.addLibrary(.{
.name = "unibilium",
.linkage = .static,
@@ -14,17 +13,19 @@ pub fn build(b: *std.Build) !void {
}),
});
lib.addIncludePath(upstream.path(""));
if (b.lazyDependency("unibilium", .{})) |upstream| {
lib.addIncludePath(upstream.path(""));
lib.installHeader(upstream.path("unibilium.h"), "unibilium.h");
lib.installHeader(upstream.path("unibilium.h"), "unibilium.h");
lib.linkLibC();
lib.linkLibC();
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"unibilium.c",
"uninames.c",
"uniutil.c",
}, .flags = &.{"-DTERMINFO_DIRS=\"/etc/terminfo:/usr/share/terminfo\""} });
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"unibilium.c",
"uninames.c",
"uniutil.c",
}, .flags = &.{"-DTERMINFO_DIRS=\"/etc/terminfo:/usr/share/terminfo\""} });
}
b.installArtifact(lib);
}

View File

@@ -7,6 +7,7 @@
.unibilium = .{
.url = "git+https://github.com/neovim/unibilium?ref=v2.1.2#bfcb0350129dd76893bc90399cf37c45812268a2",
.hash = "N-V-__8AADO1CgCggvx73yptnBlXbEm7TjOSO6VGIqc0CvYR",
.lazy = true,
},
},
}

View File

@@ -4,7 +4,6 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("utf8proc", .{});
const lib = b.addLibrary(.{
.name = "utf8proc",
.linkage = .static,
@@ -14,14 +13,16 @@ pub fn build(b: *std.Build) !void {
}),
});
lib.addIncludePath(upstream.path(""));
lib.installHeader(upstream.path("utf8proc.h"), "utf8proc.h");
if (b.lazyDependency("utf8proc", .{})) |upstream| {
lib.addIncludePath(upstream.path(""));
lib.installHeader(upstream.path("utf8proc.h"), "utf8proc.h");
lib.linkLibC();
lib.linkLibC();
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"utf8proc.c",
}, .flags = &.{"-DUTF8PROC_STATIC"} });
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"utf8proc.c",
}, .flags = &.{"-DUTF8PROC_STATIC"} });
}
b.installArtifact(lib);
}

View File

@@ -7,6 +7,7 @@
.utf8proc = .{
.url = "git+https://github.com/juliastrings/utf8proc?ref=v2.11.3#e5e799221b45bbb90f5fdc5c69b6b8dfbf017e78",
.hash = "N-V-__8AACywKABFCj0r_Y-jIWsk9ahy10zlk78hjn6S-39g",
.lazy = true,
},
},
}

View File

@@ -1,4 +1,5 @@
const std = @import("std");
const build = @import("../build.zig");
const LazyPath = std.Build.LazyPath;
pub fn build_nlua0(
@@ -7,9 +8,10 @@ pub fn build_nlua0(
optimize: std.builtin.OptimizeMode,
use_luajit: bool,
ziglua: *std.Build.Dependency,
lpeg: *std.Build.Dependency,
libluv: *std.Build.Step.Compile,
) *std.Build.Step.Compile {
lpeg: ?*std.Build.Dependency,
libluv: ?*std.Build.Step.Compile,
system_integration_options: build.SystemIntegrationOptions,
) !*std.Build.Step.Compile {
const options = b.addOptions();
options.addOption(bool, "use_luajit", use_luajit);
@@ -19,6 +21,7 @@ pub fn build_nlua0(
.root_source_file = b.path("src/nlua0.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
const nlua0_mod = nlua0_exe.root_module;
@@ -28,6 +31,7 @@ pub fn build_nlua0(
.root_source_file = b.path("src/nlua0.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
}),
});
@@ -39,14 +43,23 @@ pub fn build_nlua0(
mod.addImport("ziglua", ziglua.module("zlua"));
mod.addImport("embedded_data", embedded_data);
// addImport already links by itself. but we need headers as well..
mod.linkLibrary(ziglua.artifact("lua"));
mod.linkLibrary(libluv);
if (system_integration_options.lua) {
const system_lua_lib = if (use_luajit) "luajit" else "lua5.1";
mod.linkSystemLibrary(system_lua_lib, .{});
} else {
mod.linkLibrary(ziglua.artifact("lua"));
}
if (libluv) |luv| {
mod.linkLibrary(luv);
} else {
mod.linkSystemLibrary("luv", .{});
}
mod.addOptions("options", options);
mod.addIncludePath(b.path("src"));
mod.addIncludePath(b.path("src/includes_fixmelater"));
add_lua_modules(mod, lpeg, use_luajit, true);
try add_lua_modules(b, target.result, mod, lpeg, use_luajit, true, system_integration_options);
}
// for debugging the nlua0 environment
@@ -68,14 +81,24 @@ pub fn build_nlua0(
return nlua0_exe;
}
pub fn add_lua_modules(mod: *std.Build.Module, lpeg: *std.Build.Dependency, use_luajit: bool, is_nlua0: bool) void {
pub fn add_lua_modules(
b: *std.Build,
target: std.Target,
mod: *std.Build.Module,
lpeg_dep: ?*std.Build.Dependency,
use_luajit: bool,
is_nlua0: bool,
system_integration_options: build.SystemIntegrationOptions,
) !void {
const flags = [_][]const u8{
// Standard version used in Lua Makefile
"-std=gnu99",
if (is_nlua0) "-DNVIM_NLUA0" else "",
};
mod.addIncludePath(lpeg.path(""));
if (lpeg_dep) |lpeg| {
mod.addIncludePath(lpeg.path(""));
}
mod.addCSourceFiles(.{
.files = &.{
"src/mpack/lmpack.c",
@@ -86,18 +109,25 @@ pub fn add_lua_modules(mod: *std.Build.Module, lpeg: *std.Build.Dependency, use_
},
.flags = &flags,
});
mod.addCSourceFiles(.{
.root = .{ .dependency = .{ .dependency = lpeg, .sub_path = "" } },
.files = &.{
"lpcap.c",
"lpcode.c",
"lpcset.c",
"lpprint.c",
"lptree.c",
"lpvm.c",
},
.flags = &flags,
});
if (system_integration_options.lpeg) {
if (try findLpeg(b, target)) |lpeg_lib| {
mod.addLibraryPath(.{ .cwd_relative = std.fs.path.dirname(lpeg_lib).? });
mod.addObjectFile(.{ .cwd_relative = lpeg_lib });
}
} else if (lpeg_dep) |lpeg| {
mod.addCSourceFiles(.{
.root = .{ .dependency = .{ .dependency = lpeg, .sub_path = "" } },
.files = &.{
"lpcap.c",
"lpcode.c",
"lpcset.c",
"lpprint.c",
"lptree.c",
"lpvm.c",
},
.flags = &flags,
});
}
if (!use_luajit) {
mod.addCSourceFiles(.{
@@ -113,11 +143,12 @@ pub fn build_libluv(
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
lua: *std.Build.Step.Compile,
lua: ?*std.Build.Step.Compile,
libuv: *std.Build.Step.Compile,
use_luajit: bool,
) !*std.Build.Step.Compile {
const upstream = b.dependency("luv", .{});
const compat53 = b.dependency("lua_compat53", .{});
const upstream = b.lazyDependency("luv", .{});
const compat53 = b.lazyDependency("lua_compat53", .{});
const lib = b.addLibrary(.{
.name = "luv",
.linkage = .static,
@@ -127,21 +158,59 @@ pub fn build_libluv(
}),
});
lib.linkLibrary(lua);
if (lua) |lua_lib| {
lib.root_module.linkLibrary(lua_lib);
} else {
const system_lua_lib = if (use_luajit) "luajit" else "lua5.1";
lib.root_module.linkSystemLibrary(system_lua_lib, .{});
}
lib.linkLibrary(libuv);
lib.addIncludePath(upstream.path("src"));
lib.addIncludePath(compat53.path("c-api"));
lib.installHeader(upstream.path("src/luv.h"), "luv/luv.h");
lib.addCSourceFiles(.{ .root = upstream.path("src/"), .files = &.{
"luv.c",
} });
lib.addCSourceFiles(.{ .root = compat53.path("c-api"), .files = &.{
"compat-5.3.c",
} });
if (upstream) |dep| {
lib.addIncludePath(dep.path("src"));
lib.installHeader(dep.path("src/luv.h"), "luv/luv.h");
lib.addCSourceFiles(.{ .root = dep.path("src/"), .files = &.{
"luv.c",
} });
}
if (compat53) |dep| {
lib.addIncludePath(dep.path("c-api"));
lib.addCSourceFiles(.{ .root = dep.path("c-api"), .files = &.{
"compat-5.3.c",
} });
}
return lib;
}
fn findLpeg(b: *std.Build, target: std.Target) !?[]const u8 {
const filenames = [_][]const u8{
"lpeg_a",
"lpeg",
"liblpeg_a",
"lpeg.so",
b.fmt("lpeg{s}", .{target.dynamicLibSuffix()}),
};
var code: u8 = 0;
const dirs_stdout = std.mem.trimEnd(u8, try b.runAllowFail(&[_][]const u8{
"pkg-config",
"--variable=pc_system_libdirs",
"--keep-system-cflags",
"pkg-config",
}, &code, .Ignore), "\r\n");
var paths: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 0);
var path_it = std.mem.tokenizeAny(u8, dirs_stdout, " ,");
while (path_it.next()) |dir| {
try paths.append(b.allocator, dir);
try paths.append(b.allocator, b.fmt("{s}/lua/5.1", .{dir}));
}
for (paths.items) |path| {
var dir = std.fs.openDirAbsolute(path, .{}) catch continue;
defer dir.close();
for (filenames) |filename| {
dir.access(filename, .{}) catch continue;
return b.fmt("{s}/{s}", .{ path, filename });
}
}
return null;
}