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
3 changes: 2 additions & 1 deletion backend/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ pub fn backendModule(dep: *std.Build.Dependency, dvui_mod: *std.Build.Module, op
fn patchedSdl(b: *std.Build) ?std.Build.LazyPath {
const io = b.graph.io;
var names: std.ArrayList([]const u8) = .empty;
var dir = b.root.root_dir.handle.openDir(io, "patches/sdl", .{ .iterate = true }) catch |err|
b.dependOnDirectoryContents(b.path("patches/sdl"));
var dir = b.root.openDir(io, "patches/sdl", .{ .iterate = true }) catch |err|
std.debug.panic("backend: open patches/sdl: {t}", .{err});
defer dir.close(io);
var it = dir.iterate();
Expand Down
3 changes: 3 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ pub fn build(b: *std.Build) !void {
const windows_msvc_libc_opt = b.option([]const u8, "windows-msvc-libc", "zig libc manifest for *-windows-msvc when cross-compiling; forwarded by packageall for Windows children") orelse null;
const fetch_msvc_opt = b.option(bool, "fetch-msvc", "If *-windows-msvc libc is missing under .velopack-msvc/, run msvcup-setup first (downloads MSVC+SDK; requires network). Defaults to true on Windows hosts targeting *-windows-msvc.") orelse null;

// ZIG017 (release packaging PR): the FIZZY_MACOS_* fallbacks below are read at configure, and
// 0.17 caches the configuration without regard to the environment; scripts/release.sh and
// release.yml pass the -D options instead.
const macos_sign_app_identity = b.option([]const u8, "macos-sign-app", "macOS codesign identity for the app bundle (e.g. 'Developer ID Application: NAME (TEAMID)')") orelse
b.graph.environ_map.get("FIZZY_MACOS_SIGN_APP");
const macos_sign_install_identity = b.option([]const u8, "macos-sign-installer", "macOS codesign identity for the installer pkg (e.g. 'Developer ID Installer: NAME (TEAMID)')") orelse
Expand Down
1 change: 0 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"build",
"build.zig",
"build.zig.zon",
"update.zig",
"sdk",
"backend",
"assets",
Expand Down
67 changes: 18 additions & 49 deletions build/app.zig
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pub fn readConfig(b: *std.Build, target: std.Build.ResolvedTarget, opts: Options

var effective_win_libc: ?[]const u8 = win_libc.libc_path;
if (effective_win_libc == null) {
if (cross_win_msvc) effective_win_libc = null; // ZIG017: 0.17 has no global --libc
if (cross_win_msvc) effective_win_libc = null; // ZIG017 (release packaging PR): 0.17 has no global --libc; becomes -Dwindows-libc
}

// Velopack in the dev/install exe is opt-in (`-Dvelopack=true`). Release
Expand Down Expand Up @@ -204,6 +204,7 @@ pub fn readConfig(b: *std.Build, target: std.Build.ResolvedTarget, opts: Options
var version_owned: ?[]u8 = null; // lives as long as the build process

const app_version: []const u8 = if (app_version_opt) |v| v else blk: {
b.dependOnFileContents(b.path("VERSION"));
const raw = b.root.root_dir.handle.readFileAlloc(b.graph.io, "VERSION", b.allocator, std.Io.Limit.limited(256)) catch |e| std.debug.panic("read VERSION: {}", .{e});
version_owned = raw;
break :blk std.mem.trimEnd(u8, raw, "\r\n");
Expand Down Expand Up @@ -259,8 +260,6 @@ pub fn readConfig(b: *std.Build, target: std.Build.ResolvedTarget, opts: Options
const workbench_opts = b.addOptions();
workbench_opts.addOption(bool, "file_tree", workbench_file_tree);

common.addUpdateStep(b);

const msvcup_before_compile: ?*std.Build.Step.Run = if (vz) |v| velopack.addMsvcupSetupStep(b, v, ".velopack-msvc") else null;
const msvcup_setup_step = b.step("msvcup-setup", "Download MSVC SDK into .velopack-msvc/ via velopack-zig (writes zig-libc-*.ini)");
if (msvcup_before_compile) |m| msvcup_setup_step.dependOn(&m.step);
Expand Down Expand Up @@ -336,7 +335,7 @@ pub fn construct(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
const zig_out_install_dir = cfg.zig_out_install_dir;
const target_is_windows_msvc = cfg.target_is_windows_msvc;
const cross_win_msvc = cfg.cross_win_msvc;
_ = cross_win_msvc; // ZIG017
_ = cross_win_msvc; // ZIG017 (release packaging PR)
const effective_win_libc = cfg.effective_win_libc;
const velopack_supported_for_target = cfg.velopack_supported_for_target;
const velopack_enabled = cfg.velopack_enabled;
Expand Down Expand Up @@ -428,8 +427,20 @@ pub fn construct(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
.dest_dir = .{ .override = zig_out_install_dir },
});
// A running fizzy holds its executable on Windows: set it aside first, or the install fails.
if (false) { // ZIG017: custom step + configure-time install path, both gone in 0.17
const aside = SetAsideRunningExe.create(b, b.getInstallPath(zig_out_install_dir, exe.out_filename));
if (b.graph.host.result.os.tag == .windows and target.result.os.tag == .windows) {
const aside_exe = b.addExecutable(.{
.name = "set-aside",
.root_module = b.createModule(.{
.root_source_file = b.path("build/set_aside.zig"),
.target = b.graph.host,
.optimize = .fast,
}),
});
const aside = b.addRunArtifact(aside_exe);
aside.setName("set aside a running executable");
aside.addDirectoryArg(common.installDirPath(zig_out_install_dir));
aside.addArg(exe.out_filename);
aside.has_side_effects = true;
aside.step.dependOn(&exe.step);
install_artifact.step.dependOn(&aside.step);
}
Expand Down Expand Up @@ -1392,7 +1403,7 @@ pub fn construct(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
};

if (effective_win_libc) |ini| {
// ZIG017: no global --libc in 0.17
// ZIG017 (release packaging PR): no global --libc in 0.17
const libc_lp: std.Build.LazyPath = .{ .cwd_relative = ini };
velopack.applyWindowsMsvcLibcRecursive(b, roots[0..n], libc_lp);

Expand Down Expand Up @@ -1445,45 +1456,3 @@ fn addTestBinaryArgs(
} else try addTestBinaryArgs(b, run, seen, dep);
}
}

/// Windows will not let a file a running process was started from be written or deleted, but it
/// will let it be renamed. So before the install, an installed executable that is running (it
/// cannot be opened for writing) is renamed aside, to `<name>.<time>.old` beside it. The running
/// app goes on from the renamed file; with Restart when rebuilt on it sees the new one land and
/// restarts into it, and the next launch deletes what was set aside
/// (`ExecutableWatcher.removeSetAside`). An executable nothing runs is left for the install to
/// replace as it always has. Only on a Windows host, the one with the lock, and only once the
/// compile has succeeded, so a failed build leaves the running app's file where it was.
const SetAsideRunningExe = struct {
step: std.Build.Step,
path: []const u8,

fn create(b: *std.Build, path: []const u8) *SetAsideRunningExe {
const self = b.allocator.create(SetAsideRunningExe) catch @panic("OOM");
self.* = .{
.step = std.Build.Step.init(.{ .id = .custom, .name = "set aside a running executable", .owner = b, .makeFn = make }),
.path = path,
};
return self;
}

fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) anyerror!void {
const self: *SetAsideRunningExe = @fieldParentPtr("step", step);
const io = step.owner.graph.io;
const cwd = std.Io.Dir.cwd();
var file = cwd.openFile(io, self.path, .{ .mode = .read_write }) catch |err| switch (err) {
error.FileNotFound => return,
else => {
// Held: a running app. Renamed, the install's path is free.
const aside = try std.fmt.allocPrint(step.owner.allocator, "{s}.{d}.old", .{ self.path, std.Io.Clock.real.now(io).nanoseconds });
std.Io.Dir.renameAbsolute(self.path, aside, io) catch |rename_err| {
std.log.warn("{s} is in use and could not be set aside ({t}); the install will fail until it quits", .{ self.path, rename_err });
return;
};
std.log.info("{s} is running: set aside as {s}", .{ self.path, std.fs.path.basename(aside) });
return;
},
};
file.close(io);
}
};
37 changes: 11 additions & 26 deletions build/common.zig
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
const std = @import("std");

const plugin = @import("fizzy_sdk").plugin;
const update = @import("../update.zig");
const GitDependency = update.GitDependency;

/// Install `{id}.{ext}` flat under a `plugins/` directory (no `lib` prefix).
pub fn attachBuiltinPluginInstall(
Expand All @@ -15,31 +13,16 @@ pub fn attachBuiltinPluginInstall(
parent.dependOn(&plugin.installBuiltinPlugin(b, dylib, id, plugins_dir).step);
}

pub fn addUpdateStep(b: *std.Build) void {
const step = b.step("update", "update git dependencies");
_ = step; // ZIG017: makeFn gone; this step is stale anyway
}

fn updateStep(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
const deps = &.{
GitDependency{
.url = "https://github.com/foxnne/zig-objc",
.branch = "main",
},
GitDependency{
.url = "https://github.com/kristoff-it/zigwin32",
.branch = "fix/zig16",
},
GitDependency{
.url = "https://github.com/foxnne/zig-lib-icons",
.branch = "dvui",
},
GitDependency{
.url = "https://github.com/foxnne/dvui-dev",
.branch = "main",
},
/// Where `dir` is under the install prefix, resolved when the build runs: Zig 0.17 has no
/// install path at configure time.
pub fn installDirPath(dir: std.Build.InstallDir) std.Build.LazyPath {
return switch (dir) {
.prefix => .{ .relative = .{ .base = .install_prefix } },
.lib => .{ .relative = .{ .base = .install_lib } },
.bin => .{ .relative = .{ .base = .install_bin } },
.header => .{ .relative = .{ .base = .install_include } },
.custom => |sub| .{ .relative = .{ .base = .install_prefix, .sub_path = sub } },
};
try update.update_dependency(step.owner.allocator, step.owner.graph.io, deps);
}

/// Installed artifacts go under `zig-out/<this>/…` so `packageall` and parallel targets never clobber each other.
Expand Down Expand Up @@ -75,6 +58,8 @@ pub const MacosSdlPaths = struct {
};

fn resolveMacosSdkPath(b: *std.Build) ![]const u8 {
// ZIG017 (release packaging PR): `SDKROOT` is read at configure, which 0.17 caches without
// regard to the environment; becomes a -D option.
if (b.graph.environ_map.get("SDKROOT")) |sdk| {
const trimmed = std.mem.trim(u8, sdk, " \t\r\n");
if (trimmed.len > 0) {
Expand Down
2 changes: 1 addition & 1 deletion build/exe.zig
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ pub fn addFizzyExecutableForTarget(

const exe = b.addExecutable(.{
.name = app_name,
.root_module = b.createModule(.{ // ZIG017: 0.17 refuses a second public "App"
.root_module = b.createModule(.{ // private: one per target, and 0.17 refuses a second public "App"
.target = resolved_target,
.optimize = optimize,
// `b.path`, not `.cwd_relative`: this resolves against *fizzy's* build root, which
Expand Down
2 changes: 1 addition & 1 deletion build/msvc.zig
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const std = @import("std");

pub fn applyMsvcTranslateCShim(b: *std.Build, roots: []const *std.Build.Step.Compile) !void {
if (true) return; // ZIG017: Step.id and generated-file steps reworked in 0.17
if (true) return; // ZIG017 (release packaging PR): Step.id and generated-file steps are gone in 0.17; the MSVC shim moves to where each translate-c step is made
var seen = std.AutoHashMap(*std.Build.Step.TranslateC, void).init(b.allocator);
defer seen.deinit();
for (roots) |root_compile| {
Expand Down
3 changes: 2 additions & 1 deletion build/package.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const common = @import("common.zig");
// Vendored Velopack glue — see build/velopack.zig header (never `@import("velopack_zig")`).
const velopack = @import("velopack.zig");
const exe = @import("exe.zig");
Expand Down Expand Up @@ -141,7 +142,7 @@ pub fn addSteps(opts: Options) *std.Build.Step {
&strip_release_sh.step,
);
vpk_pkg_sh.addArg("--packDir");
vpk_pkg_sh.addArg("zig-out/ZIG017");
vpk_pkg_sh.addDirectoryArg(common.installDirPath(.{ .custom = pack_input_subdir }));
switch (target.result.os.tag) {
.windows => {
// Sets the installer's icon and the Start Menu shortcut icon. The
Expand Down
32 changes: 32 additions & 0 deletions build/set_aside.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! Set aside a running fizzy's executable before the build installs over it: run by a Run step
//! on a Windows host, where a running program holds its file and the install fails. Renamed, the
//! path is free, and the running app keeps its open file. Zig 0.17's build has no custom steps.
//!
//! Usage: `set_aside <install dir> <file name>`. Nothing installed yet, or not held: nothing to do.
const std = @import("std");

pub fn main(init: std.process.Init) !void {
const arena = init.arena.allocator();
const io = init.io;
const args = try init.minimal.args.toSlice(arena);
if (args.len != 3) {
std.debug.print("usage: set_aside <install dir> <file name>\n", .{});
std.process.exit(2);
}
const path = try std.fs.path.join(arena, &.{ args[1], args[2] });
const cwd = std.Io.Dir.cwd();
var file = cwd.openFile(io, path, .{ .mode = .read_write }) catch |err| switch (err) {
error.FileNotFound => return,
else => {
// Held: a running app. Renamed, the install's path is free.
const aside = try std.fmt.allocPrint(arena, "{s}.{d}.old", .{ path, std.Io.Clock.real.now(io).nanoseconds });
std.Io.Dir.rename(cwd, path, cwd, aside, io) catch |rename_err| {
std.log.warn("{s} is in use and could not be set aside ({t}); the install will fail until it quits", .{ path, rename_err });
return;
};
std.log.info("{s} is running: set aside as {s}", .{ path, std.fs.path.basename(aside) });
return;
},
};
file.close(io);
}
2 changes: 1 addition & 1 deletion build/velopack.zig
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ pub fn attachMksquashfsToVpkRun(
) !void {
if (target.result.os.tag != .linux) return;
const built = (try buildMksquashfs(b, vz)) orelse return;
_ = built.bin_dir; // ZIG017: addPathDir gone in 0.17
_ = built.bin_dir; // ZIG017 (release packaging PR): Run.addPathDir is gone in 0.17
run.step.dependOn(built.step);
}

Expand Down
26 changes: 24 additions & 2 deletions build/web.zig
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ pub fn addSteps(
for (web_plugin_dirs) |wp| {
const dir = wp.dir;
const zon_path = b.pathJoin(&.{ dir, "plugin.zig.zon" });
b.root.root_dir.handle.access(b.graph.io, zon_path, .{}) catch {
dependOnPathExistence(b, zon_path);
b.root.access(b.graph.io, zon_path, .{}) catch {
std.debug.print("fizzy web: plugin checkout '{s}' not found; the web build goes without it\n", .{dir});
continue;
};
Expand Down Expand Up @@ -329,7 +330,11 @@ pub fn addSteps(
).step);
for (web_pages.items) |page| {
const web_dir = b.pathJoin(&.{ page.dir, "web" });
var d = b.root.root_dir.handle.openDir(b.graph.io, web_dir, .{ .iterate = true }) catch continue;
var d = b.root.openDir(b.graph.io, web_dir, .{ .iterate = true }) catch {
dependOnPathExistence(b, web_dir);
continue;
};
b.dependOnDirectoryContents(b.path(web_dir));
defer d.close(b.graph.io);
var it = d.iterate();
while (it.next(b.graph.io) catch null) |entry| {
Expand Down Expand Up @@ -381,6 +386,7 @@ fn stampStorage(b: *std.Build) std.Build.LazyPath {
else => std.debug.panic("-Dweb-storage={s}: only a-z, 0-9, '-' and '_'", .{name}),
};
const token = "__FIZZY_WEB_STORAGE__";
b.dependOnFileContents(b.path("web/index.html"));
const html = b.root.root_dir.handle.readFileAlloc(b.graph.io, "web/index.html", b.allocator, .unlimited) catch |err|
std.debug.panic("web/index.html: {t}", .{err});
if (std.mem.indexOf(u8, html, token) == null) std.debug.panic("web/index.html: no {s} to stamp", .{token});
Expand Down Expand Up @@ -417,3 +423,19 @@ fn rehome(
if (icons_mod) |icons| m.addImport("icons", icons);
return m;
}

/// Declare to Zig 0.17's configure cache that the build read whether `rel` exists: the file itself
/// when it does, and otherwise the nearest directory that exists, since the maker cannot load a
/// configuration that depends on a path inside a missing directory ("configuration failed:
/// FileSystemFailure"). Making the file changes that directory, so the build still reconfigures.
fn dependOnPathExistence(b: *std.Build, rel: []const u8) void {
b.root.access(b.graph.io, rel, .{}) catch {
var dir = std.fs.path.dirname(rel);
while (dir) |d| : (dir = std.fs.path.dirname(d)) {
b.root.access(b.graph.io, d, .{}) catch continue;
return b.dependOnDirectoryMetadata(b.path(d));
}
return b.dependOnDirectoryMetadata(b.path("."));
};
b.dependOnFileMetadata(b.path(rel));
}
1 change: 1 addition & 0 deletions plugins/shared/build/helpers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub const IdentityManifest = @import("../../../sdk/src/manifest_identity.zig").I
/// collide with the same file when the plugin is built standalone (its own `build.zig` already
/// `@import`s it via `plugin_sdk.readManifest`). Panics clearly on a missing/invalid manifest.
pub fn readManifestAt(b: *std.Build, zon_rel_path: []const u8) IdentityManifest {
b.dependOnFileContents(b.path(zon_rel_path));
const raw = b.root.root_dir.handle.readFileAlloc(b.graph.io, zon_rel_path, b.allocator, std.Io.Limit.limited(256 * 1024)) catch |e|
std.debug.panic("fizzy: could not read {s}: {}", .{ zon_rel_path, e });
const src = b.allocator.dupeSentinel(u8, raw, 0) catch @panic("OOM");
Expand Down
Loading
Loading