webui/build.zig
2024-06-09 11:35:29 +08:00

153 lines
6.0 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const Build = std.Build;
const OptimizeMode = std.builtin.OptimizeMode;
const Compile = Build.Step.Compile;
const Module = Build.Module;
const log = std.log.scoped(.WebUI);
const lib_name = "webui";
const zig_ver = builtin.zig_version.minor;
pub fn build(b: *Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const is_dynamic = b.option(bool, "dynamic", "build the dynamic library") orelse false;
const enable_tls = b.option(bool, "enable-tls", "enable TLS support") orelse false;
const verbose = b.option(bool, "verbose", "enable verbose output") orelse false;
switch (zig_ver) {
11 => {
if (enable_tls and !target.isNative()) {
log.err("cross compilation is not supported with TLS enabled", .{});
std.os.exit(1);
}
},
12, 13, 14 => {
if (enable_tls and !target.query.isNative()) {
log.err("cross compilation is not supported with TLS enabled", .{});
std.process.exit(1);
}
},
else => @compileError("unsupported Zig version!"),
}
if (verbose) {
std.debug.print("Building {s} WebUI library{s}...\n", .{
if (is_dynamic) "dynamic" else "static",
if (enable_tls) " with TLS support" else "",
});
defer std.debug.print("Done.\n", .{});
}
const webui = if (is_dynamic) b.addSharedLibrary(.{
.name = lib_name,
.target = target,
.optimize = optimize,
}) else b.addStaticLibrary(.{
.name = lib_name,
.target = target,
.optimize = optimize,
});
try addLinkerFlags(b, webui, enable_tls);
b.installArtifact(webui);
build_examples(b, webui) catch |err| {
log.err("failed to build examples: {}", .{err});
if (zig_ver < 12) std.os.exit(1) else std.process.exit(1);
};
}
fn addLinkerFlags(b: *Build, webui: *Compile, enable_tls: bool) !void {
const webui_target = if (zig_ver < 12) webui.target else webui.rootModuleTarget();
const is_windows = if (zig_ver < 12) webui_target.isWindows() else webui_target.os.tag == .windows;
// Prepare compiler flags.
const tls_flags = &[_][]const u8{ "-DWEBUI_TLS", "-DNO_SSL_DL", "-DOPENSSL_API_1_1" };
var civetweb_flags = std.ArrayList([]const u8).init(b.allocator);
try civetweb_flags.appendSlice(&[_][]const u8{ "-DNDEBUG", "-DNO_CACHING", "-DNO_CGI", "-DUSE_WEBSOCKET" });
try civetweb_flags.appendSlice(if (enable_tls) tls_flags else &[_][]const u8{ "-DUSE_WEBSOCKET", "-DNO_SSL" });
if (is_windows) try civetweb_flags.append("-DMUST_IMPLEMENT_CLOCK_GETTIME");
webui.addCSourceFile(.{
.file = if (zig_ver < 12) .{ .path = "src/webui.c" } else b.path("src/webui.c"),
.flags = if (enable_tls) tls_flags else &[_][]const u8{"-DNO_SSL"},
});
webui.addCSourceFile(.{
.file = if (zig_ver < 12) .{ .path = "src/civetweb/civetweb.c" } else b.path("src/civetweb/civetweb.c"),
.flags = civetweb_flags.items,
});
webui.linkLibC();
webui.addIncludePath(if (zig_ver < 12) .{ .path = "include" } else b.path("include"));
if (zig_ver < 12) {
webui.installHeader("include/webui.h", "webui.h");
} else {
webui.installHeader(b.path("include/webui.h"), "webui.h");
}
if (webui_target.isDarwin()) {
webui.addCSourceFile(.{
.file = if (zig_ver < 12) .{ .path = "src/webview/wkwebview.m" } else b.path("src/webview/wkwebview.m"),
.flags = &.{},
});
webui.linkFramework("Cocoa");
webui.linkFramework("WebKit");
} else if (is_windows) {
webui.linkSystemLibrary("ws2_32");
webui.linkSystemLibrary("Ole32");
if (webui_target.abi == .msvc) {
webui.linkSystemLibrary("Advapi32");
webui.linkSystemLibrary("Shell32");
webui.linkSystemLibrary("user32");
}
if (enable_tls) {
webui.linkSystemLibrary("bcrypt");
}
}
if (enable_tls) {
webui.linkSystemLibrary("ssl");
webui.linkSystemLibrary("crypto");
}
}
fn build_examples(b: *Build, webui: *Compile) !void {
const build_examples_step = b.step("examples", "builds the library and its examples");
const target = if (zig_ver < 12) webui.target else webui.root_module.resolved_target.?;
const optimize = if (zig_ver < 12) webui.optimize else webui.root_module.optimize.?;
const examples_path = (if (zig_ver < 12) (Build.LazyPath{ .path = "examples/C" }) else b.path("examples/C")).getPath(b);
var examples_dir = if (zig_ver < 12)
try std.fs.openIterableDirAbsolute(examples_path, .{})
else
try std.fs.openDirAbsolute(examples_path, .{ .iterate = true });
defer examples_dir.close();
var paths = examples_dir.iterate();
while (try paths.next()) |val| {
if (val.kind != .directory) {
continue;
}
const example_name = val.name;
const exe = b.addExecutable(.{ .name = example_name, .target = target, .optimize = optimize });
const path = try std.fmt.allocPrint(b.allocator, "examples/C/{s}/main.c", .{example_name});
exe.addCSourceFile(.{ .file = if (zig_ver < 12) .{ .path = path } else b.path(path), .flags = &.{} });
exe.linkLibrary(webui);
const exe_install = b.addInstallArtifact(exe, .{});
const exe_run = b.addRunArtifact(exe);
const step_name = try std.fmt.allocPrint(b.allocator, "run_{s}", .{example_name});
const step_desc = try std.fmt.allocPrint(b.allocator, "run example {s}", .{example_name});
const cwd = try std.fmt.allocPrint(b.allocator, "src/examples/{s}", .{example_name});
if (zig_ver < 12) exe_run.cwd = cwd else exe_run.setCwd(b.path(cwd));
exe_run.step.dependOn(&exe_install.step);
build_examples_step.dependOn(&exe_install.step);
b.step(step_name, step_desc).dependOn(&exe_run.step);
}
}