🕰️
Zigでビルド時にZig依存を作る
はじめに
きっかけ
アイヌ語のIMEを作る時に、COMは自動的にアンロードされないので、いまどのバージョンを実行しているんだっけということを知らせるために、version
という定数にバージョンを入れたいが、手書きで書き換えるの流石にめんどくさいので、ビルド時今の日付・時間を自動的に書き込んでインポートしたいという次第です。
TL;DR
-
pub const VERSION = "04/03 12:34";
というZIGファイル生成するスクリプトを作る。 -
build.zig
でそれをビルドし、匿名インポートとして追加する。 - 本来のプロジェクトファイルで
const VERSION = @import("version").VERSION;
インストール・開発環境整備
以前の文章参照。
実装
以下の資料を参照して、時間を書き込む。
時間付きバージョンファイルの生成
tools\generate_time.zig
const std = @import("std");
pub fn main() !void {
var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_state.deinit();
const arena = arena_state.allocator();
const args = try std.process.argsAlloc(arena);
if (args.len != 2) return error.@"Usage: version.zig <version_file_path>\n";
const output_file_path = args[1];
const jst_offset = 60 * 60 * 9;
const now = std.time.epoch.EpochSeconds{ .secs = @intCast(std.time.timestamp() + jst_offset) };
const month_day = now.getEpochDay().calculateYearDay().calculateMonthDay();
const day_seconds = now.getDaySeconds();
const month = month_day.month.numeric();
const day = month_day.day_index + 1;
const hour = day_seconds.getHoursIntoDay();
const minute = day_seconds.getMinutesIntoHour();
var version_file = try std.fs.cwd().createFile(output_file_path, .{});
defer version_file.close();
const version = try std.fmt.allocPrint(std.heap.page_allocator, "{d:0>2}/{d:0>2} {d:0>2}:{d:0>2}", .{ month, day, hour, minute });
const module = try std.fmt.allocPrint(std.heap.page_allocator, "pub const VERSION = \"{s}\";", .{version});
try version_file.writeAll(module);
return std.process.cleanExit();
}
ビルドステップの追加
build.zig
const std = @import("std");
pub fn build(b: *std.Build) !void {
const tool = b.addExecutable(.{ .name = "generate_time", .root_source_file = .{ .path = "tools/generate_time.zig" }, .target = b.host });
const tool_step = b.addRunArtifact(tool);
tool_step.has_side_effects = true;
const output = tool_step.addOutputFileArg("version.zig");
const artifact = // exeなり、dllなり、libなり...
artifact.root_module.addAnonymousImport("version", .{ .root_source_file = output });
b.installArtifact(artifact);
}
キャッシュについて
現時点では、以下のIssueやPull Requestがある通り、もしhas_side_effects
がtrue
になっている場合、addOutputFileArg
ファイルパスが伝わらないという問題があるので、以上の方法だとエラーが出てしまうため、以下のように時間をパスすることで一時的な解決を図れる。
pub fn build(b: *std.Build) !void {
const tool = b.addExecutable(.{ .name = "generate_time", .root_source_file = .{ .path = "tools/generate_time.zig" }, .target = b.host });
const tool_step = b.addRunArtifact(tool);
const output = tool_step.addOutputFileArg("version.zig");
tool_step.addArg(try std.fmt.allocPrint(std.heap.page_allocator, "{d}", .{std.time.timestamp()}));
// ...
}
const std = @import("std");
pub fn main() !void {
// ...
const args = try std.process.argsAlloc(arena);
defer std.process.argsFree(arena, args);
if (args.len < 2) return error.@"Usage: version.zig <version_file_path>\n";
const output_file_path = args[1];
// ...
}
Discussion