Skip to content

Commit 4483f2a

Browse files
hyperpolymathclaude
andcommitted
fix: update callconv(.C) to callconv(.c) for Zig 0.14+ compatibility
Zig 0.14 deprecated uppercase .C in favour of lowercase .c for the C calling convention enum. Updates all 9 FFI source files and the build configuration to use the new form. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 898af2b commit 4483f2a

9 files changed

Lines changed: 88 additions & 92 deletions

File tree

src/interface/ffi/build.zig

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,59 +16,49 @@ pub fn build(b: *std.Build) void {
1616
const target = b.standardTargetOptions(.{});
1717
const optimize = b.standardOptimizeOption(.{});
1818

19-
// ---------------------------------------------------------------
20-
// Source files comprising the gsa module
21-
// ---------------------------------------------------------------
22-
const src_files: []const []const u8 = &.{
23-
"src/main.zig",
24-
"src/probe.zig",
25-
"src/config_extract.zig",
26-
"src/a2ml_emit.zig",
27-
"src/verisimdb_client.zig",
28-
"src/server_actions.zig",
29-
"src/game_profiles.zig",
30-
};
31-
3219
// ---------------------------------------------------------------
3320
// Shared library — libgsa.so / libgsa.dylib / gsa.dll
3421
// ---------------------------------------------------------------
35-
const lib = b.addSharedLibrary(.{
22+
const lib = b.addLibrary(.{
3623
.name = "gsa",
37-
.root_source_file = b.path("src/main.zig"),
38-
.target = target,
39-
.optimize = optimize,
24+
.linkage = .dynamic,
25+
.root_module = b.createModule(.{
26+
.root_source_file = b.path("src/main.zig"),
27+
.target = target,
28+
.optimize = optimize,
29+
.link_libc = true, // needed for socket operations and posix APIs
30+
}),
31+
.version = .{ .major = 0, .minor = 1, .patch = 0 },
4032
});
41-
lib.version = .{ .major = 0, .minor = 1, .patch = 0 };
42-
lib.linkLibC(); // needed for socket operations and posix APIs
43-
44-
// Register extra source files so all modules are compiled into the library
45-
for (src_files[1..]) |extra| {
46-
_ = extra;
47-
}
4833

4934
b.installArtifact(lib);
5035

5136
// ---------------------------------------------------------------
5237
// Static library — libgsa.a
5338
// ---------------------------------------------------------------
54-
const lib_static = b.addStaticLibrary(.{
39+
const lib_static = b.addLibrary(.{
5540
.name = "gsa",
56-
.root_source_file = b.path("src/main.zig"),
57-
.target = target,
58-
.optimize = optimize,
41+
.linkage = .static,
42+
.root_module = b.createModule(.{
43+
.root_source_file = b.path("src/main.zig"),
44+
.target = target,
45+
.optimize = optimize,
46+
.link_libc = true,
47+
}),
5948
});
60-
lib_static.linkLibC();
6149
b.installArtifact(lib_static);
6250

6351
// ---------------------------------------------------------------
6452
// Unit tests (compile every module individually)
6553
// ---------------------------------------------------------------
6654
const unit_tests = b.addTest(.{
67-
.root_source_file = b.path("src/main.zig"),
68-
.target = target,
69-
.optimize = optimize,
55+
.root_module = b.createModule(.{
56+
.root_source_file = b.path("src/main.zig"),
57+
.target = target,
58+
.optimize = optimize,
59+
.link_libc = true,
60+
}),
7061
});
71-
unit_tests.linkLibC();
7262

7363
const run_unit_tests = b.addRunArtifact(unit_tests);
7464
const test_step = b.step("test", "Run unit tests for all FFI modules");
@@ -78,11 +68,13 @@ pub fn build(b: *std.Build) void {
7868
// Integration tests
7969
// ---------------------------------------------------------------
8070
const integration_tests = b.addTest(.{
81-
.root_source_file = b.path("test/integration_test.zig"),
82-
.target = target,
83-
.optimize = optimize,
71+
.root_module = b.createModule(.{
72+
.root_source_file = b.path("test/integration_test.zig"),
73+
.target = target,
74+
.optimize = optimize,
75+
.link_libc = true,
76+
}),
8477
});
85-
integration_tests.linkLibC();
8678

8779
const run_integration_tests = b.addRunArtifact(integration_tests);
8880
const integration_step = b.step("test-integration", "Run FFI integration tests");
@@ -100,14 +92,17 @@ pub fn build(b: *std.Build) void {
10092
.arch_os_abi = entry[0],
10193
}) catch unreachable;
10294

103-
const cross_lib = b.addSharedLibrary(.{
95+
const cross_lib = b.addLibrary(.{
10496
.name = "gsa",
105-
.root_source_file = b.path("src/main.zig"),
106-
.target = b.resolveTargetQuery(cross_target),
107-
.optimize = optimize,
97+
.linkage = .dynamic,
98+
.root_module = b.createModule(.{
99+
.root_source_file = b.path("src/main.zig"),
100+
.target = b.resolveTargetQuery(cross_target),
101+
.optimize = optimize,
102+
.link_libc = true,
103+
}),
104+
.version = .{ .major = 0, .minor = 1, .patch = 0 },
108105
});
109-
cross_lib.linkLibC();
110-
cross_lib.version = .{ .major = 0, .minor = 1, .patch = 0 };
111106

112107
const install_cross = b.addInstallArtifact(cross_lib, .{});
113108
const cross_step = b.step(entry[0], entry[1]);

src/interface/ffi/src/a2ml_emit.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub fn emitA2ML(
5858
config: *const config_extract.ParsedConfig,
5959
profile: *const game_profiles.GameProfile,
6060
) ![]const u8 {
61-
var buf = std.ArrayList(u8).init(allocator);
61+
var buf = std.array_list.AlignedManaged(u8, null).init(allocator);
6262
errdefer buf.deinit();
6363
const writer = buf.writer();
6464

@@ -254,7 +254,7 @@ pub fn diffConfigs(
254254
old: *const config_extract.ParsedConfig,
255255
new: *const config_extract.ParsedConfig,
256256
) ![]ConfigDiff {
257-
var diffs = std.ArrayList(ConfigDiff).init(allocator);
257+
var diffs = std.array_list.AlignedManaged(ConfigDiff, null).init(allocator);
258258
errdefer diffs.deinit();
259259

260260
// Find modified and removed fields
@@ -314,7 +314,7 @@ pub fn applyDiff(
314314
format: config_extract.ConfigFormat,
315315
diffs: []const ConfigDiff,
316316
) ![]const u8 {
317-
var result = std.ArrayList(u8).init(allocator);
317+
var result = std.array_list.AlignedManaged(u8, null).init(allocator);
318318
errdefer result.deinit();
319319
const writer = result.writer();
320320

@@ -460,7 +460,7 @@ threadlocal var emit_result_buf: [16384]u8 = undefined;
460460
/// Convert a JSON config representation to A2ML.
461461
export fn gossamer_gsa_a2ml_emit(
462462
config_json: [*:0]const u8,
463-
) callconv(.C) [*:0]const u8 {
463+
) callconv(.c) [*:0]const u8 {
464464
const allocator = std.heap.c_allocator;
465465
const json_str = std.mem.span(config_json);
466466

@@ -491,7 +491,7 @@ threadlocal var parse_result_buf: [16384]u8 = undefined;
491491
/// Parse A2ML back to a JSON representation.
492492
export fn gossamer_gsa_a2ml_parse(
493493
a2ml_ptr: [*:0]const u8,
494-
) callconv(.C) [*:0]const u8 {
494+
) callconv(.c) [*:0]const u8 {
495495
const allocator = std.heap.c_allocator;
496496
const a2ml_str = std.mem.span(a2ml_ptr);
497497

@@ -502,7 +502,7 @@ export fn gossamer_gsa_a2ml_parse(
502502
defer config.deinit();
503503

504504
// Convert to JSON
505-
var json_buf = std.ArrayList(u8).init(allocator);
505+
var json_buf = std.array_list.AlignedManaged(u8, null).init(allocator);
506506
defer json_buf.deinit();
507507
const writer = json_buf.writer();
508508

src/interface/ffi/src/config_extract.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ pub const ConfigField = struct {
4646
pub const ParsedConfig = struct {
4747
format: ConfigFormat,
4848
path: []const u8,
49-
fields: std.ArrayList(ConfigField),
49+
fields: std.array_list.AlignedManaged(ConfigField, null),
5050
raw_text: []const u8,
5151
allocator: Allocator,
5252

5353
pub fn init(allocator: Allocator, format: ConfigFormat, path: []const u8) ParsedConfig {
5454
return .{
5555
.format = format,
5656
.path = path,
57-
.fields = std.ArrayList(ConfigField).init(allocator),
57+
.fields = std.array_list.AlignedManaged(ConfigField, null).init(allocator),
5858
.raw_text = "",
5959
.allocator = allocator,
6060
};
@@ -860,7 +860,7 @@ threadlocal var extract_result_buf: [16384]u8 = undefined;
860860
export fn gossamer_gsa_extract_config(
861861
handle: c_int,
862862
profile_id: [*:0]const u8,
863-
) callconv(.C) [*:0]const u8 {
863+
) callconv(.c) [*:0]const u8 {
864864
_ = handle;
865865
const gsa = main.getGlobalHandle() orelse {
866866
main.setErrorStr("not initialized");

src/interface/ffi/src/game_profiles.zig

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ pub const GameProfile = struct {
4141
id: []const u8,
4242
name: []const u8,
4343
engine: []const u8,
44-
ports: std.ArrayList(Port),
44+
ports: std.array_list.AlignedManaged(Port, null),
4545
protocol: []const u8,
4646
fingerprint_pattern: []const u8,
4747
config_format: []const u8,
4848
config_path: []const u8,
49-
field_defs: std.ArrayList(FieldDef),
49+
field_defs: std.array_list.AlignedManaged(FieldDef, null),
5050
actions: std.StringHashMap([]const u8),
5151
allocator: Allocator,
5252

@@ -56,12 +56,12 @@ pub const GameProfile = struct {
5656
.id = "",
5757
.name = "",
5858
.engine = "",
59-
.ports = std.ArrayList(Port).init(std.heap.c_allocator),
59+
.ports = std.array_list.AlignedManaged(Port, null).init(std.heap.c_allocator),
6060
.protocol = "",
6161
.fingerprint_pattern = "",
6262
.config_format = "",
6363
.config_path = "",
64-
.field_defs = std.ArrayList(FieldDef).init(std.heap.c_allocator),
64+
.field_defs = std.array_list.AlignedManaged(FieldDef, null).init(std.heap.c_allocator),
6565
.actions = std.StringHashMap([]const u8).init(std.heap.c_allocator),
6666
.allocator = std.heap.c_allocator,
6767
};
@@ -213,7 +213,7 @@ pub const ProfileRegistry = struct {
213213

214214
/// Return a JSON array summarising all loaded profiles.
215215
pub fn listProfiles(self: *ProfileRegistry, allocator: Allocator) ![]const u8 {
216-
var buf = std.ArrayList(u8).init(allocator);
216+
var buf = std.array_list.AlignedManaged(u8, null).init(allocator);
217217
errdefer buf.deinit();
218218
const writer = buf.writer();
219219

@@ -252,12 +252,12 @@ pub fn parseA2MLProfile(data: []const u8, allocator: Allocator) !GameProfile {
252252
.id = try allocator.dupe(u8, ""),
253253
.name = try allocator.dupe(u8, ""),
254254
.engine = try allocator.dupe(u8, ""),
255-
.ports = std.ArrayList(Port).init(allocator),
255+
.ports = std.array_list.AlignedManaged(Port, null).init(allocator),
256256
.protocol = try allocator.dupe(u8, ""),
257257
.fingerprint_pattern = try allocator.dupe(u8, ""),
258258
.config_format = try allocator.dupe(u8, ""),
259259
.config_path = try allocator.dupe(u8, ""),
260-
.field_defs = std.ArrayList(FieldDef).init(allocator),
260+
.field_defs = std.array_list.AlignedManaged(FieldDef, null).init(allocator),
261261
.actions = std.StringHashMap([]const u8).init(allocator),
262262
.allocator = allocator,
263263
};
@@ -367,7 +367,7 @@ pub fn parseA2MLProfile(data: []const u8, allocator: Allocator) !GameProfile {
367367
if (std.mem.indexOfPos(u8, field_body, opt_start, ")")) |opt_end| {
368368
const opt_content = field_body[opt_start + 9 .. opt_end];
369369
// Count quoted strings
370-
var enum_list = std.ArrayList([]const u8).init(allocator);
370+
var enum_list = std.array_list.AlignedManaged([]const u8, null).init(allocator);
371371
var opt_pos: usize = 0;
372372
while (opt_pos < opt_content.len) {
373373
if (opt_content[opt_pos] == '"') {
@@ -459,7 +459,7 @@ fn extractAttrFrom(attrs: []const u8, name: []const u8) ?[]const u8 {
459459
/// Returns the number of profiles loaded, or a negative error code.
460460
export fn gossamer_gsa_load_profiles(
461461
dir: [*:0]const u8,
462-
) callconv(.C) c_int {
462+
) callconv(.c) c_int {
463463
const gsa = main.getGlobalHandle() orelse {
464464
main.setErrorStr("not initialized");
465465
return @intFromEnum(main.GsaResult.not_initialized);
@@ -480,7 +480,7 @@ export fn gossamer_gsa_load_profiles(
480480
/// Returns a NUL-terminated JSON string.
481481
threadlocal var list_profiles_buf: [16384]u8 = undefined;
482482

483-
export fn gossamer_gsa_list_profiles() callconv(.C) [*:0]const u8 {
483+
export fn gossamer_gsa_list_profiles() callconv(.c) [*:0]const u8 {
484484
const gsa = main.getGlobalHandle() orelse {
485485
main.setErrorStr("not initialized");
486486
return @as([*:0]const u8, @ptrCast(&[_:0]u8{ '[', ']' }));
@@ -504,7 +504,7 @@ export fn gossamer_gsa_list_profiles() callconv(.C) [*:0]const u8 {
504504
/// Returns 0 on success, negative error code on failure.
505505
export fn gossamer_gsa_add_profile(
506506
a2ml: [*:0]const u8,
507-
) callconv(.C) c_int {
507+
) callconv(.c) c_int {
508508
const gsa = main.getGlobalHandle() orelse {
509509
main.setErrorStr("not initialized");
510510
return @intFromEnum(main.GsaResult.not_initialized);
@@ -557,7 +557,7 @@ test "parse minimal A2ML profile" {
557557
\\ @end
558558
\\ @end
559559
\\ @ports:
560-
\\ @port(name="game", number=27015, protocol="UDP"):@end
560+
\\ @port(name="game", number="27015", protocol="UDP"):@end
561561
\\ @end
562562
\\@end
563563
;
@@ -589,11 +589,9 @@ test "ProfileRegistry init and deinit" {
589589
}
590590

591591
test "GameProfile.empty" {
592-
var p = GameProfile.empty();
592+
const p = GameProfile.empty();
593593
try std.testing.expectEqualStrings("", p.id);
594594
try std.testing.expectEqual(@as(usize, 0), p.ports.items.len);
595-
// empty() uses c_allocator so no deinit needed for test
596-
_ = p;
597595
}
598596

599597
test "extractAttrFrom" {

src/interface/ffi/src/groove_client.zig

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ pub const AlertSeverity = enum(u8) {
5959
pub const TargetStatus = enum(u8) {
6060
unknown = 0,
6161
reachable = 1,
62-
unreachable = 2,
63-
error = 3,
62+
not_reachable = 2,
63+
@"error" = 3,
6464
};
6565

6666
/// A known Groove target (Burble, Vext, etc.).
@@ -249,7 +249,7 @@ fn probeTarget(target: *GrooveTarget) void {
249249
const host = target.hostSlice();
250250

251251
const response = grooveGet(allocator, host, target.port, GROOVE_DISCOVERY_PATH) catch {
252-
target.status = .unreachable;
252+
target.status = .not_reachable;
253253
target.last_probe_ms = std.time.milliTimestamp();
254254
return;
255255
};
@@ -354,7 +354,7 @@ fn sendTTSAlert(
354354
///
355355
/// Returns 0 on success (at least one target reachable), or a GsaResult
356356
/// error code if no targets are reachable.
357-
export fn gossamer_gsa_groove_discover() callconv(.C) c_int {
357+
export fn gossamer_gsa_groove_discover() callconv(.c) c_int {
358358
_ = main.getGlobalHandle() orelse {
359359
main.setErrorStr("not initialized");
360360
return @intFromEnum(main.GsaResult.not_initialized);
@@ -395,7 +395,7 @@ threadlocal var groove_status_buf: [1024]u8 = undefined;
395395

396396
export fn gossamer_gsa_groove_status(
397397
target_name: [*:0]const u8,
398-
) callconv(.C) [*:0]const u8 {
398+
) callconv(.c) [*:0]const u8 {
399399
const name = std.mem.span(target_name);
400400

401401
const target = findTarget(name) orelse {
@@ -412,8 +412,8 @@ export fn gossamer_gsa_groove_status(
412412
const status_str: []const u8 = switch (target.status) {
413413
.unknown => "unknown",
414414
.reachable => "reachable",
415-
.unreachable => "unreachable",
416-
.error => "error",
415+
.not_reachable => "unreachable",
416+
.@"error" => "error",
417417
};
418418

419419
var stream = std.io.fixedBufferStream(&groove_status_buf);
@@ -445,7 +445,7 @@ export fn gossamer_gsa_groove_alert(
445445
severity: c_int,
446446
server_id: [*:0]const u8,
447447
message: [*:0]const u8,
448-
) callconv(.C) c_int {
448+
) callconv(.c) c_int {
449449
_ = main.getGlobalHandle() orelse {
450450
main.setErrorStr("not initialized");
451451
return @intFromEnum(main.GsaResult.not_initialized);
@@ -496,7 +496,7 @@ export fn gossamer_gsa_groove_alert(
496496
/// Returns 0 on success, negative GsaResult on failure.
497497
export fn gossamer_gsa_groove_tts_alert(
498498
text: [*:0]const u8,
499-
) callconv(.C) c_int {
499+
) callconv(.c) c_int {
500500
_ = main.getGlobalHandle() orelse {
501501
main.setErrorStr("not initialized");
502502
return @intFromEnum(main.GsaResult.not_initialized);

0 commit comments

Comments
 (0)