zig/lib/std/build/TranslateCStep.zig
rohlem fbc06f9c91 std.build.TranslateCStep: add C macro support
The string construction code is moved out of std.build.LibExeObjStep
into std.build.constructCMacroArg, to allow reusing it elsewhere.
2022-02-05 03:17:07 -05:00

113 lines
4.0 KiB
Zig

const std = @import("../std.zig");
const build = std.build;
const Step = build.Step;
const Builder = build.Builder;
const LibExeObjStep = build.LibExeObjStep;
const CheckFileStep = build.CheckFileStep;
const fs = std.fs;
const mem = std.mem;
const CrossTarget = std.zig.CrossTarget;
const TranslateCStep = @This();
pub const base_id = .translate_c;
step: Step,
builder: *Builder,
source: build.FileSource,
include_dirs: std.ArrayList([]const u8),
c_macros: std.ArrayList([]const u8),
output_dir: ?[]const u8,
out_basename: []const u8,
target: CrossTarget = CrossTarget{},
output_file: build.GeneratedFile,
pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
const self = builder.allocator.create(TranslateCStep) catch unreachable;
self.* = TranslateCStep{
.step = Step.init(.translate_c, "translate-c", builder.allocator, make),
.builder = builder,
.source = source,
.include_dirs = std.ArrayList([]const u8).init(builder.allocator),
.c_macros = std.ArrayList([]const u8).init(builder.allocator),
.output_dir = null,
.out_basename = undefined,
.output_file = build.GeneratedFile{ .step = &self.step },
};
source.addStepDependencies(&self.step);
return self;
}
pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
self.target = target;
}
/// Creates a step to build an executable from the translated source.
pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep {
return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file });
}
pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void {
self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable;
}
pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep {
return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches));
}
/// If the value is omitted, it is set to 1.
/// `name` and `value` need not live longer than the function call.
pub fn defineCMacro(self: *TranslateCStep, name: []const u8, value: ?[]const u8) void {
const macro = build.constructCMacro(self.builder.allocator, name, value);
self.c_macros.append(macro) catch unreachable;
}
/// name_and_value looks like [name]=[value]. If the value is omitted, it is set to 1.
pub fn defineCMacroRaw(self: *TranslateCStep, name_and_value: []const u8) void {
self.c_macros.append(self.builder.dupe(name_and_value)) catch unreachable;
}
fn make(step: *Step) !void {
const self = @fieldParentPtr(TranslateCStep, "step", step);
var argv_list = std.ArrayList([]const u8).init(self.builder.allocator);
try argv_list.append(self.builder.zig_exe);
try argv_list.append("translate-c");
try argv_list.append("-lc");
try argv_list.append("--enable-cache");
if (!self.target.isNative()) {
try argv_list.append("-target");
try argv_list.append(try self.target.zigTriple(self.builder.allocator));
}
for (self.include_dirs.items) |include_dir| {
try argv_list.append("-I");
try argv_list.append(include_dir);
}
for (self.c_macros.items) |c_macro| {
try argv_list.append("-D");
try argv_list.append(c_macro);
}
try argv_list.append(self.source.getPath(self.builder));
const output_path_nl = try self.builder.execFromStep(argv_list.items, &self.step);
const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
self.out_basename = fs.path.basename(output_path);
if (self.output_dir) |output_dir| {
const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename });
try self.builder.updateFile(output_path, full_dest);
} else {
self.output_dir = fs.path.dirname(output_path).?;
}
self.output_file.path = fs.path.join(
self.builder.allocator,
&[_][]const u8{ self.output_dir.?, self.out_basename },
) catch unreachable;
}