Changes
3 changed files (+173/-94)
-
-
@@ -22,6 +22,8 @@ //! https://ziglang.org/learn/build-system/const std = @import("std"); const CompileVala = @import("./build/CompileVala.zig"); const BuildError = error{ NonValaSourceInSourceListError, };
-
@@ -92,26 +94,6 @@break :zig_lib obj; }; // Vala source codes to compile. const vala_sources: [][]const u8 = vala_sources: { var list = std.ArrayList([]const u8).init(b.allocator); var dir = try std.fs.cwd().openDir("src", .{ .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)) { try list.append(b.dupe(entry.path)); } } break :vala_sources try list.toOwnedSlice(); }; // System libraries to link. const system_libraries = [_][]const u8{ "gtk4",
-
@@ -123,68 +105,42 @@ "gee-0.8","libsoup-3.0", }; // A directory containing C source files compiled from Vala source code. // If you use this LazyPath in your artifact, the artifact automatically depends on // this Vala to C complication step. You don't have to manually `a.dependOn()`. const vala_cdir = vala: { const valac = b.addSystemCommand(&.{"valac"}); 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, }); // Tell Vala compiler to emit C rather than compile using system C compiler. valac.addArg("--ccode"); // 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", }); // 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. valac.addArg("--enable-deprecated"); compile.addPackage("posix"); compile.addPackages(&.{ "plac", "libsood" }); // Vala compiler uses GResource XML to statically check attributes. valac.addArg("--gresources"); valac.addFileArg(b.path("data/gresource.xml")); compile.addGResourceXML(b.path("data/gresource.xml")); valac.addArg("--vapidir"); valac.addDirectoryArg(b.path("src/core")); valac.addArg("--vapidir"); valac.addDirectoryArg(b.path("src")); valac.addFileInput(b.path("src/libsood.vapi")); // Tell Vala what system libraries to use. Perhaps type checking things? for (system_libraries) |lib| { valac.addArgs(&.{ "--pkg", lib }); } valac.addArgs(&.{ "--pkg", "posix" }); valac.addArgs(&.{ "--pkg", "plac" }); valac.addArgs(&.{ "--pkg", "libsood" }); // 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/src/Foo.c" valac.addArg("--directory"); const dir = valac.addOutputDirectoryArg("vala"); // Let valac emit C source code without "src/" prefix. valac.addArg("--basedir"); valac.addDirectoryArg(b.path("src")); compile.addVapi(b.path("src/core/plac.vapi")); compile.addVapi(b.path("src/libsood.vapi")); // Vala compiler takes a list of Vala source files, then process them all. for (vala_sources) |src| { valac.addFileArg(b.path(b.pathJoin(&.{ "src", src }))); } const t = b.addInstallDirectory(.{ .source_dir = dir, .install_dir = .{ .custom = "src" }, .install_subdir = "", }); const step = b.step("valac", "Compile C source code from Vala files for debugging purpose"); step.dependOn(&t.step); step.dependOn(compile.step); break :vala dir; break :vala_main compile; }; const gresouce_c = gresource: {
-
@@ -244,25 +200,8 @@ exe.root_module.linkLibrary(libsood);exe.addCSourceFile(.{ .file = gresouce_c }); // At this point, build does not run yet—we can't enumerate C source // directory. Since we already have a list of Vala source code, we can // build a list of paths of to-be-generated C source file. for (vala_sources) |src| { // Basically unreachable. Don't put non Vala source into `vala_sources`. if (!std.mem.endsWith(u8, src, ".vala")) { return BuildError.NonValaSourceInSourceListError; } // 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 = "src/Foo.c" // file = "(step cache directory)/vala/src/Foo.c" exe.addCSourceFile(.{ .file = try vala_cdir.join(b.allocator, rel_path), }); for (vala_main.compiled_c_files) |file| { exe.addCSourceFile(.{ .file = file }); } break :exe exe;
-
-
build/CompileVala.zig (new)
-
@@ -0,0 +1,139 @@// 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 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).init(b.allocator); 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.dupe(entry.path)); } } break :vala_sources try list.toOwnedSlice(); }; // 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; }
-
-
-
@@ -40,6 +40,7 @@ root = ../.;fileset = unions [ ../src ../data ../build ../build.zig ../build.zig.zon ];
-