feat(build): build.zig windows support

Tested using cross-compiling from linux:

    zig build -Dcross=true -Dtarget=x86_64-windows nvim_bin

Note: not fully functional without a runtime, which still has to be
fuddled with manually

Macos and windows builds require a recent zig 0.15+dev version
As this zig master branch is currently too much in flux, we can't make
our CI depend on zig master.

Revisit CI after zig 0.15 release or at least feature freeze.
This commit is contained in:
bfredl
2025-07-17 10:55:43 +02:00
parent 22d90217c6
commit dc6cf3add9
9 changed files with 25 additions and 256 deletions

View File

@@ -209,7 +209,7 @@ jobs:
zig-build:
runs-on: ubuntu-24.04
timeout-minutes: 45
name: build using zig build
name: build using zig build (linux)
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2

View File

@@ -70,11 +70,14 @@ pub fn build(b: *std.Build) !void {
const lpeg = b.dependency("lpeg", .{});
const iconv_apple = if (cross_compiling and is_darwin) b.lazyDependency("iconv_apple", .{ .target = target, .optimize = optimize }) else null;
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 });
@@ -234,7 +237,7 @@ 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 include_path = [_]LazyPath{
const unittest_include_path = [_]LazyPath{
b.path("src/"),
gen_config.getDirectory(),
lua.getEmittedIncludeTree(),
@@ -243,6 +246,7 @@ pub fn build(b: *std.Build) !void {
utf8proc.artifact("utf8proc").getEmittedIncludeTree(),
unibilium.artifact("unibilium").getEmittedIncludeTree(),
treesitter.artifact("tree-sitter").getEmittedIncludeTree(),
if (iconv) |dep| dep.artifact("iconv").getEmittedIncludeTree() else b.path("UNUSED_PATH/"),
};
const gen_headers, const funcs_data = try gen.nvim_gen_sources(b, nlua0, &nvim_sources, &nvim_headers, &api_headers, versiondef_git, version_lua);
@@ -267,12 +271,13 @@ pub fn build(b: *std.Build) !void {
nvim_exe.linkLibrary(lua);
nvim_exe.linkLibrary(libuv);
nvim_exe.linkLibrary(libluv);
if (iconv_apple) |iconv| {
nvim_exe.linkLibrary(iconv.artifact("iconv"));
}
if (iconv) |dep| nvim_exe.linkLibrary(dep.artifact("iconv"));
nvim_exe.linkLibrary(utf8proc.artifact("utf8proc"));
nvim_exe.linkLibrary(unibilium.artifact("unibilium"));
nvim_exe.linkLibrary(treesitter.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());
@@ -304,6 +309,9 @@ pub fn build(b: *std.Build) !void {
"-D_GNU_SOURCE",
if (support_unittests) "-DUNIT_TESTING" else "",
if (use_luajit) "" else "-DNVIM_VENDOR_BIT",
if (is_windows) "-DMSWIN" else "",
if (is_windows) "-DWIN32_LEAN_AND_MEAN" else "",
if (is_windows) "-DUTF8PROC_STATIC" else "",
};
nvim_exe.addCSourceFiles(.{ .files = src_paths, .flags = &flags });
@@ -359,7 +367,7 @@ pub fn build(b: *std.Build) !void {
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) &(include_path ++ .{gen_headers.getDirectory()}) else null;
const unit_headers: ?[]const LazyPath = if (support_unittests) &(unittest_include_path ++ .{gen_headers.getDirectory()}) else null;
try tests.test_steps(b, nvim_exe, test_deps, lua_dev_deps.path("."), test_config_step.getDirectory(), unit_headers);
}

View File

@@ -25,10 +25,17 @@
.url = "git+https://github.com/tree-sitter/tree-sitter#d87921bb9c39b0b06c811f2082f9a9991cdca027",
.hash = "tree_sitter-0.26.0-Tw2sRxO7CwC0NyDrSygSi7UXRHMNUFEF8GRq6dK81lRF",
},
.libuv = .{ .path = "./deps/libuv" },
.libuv = .{
.url = "git+https://github.com/allyourcodebase/libuv#a2dfd385bd2a00d6d290fda85a40a55a9d6cffc5",
.hash = "libuv-1.51.0-htqqv6liAADxBLIBCZT-qUh_3nRRwtNYsOFQOUmrd_sx",
},
.utf8proc = .{ .path = "./deps/utf8proc/" },
.unibilium = .{ .path = "./deps/unibilium/" },
.iconv_apple = .{ .path = "./deps/iconv_apple/", .lazy = true },
.libiconv = .{
.url = "git+https://github.com/allyourcodebase/libiconv#9def4c8a1743380e85bcedb80f2c15b455e236f3",
.hash = "libiconv-1.18.0-p9sJwWnqAACzVYeWgXB5r5lOQ74XwTPlptixV0JPRO28",
.lazy = true,
},
.lua_dev_deps = .{
.url = "https://github.com/neovim/deps/raw/06ef2b58b0876f8de1a3f5a710473dcd7afff251/opt/lua-dev-deps.tar.gz",
.hash = "N-V-__8AAGevEQCHAkCozca5AIdN9DFc3Luf3g3r2AcbyOrm",

View File

@@ -1,93 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("libiconv", .{});
const lib = b.addLibrary(.{
.name = "iconv",
.linkage = .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
lib.addIncludePath(b.path("include/"));
lib.addIncludePath(upstream.path(""));
lib.addIncludePath(upstream.path("citrus/"));
lib.addIncludePath(upstream.path("libcharset/"));
lib.addIncludePath(upstream.path("libiconv_modules/UTF8/"));
// zig any-macos-any headers already includes iconv, it just cannot link without a SDK
// lib.installHeader(upstream.path("iconv.h"), "iconv.h");
lib.linkLibC();
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"citrus/bsd_iconv.c",
"citrus/citrus_bcs.c",
"citrus/citrus_bcs_strtol.c",
"citrus/citrus_bcs_strtoul.c",
"citrus/citrus_csmapper.c",
"citrus/citrus_db.c",
"citrus/citrus_db_factory.c",
"citrus/citrus_db_hash.c",
"citrus/citrus_esdb.c",
"citrus/citrus_hash.c",
"citrus/citrus_iconv.c",
"citrus/citrus_lookup.c",
"citrus/citrus_lookup_factory.c",
"citrus/citrus_mapper.c",
"citrus/citrus_memstream.c",
"citrus/citrus_mmap.c",
"citrus/citrus_module.c",
"citrus/citrus_none.c",
"citrus/citrus_pivot_factory.c",
"citrus/citrus_prop.c",
"citrus/citrus_stdenc.c",
"citrus/__iconv.c",
"citrus/iconv.c",
"citrus/iconv_canonicalize.c",
"citrus/iconv_close.c",
"citrus/iconv_compat.c",
"citrus/iconvctl.c",
"citrus/__iconv_free_list.c",
"citrus/__iconv_get_list.c",
"citrus/iconvlist.c",
"citrus/iconv_open.c",
"citrus/iconv_open_into.c",
"citrus/iconv_set_relocation_prefix.c",
"libcharset/libcharset.c",
"libiconv_modules/BIG5/citrus_big5.c",
"libiconv_modules/DECHanyu/citrus_dechanyu.c",
"libiconv_modules/DECKanji/citrus_deckanji.c",
"libiconv_modules/EUC/citrus_euc.c",
"libiconv_modules/EUCTW/citrus_euctw.c",
"libiconv_modules/GBK2K/citrus_gbk2k.c",
"libiconv_modules/HZ/citrus_hz.c",
"libiconv_modules/iconv_none/citrus_iconv_none.c",
"libiconv_modules/iconv_std/citrus_iconv_std.c",
"libiconv_modules/ISO2022/citrus_iso2022.c",
"libiconv_modules/JOHAB/citrus_johab.c",
"libiconv_modules/mapper_646/citrus_mapper_646.c",
"libiconv_modules/mapper_none/citrus_mapper_none.c",
"libiconv_modules/mapper_serial/citrus_mapper_serial.c",
"libiconv_modules/mapper_std/citrus_mapper_std.c",
"libiconv_modules/mapper_zone/citrus_mapper_zone.c",
"libiconv_modules/MSKanji/citrus_mskanji.c",
"libiconv_modules/UES/citrus_ues.c",
"libiconv_modules/UTF1632/citrus_utf1632.c",
"libiconv_modules/UTF7/citrus_utf7.c",
"libiconv_modules/UTF8/citrus_utf8.c",
"libiconv_modules/UTF8MAC/citrus_utf8mac.c",
"libiconv_modules/VIQR/citrus_viqr.c",
"libiconv_modules/ZW/citrus_zw.c",
}, .flags = &.{
"-D_PATH_I18NMODULE=\"/usr/lib/i18n\"",
"-D_PATH_ESDB=\"/usr/share/i18n/esdb\"",
"-D_PATH_CSMAPPER=\"/usr/share/i18n/csmapper\"",
} });
b.installArtifact(lib);
}

