-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
// Copyright 2025 Shota FUJI
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
//! This file defines how `zig build` command behaves.
//! Run `zig build --help` for available subcommands and options.
//!
//! Learn more at
//! https://ziglang.org/learn/build-system/
const std = @import("std");
const CompileVala = @import("./build/CompileVala.zig");
const LibRoon = @import("./build/LibRoon.zig");
const BuildError = error{
NonValaSourceInSourceListError,
};
const RoonExtension = struct {
id: []const u8,
name: []const u8,
version: []const u8,
};
const app_name = "jp.pocka.plac.gtk-adwaita";
const glib_schemas_dir = "share/glib-2.0/schemas";
const glib_compiled_schema_name = "gschemas.compiled";
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const compile_gschema = b.option(bool, "compile-gschema", "Compile gschema XML file for local run") orelse false;
const libsood = libsood: {
const sood = b.dependency("sood", .{
.target = target,
.optimize = optimize,
.linkage = .static,
});
const lib = sood.artifact("sood");
lib.installHeader(b.path("src/libsood.vapi"), "libsood.vapi");
break :libsood lib;
};
const libroon = LibRoon.init(b, .{
.target = target,
.optimize = optimize,
});
// `zig build emit-libroon`
{
const step = b.step("emit-libroon", "Emit libroon library files.");
step.dependOn(libroon.step);
step.dependOn(libroon.install_pretty_headers);
}
// System libraries to link.
const system_libraries = [_][]const u8{
"gtk4",
"libadwaita-1",
// Neither GTK4 nor Libadwaita provides SVG rendering. We need to use librsvg for
// that purpose, whilst undocumented.
"librsvg-2.0",
"gee-0.8",
"libsoup-3.0",
};
const vala_main = vala_main: {
var compile = try CompileVala.init(b, .{
.src = b.path("src"),
.includeTestFiles = false,
// Vala's GTK binding incorrectly mark `Gtk.StyleContext` as deprecated, even though
// its static method `add_provider_for_display` is the only future proof way to add
// CSS. As Vala compiler has no CLI flag or magic comment to suppress specific use of
// "deprecated" API, I resorted to suppress entire deprecation warnings. This has risk
// of accidentally using deprecated API. It's still better than getting used to see
// warnings on build and starting to ignore warnings.
.suppressDeprecationWarning = true,
});
// System libraries to link.
compile.addPackages(&.{
"gtk4",
"libadwaita-1",
// Neither GTK4 nor Libadwaita provides SVG rendering. We need to use librsvg for
// that purpose, whilst undocumented.
"librsvg-2.0",
"gee-0.8",
"libsoup-3.0",
});
compile.addPackage("posix");
compile.addPackages(&.{ "libsood", "roon" });
compile.addGResourceXML(b.path("data/gresource.xml"));
compile.addVapi(b.path("src/libsood.vapi"));
compile.addVapi(libroon.lib.getEmittedIncludeTree().path(b, "roon.vapi"));
const step = b.step("valac", "Compile C source code from Vala files for debugging purpose");
step.dependOn(compile.step);
break :vala_main compile;
};
const gresouce_c = gresource: {
const compiler = b.addSystemCommand(&.{"glib-compile-resources"});
compiler.addArg("--sourcedir");
compiler.addDirectoryArg(b.path("data"));
compiler.addFileArg(b.path("data/gresource.xml"));
compiler.addArg("--target");
const built_c = compiler.addOutputFileArg("gresource.c");
compiler.addArg("--dependency-file");
_ = compiler.addDepFileOutputArg("resource.d");
compiler.addArg("--generate-source");
break :gresource built_c;
};
const gschema_compiled = gschema: {
const compiler = b.addSystemCommand(&.{"glib-compile-schemas"});
compiler.addArg("--targetdir");
const out = compiler.addOutputDirectoryArg("compiled");
compiler.addArg("--strict");
compiler.addDirectoryArg(b.path("data/"));
compiler.addFileInput(b.path(b.fmt("data/{s}.gschema.xml", .{app_name})));
break :gschema out.path(b, glib_compiled_schema_name);
};
// An executable.
const exe = exe: {
const exe = b.addExecutable(.{
.name = app_name,
.root_module = b.createModule(.{
// This is a standard C application, so libc is required.
.link_libc = true,
.target = target,
.optimize = optimize,
}),
});
// Vala does not bundle system libraries (of course): we have to tell the
// linker.
for (system_libraries) |lib| {
exe.linkSystemLibrary(lib);
}
exe.root_module.linkLibrary(libsood);
exe.root_module.linkLibrary(libroon.lib);
exe.addCSourceFile(.{ .file = gresouce_c });
for (vala_main.compiled_c_files) |file| {
exe.addCSourceFile(.{ .file = file });
}
break :exe exe;
};
const install_compiled_gschema = b.addInstallFile(
gschema_compiled,
b.pathJoin(&.{ glib_schemas_dir, glib_compiled_schema_name }),
);
// 256x256 PNG icon (required for `.DirIcon`, icon file specific for AppImage)
const icon_png256 = icon_png256: {
const rsvg_convert = b.addSystemCommand(&.{"rsvg-convert"});
rsvg_convert.addArgs(&.{ "--width=256", "--height=256" });
rsvg_convert.addArg("--output");
const output = rsvg_convert.addOutputFileArg(b.fmt("{s}.png", .{app_name}));
// Input filename must be the last argument.
rsvg_convert.addFileArg(b.path("data/app-icon.svg"));
break :icon_png256 output;
};
// Default install step
{
const step = b.getInstallStep();
// Application binary
b.installArtifact(exe);
// GLib schema file
b.installFile(
b.fmt("data/{s}.gschema.xml", .{app_name}),
b.pathJoin(&.{ glib_schemas_dir, b.fmt("{s}.gschema.xml", .{app_name}) }),
);
// GLib schema file (compiled)
if (compile_gschema) {
step.dependOn(&install_compiled_gschema.step);
}
// Desktop entry
b.installFile(
"data/plac.desktop",
b.pathJoin(&.{ "share/applications", b.fmt("{s}.desktop", .{app_name}) }),
);
// Icons
b.installFile(
"data/app-icon.svg",
b.pathJoin(&.{ "share/icons/hicolor/16x16/apps", b.fmt("{s}.svg", .{app_name}) }),
);
step.dependOn(&b.addInstallFile(
icon_png256,
b.pathJoin(&.{ "share/icons/hicolor/256x256/apps", b.fmt("{s}.png", .{app_name}) }),
).step);
}
// `zig build run`
{
const run = b.addRunArtifact(exe);
run.step.dependOn(&install_compiled_gschema.step);
run.setEnvironmentVariable("GSETTINGS_SCHEMA_DIR", b.pathJoin(&.{ b.install_path, glib_schemas_dir }));
const step = b.step("run", "Build and run Plac GTK-Adwaita app");
step.dependOn(&run.step);
}
// `zig build moo-test`
const moo_test = moo_test: {
var vala = try CompileVala.init(b, .{
.src = b.path("src/Moo"),
.includeTestFiles = true,
});
vala.addPackage("glib-2.0");
vala.addPackage("gee-0.8");
const test_exe = b.addExecutable(.{
.name = "moo_test",
.root_module = b.createModule(.{
.link_libc = true,
.target = target,
.optimize = optimize,
}),
});
test_exe.linkSystemLibrary("gee-0.8");
test_exe.linkSystemLibrary("glib-2.0");
test_exe.linkSystemLibrary("gobject-2.0");
for (vala.compiled_c_files) |file| {
test_exe.root_module.addCSourceFile(.{ .file = file });
}
const run = b.addRunArtifact(test_exe);
const step = b.step("moo-test", "Test MOO message parsing");
step.dependOn(&run.step);
break :moo_test run;
};
// `zig build test`
{
const step = b.step("test", "Run unit tests");
step.dependOn(&moo_test.step);
}
}