-
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
// Copyright 2025 Shota FUJI
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//
// SPDX-License-Identifier: MPL-2.0
const CompileVala = @This();
const std = @import("std");
step: *std.Build.Step,
compiled_c_directory: std.Build.LazyPath,
compiled_c_files: []std.Build.LazyPath,
valac: *std.Build.Step.Run,
pub const Options = struct {
/// This must be an existing path.
src: std.Build.LazyPath,
includeTestFiles: bool = false,
suppressDeprecationWarning: bool = false,
};
pub fn init(b: *std.Build, opts: Options) !CompileVala {
const valac = b.addSystemCommand(&.{"valac"});
// Vala source codes to compile.
const vala_sources: [][]const u8 = vala_sources: {
var list: std.ArrayList([]const u8) = .empty;
var dir = try opts.src.getPath3(b, &valac.step).openDir("", .{ .iterate = true });
defer dir.close();
var walker = try dir.walk(b.allocator);
defer walker.deinit();
while (try walker.next()) |entry| {
const ext = std.fs.path.extension(entry.basename);
if (std.mem.eql(u8, ".vala", ext)) {
if (!opts.includeTestFiles and std.mem.endsWith(u8, entry.basename, ".test.vala")) {
continue;
}
try list.append(b.allocator, b.dupe(entry.path));
}
}
break :vala_sources try list.toOwnedSlice(b.allocator);
};
// Tell Vala compiler to emit C rather than compile using system C compiler.
valac.addArg("--ccode");
if (opts.suppressDeprecationWarning) {
valac.addArg("--enable-deprecated");
}
// Tell Vala to emit C source files under the output directory.
// The directory usually is Zig cache directory (like ".zig-cache/o/xxx").
// For example, when there is "src/Foo.vala", this step produces
// ".zig-cache/o/hash-or-something-idk/vala/Foo.c"
valac.addArg("--directory");
const dir = valac.addOutputDirectoryArg("vala");
// Let valac emit C source code without prefixing using directory.
valac.addArg("--basedir");
valac.addDirectoryArg(opts.src);
// Vala compiler takes a list of Vala source files, then process them all.
for (vala_sources) |src| {
valac.addFileArg(try opts.src.join(b.allocator, src));
}
const t = b.addInstallDirectory(.{
.source_dir = dir,
.install_dir = .{ .custom = "src" },
.install_subdir = "",
});
const compiled_c_files = try b.allocator.alloc(std.Build.LazyPath, vala_sources.len);
for (vala_sources, 0..) |src, i| {
// Looks fragile but it works. Even if it produced incorrect paths,
// filesystem and Zig compiler will tell us a file is missing.
const rel_path = b.fmt("{s}.c", .{src[0..(src.len - 5)]});
// src = "src/Foo.vala"
// rel_path = "Foo.c"
// file = "(step cache directory)/vala/Foo.c"
compiled_c_files[i] = try dir.join(b.allocator, rel_path);
}
return .{
.step = &t.step,
.compiled_c_directory = dir,
.compiled_c_files = compiled_c_files,
.valac = valac,
};
}
pub fn addPackage(self: *CompileVala, pkg: []const u8) void {
self.valac.addArg("--pkg");
self.valac.addArg(pkg);
}
pub fn addPackages(self: *CompileVala, pkgs: []const []const u8) void {
for (pkgs) |pkg| {
self.addPackage(pkg);
}
}
pub fn addVapi(self: *CompileVala, file: std.Build.LazyPath) void {
self.valac.addArg("--vapidir");
self.valac.addDirectoryArg(file.dirname());
self.valac.addFileInput(file);
}
pub fn addGResourceXML(self: *CompileVala, path: std.Build.LazyPath) void {
self.valac.addArg("--gresources");
self.valac.addFileArg(path);
}
pub fn getCompiledCDirectory(self: CompileVala) std.Build.LazyPath {
return self.compiled_c_directory;
}
pub fn getCompiledCFiles(self: CompileVala) []std.Build.LazyPath {
return self.compiled_c_files;
}