View File

@@ -1,12 +0,0 @@
.{
.name = "libiconv",
.version = "107.0.0",
.paths = .{""},
.dependencies = .{
.libiconv = .{
.url = "git+https://github.com/apple-oss-distributions/libiconv?ref=libiconv-107#a3f3b2c76dbf8ba11881debc6bcb4e309958d252",
.hash = "N-V-__8AAKce8wQq3Mp26YIvUGtazS8KPihcFS4vSGgzQf1x",
},
},
}

View File

@@ -1 +0,0 @@
#define os_variant_has_internal_content(sys) false

128
deps/libuv/build.zig vendored
View File

@@ -1,128 +0,0 @@
const std = @import("std");
// Based on mitchellh/zig-libuv, with changes.
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("libuv", .{});
const lib = b.addLibrary(.{
.name = "uv",
.linkage = .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
lib.addIncludePath(upstream.path("include"));
lib.addIncludePath(upstream.path("src"));
lib.installHeadersDirectory(upstream.path("include"), ".", .{});
if (target.result.os.tag == .windows) {
lib.linkSystemLibrary("psapi");
lib.linkSystemLibrary("user32");
lib.linkSystemLibrary("advapi32");
lib.linkSystemLibrary("iphlpapi");
lib.linkSystemLibrary("userenv");
lib.linkSystemLibrary("ws2_32");
}
if (target.result.os.tag == .linux) {
lib.linkSystemLibrary("pthread");
}
lib.linkLibC();
if (target.result.os.tag != .windows) {
lib.root_module.addCMacro("FILE_OFFSET_BITS", "64");
lib.root_module.addCMacro("_LARGEFILE_SOURCE", "");
}
if (target.result.os.tag == .linux) {
lib.root_module.addCMacro("_GNU_SOURCE", "");
lib.root_module.addCMacro("_POSIX_C_SOURCE", "200112");
}
if (target.result.os.tag.isDarwin()) {
lib.root_module.addCMacro("_DARWIN_UNLIMITED_SELECT", "1");
lib.root_module.addCMacro("_DARWIN_USE_64_BIT_INODE", "1");
}
const root = upstream.path("");
// C files common to all platforms
lib.addCSourceFiles(.{ .root = root, .files = &.{
"src/fs-poll.c",
"src/idna.c",
"src/inet.c",
"src/random.c",
"src/strscpy.c",
"src/strtok.c",
"src/threadpool.c",
"src/timer.c",
"src/uv-common.c",
"src/uv-data-getter-setters.c",
"src/version.c",
} });
if (target.result.os.tag != .windows) {
lib.addCSourceFiles(.{ .root = root, .files = &.{
"src/unix/async.c",
"src/unix/core.c",
"src/unix/dl.c",
"src/unix/fs.c",
"src/unix/getaddrinfo.c",
"src/unix/getnameinfo.c",
"src/unix/loop-watcher.c",
"src/unix/loop.c",
"src/unix/pipe.c",
"src/unix/poll.c",
"src/unix/process.c",
"src/unix/random-devurandom.c",
"src/unix/signal.c",
"src/unix/stream.c",
"src/unix/tcp.c",
"src/unix/thread.c",
"src/unix/tty.c",
"src/unix/udp.c",
} });
}
if (target.result.os.tag == .linux or target.result.os.tag.isDarwin()) {
lib.addCSourceFiles(.{ .root = root, .files = &.{
"src/unix/proctitle.c",
} });
}
if (target.result.os.tag == .linux) {
lib.addCSourceFiles(.{ .root = root, .files = &.{
"src/unix/linux.c",
"src/unix/procfs-exepath.c",
"src/unix/random-getrandom.c",
"src/unix/random-sysctl-linux.c",
} });
}
if (target.result.os.tag.isBSD()) {
lib.addCSourceFiles(.{ .root = root, .files = &.{
"src/unix/bsd-ifaddrs.c",
"src/unix/kqueue.c",
} });
}
if (target.result.os.tag.isDarwin() or target.result.os.tag == .openbsd) {
lib.addCSourceFiles(.{ .root = root, .files = &.{
"src/unix/random-getentropy.c",
} });
}
if (target.result.os.tag.isDarwin()) {
lib.addCSourceFiles(.{ .root = root, .files = &.{
"src/unix/darwin-proctitle.c",
"src/unix/darwin.c",
"src/unix/fsevents.c",
} });
}
b.installArtifact(lib);
}

View File

@@ -1,12 +0,0 @@
.{
.name = "libuv",
.version = "1.51.0",
.paths = .{""},
.dependencies = .{
.libuv = .{
.url = "git+https://github.com/libuv/libuv?ref=v1.51.0#76fb3b73da3f8ddaeeb87d23fda04b9bda219f5e",
.hash = "N-V-__8AAExNRADXPh6GLMmWlqC2EVkp6hzH9wPuzjh_eSkE",
},
},
}

View File

@@ -21,7 +21,7 @@ pub fn build(b: *std.Build) !void {
lib.addCSourceFiles(.{ .root = upstream.path(""), .files = &.{
"utf8proc.c",
} });
}, .flags = &.{"-DUTF8PROC_STATIC"} });
b.installArtifact(lib);
}