176 lines
6 KiB
Zig
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";
|
|
}
|
|
};
|