zig-leapc-examples/build.zig
2024-05-12 09:08:18 +01:00

176 lines
6 KiB
Zig

const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const leapc_header = switch (target.result.os.tag) {
std.Target.Os.Tag.windows => "C:/Program Files/Ultraleap/LeapSDK/include/LeapC.h",
std.Target.Os.Tag.linux => "/usr/include/LeapC.h",
else => "",
};
const leapc_include = switch (target.result.os.tag) {
std.Target.Os.Tag.windows => "C:/Program Files/Ultraleap/LeapSDK/include",
std.Target.Os.Tag.linux => "/usr/include",
else => "",
};
const leapc_lib_path = switch (target.result.os.tag) {
std.Target.Os.Tag.windows => "C:/Program Files/Ultraleap/LeapSDK/lib/x64",
std.Target.Os.Tag.linux => "/usr/lib/ultraleap-hand-tracking-service",
else => "",
};
const binding = generate_binding(b, leapc_header, target, optimize, &[_][]const u8{leapc_include});
const exe = b.addExecutable(.{
.name = "leapc_polling",
.root_source_file = .{ .path = "src/leapc_polling.zig" },
.target = target,
.optimize = optimize,
.link_libc = true,
});
switch (target.result.os.tag) {
std.Target.Os.Tag.windows => {
exe.addLibraryPath(.{ .path = leapc_lib_path });
exe.addIncludePath(.{ .path = leapc_include });
},
std.Target.Os.Tag.linux => {
exe.addLibraryPath(.{ .path = leapc_lib_path });
},
else => {},
}
exe.linkSystemLibrary("LeapC");
exe.step.dependOn(&binding.write_step.step);
b.installArtifact(exe);
const module = b.addModule("leapc", .{
.root_source_file = b.path("src/leapc/leapc.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
module.addLibraryPath(.{ .path = leapc_lib_path });
module.linkSystemLibrary("LeapC", .{ .needed = true });
}
fn generate_binding(b: *std.Build, header_path: []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.Mode, includes: []const []const u8) *WriteGeneratedContent {
// Translate C step
const translate_c = b.addTranslateC(.{ .root_source_file = .{ .cwd_relative = header_path }, .target = target, .optimize = optimize });
for (includes) |include| {
translate_c.addIncludeDir(include);
}
const read_file = ReadTranslatedCStep.readFile(b, translate_c);
read_file.step.dependOn(&translate_c.step);
const write_file = WriteGeneratedContent.add(b, read_file.file_content);
// Set dependencies on other steps
write_file.step.dependOn(&read_file.step);
write_file.write_step.step.dependOn(&write_file.step);
return write_file;
}
const ReadTranslatedCStep = struct {
step: std.Build.Step,
file_content: *GeneratedContent,
translate_step: *std.Build.Step.TranslateC,
fn readFile(b: *std.Build, translate_step: *std.Build.Step.TranslateC) *ReadTranslatedCStep {
const result = b.allocator.create(ReadTranslatedCStep) catch unreachable;
result.* = .{
.step = std.Build.Step.init(.{
.id = .custom,
.name = "read translated c",
.owner = b,
.makeFn = ReadTranslatedCStep.make,
}),
.file_content = b.allocator.create(GeneratedContent) catch unreachable,
.translate_step = translate_step,
};
return result;
}
fn make(step: *std.Build.Step, _: *std.Progress.Node) anyerror!void {
const self: *ReadTranslatedCStep = @fieldParentPtr("step", step);
// Read temporary header
var file = try std.fs.cwd().openFile(self.translate_step.output_file.path.?, .{});
defer file.close();
// From there we have our file content
self.file_content.content = try file.reader().readAllAlloc(self.step.owner.allocator, 1000000);
}
};
const GeneratedContent = struct {
content: ?[]const u8 = null,
};
const WriteGeneratedContent = struct {
step: std.Build.Step,
content: *GeneratedContent,
write_step: *std.Build.Step.WriteFile,
fn add(b: *std.Build, content: *GeneratedContent) *WriteGeneratedContent {
const result = b.allocator.create(WriteGeneratedContent) catch unreachable;
result.* = .{
.step = std.Build.Step.init(.{
.id = .custom,
.name = "write generated content",
.owner = b,
.makeFn = WriteGeneratedContent.make,
}),
.content = content,
.write_step = b.addWriteFiles(),
};
return result;
}
fn make(step: *std.Build.Step, _: *std.Progress.Node) anyerror!void {
const self: *WriteGeneratedContent = @fieldParentPtr("step", step);
const first_modif = try std.mem.replaceOwned(
u8,
self.step.owner.allocator,
self.content.content.?,
"visible_time: u64 =",
"visible_time: u64 align(1) =",
);
defer self.step.owner.allocator.free(first_modif);
const second_modif = try std.mem.replaceOwned(
u8,
self.step.owner.allocator,
first_modif,
"pHands: [*c]LEAP_HAND =",
"pHands: [*c]LEAP_HAND align(1) =",
);
defer self.step.owner.allocator.free(second_modif);
const third_modif = try std.mem.replaceOwned(
u8,
self.step.owner.allocator,
second_modif,
"properties: LEAP_IMAGE_PROPERTIES =",
"properties: LEAP_IMAGE_PROPERTIES align(1) =",
);
// Deferring free here makes the final file garbage?
// Probably because the write_step is actually executed after
// the function is closed, so defer is called and the memory freed
// Can I just let the allocator take care of that when the build is over?
// defer self.step.owner.allocator.free(third_modif);
self.write_step.addBytesToSource(third_modif, "src/leapc/leapc.zig");
self.write_step.step.name = "writing leapc.zig";
}
};