-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbuild.zig
154 lines (129 loc) · 5.7 KB
/
build.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
const std = @import("std");
pub fn addExecutable(b: *std.Build, options: BuildStep.Options) *BuildStep {
return BuildStep.create(b, options);
}
pub fn build(b: *std.Build) void {
_ = b;
}
/// Runs `go build` with relevant flags
pub const BuildStep = struct {
step: std.Build.Step,
generated_bin: ?*std.Build.GeneratedFile,
opts: Options,
pub const Options = struct {
name: []const u8,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
package_path: std.Build.LazyPath,
cgo_enabled: bool = true,
};
/// Create a GoBuildStep
pub fn create(b: *std.Build, options: Options) *BuildStep {
const self = b.allocator.create(BuildStep) catch unreachable;
self.* = .{
.opts = options,
.generated_bin = null,
.step = std.Build.Step.init(.{
.id = .custom,
.name = "go build",
.owner = b,
.makeFn = BuildStep.make,
}),
};
return self;
}
pub fn make(step: *std.Build.Step, progress: std.Progress.Node) !void {
const self: *BuildStep = @fieldParentPtr("step", step);
const b = step.owner;
var go_args = std.ArrayList([]const u8).init(b.allocator);
defer go_args.deinit();
try go_args.append("go");
try go_args.append("build");
const output_file = try b.cache_root.join(b.allocator, &.{ "go", self.opts.name });
try go_args.appendSlice(&.{ "-o", output_file });
switch (self.opts.optimize) {
.ReleaseSafe => try go_args.appendSlice(&.{ "-tags", "ReleaseSafe" }),
.ReleaseFast => try go_args.appendSlice(&.{ "-tags", "ReleaseFast" }),
.ReleaseSmall => try go_args.appendSlice(&.{ "-tags", "ReleaseFast" }),
.Debug => try go_args.appendSlice(&.{ "-tags", "Debug" }),
}
var env = try std.process.getEnvMap(b.allocator);
// CGO
if (self.opts.cgo_enabled) {
try env.put("CGO_ENABLED", "1");
// Set zig as the CGO compiler
const target = self.opts.target;
const cc = b.fmt(
"zig cc -target {s}-{s}-{s}",
.{ @tagName(target.result.cpu.arch), @tagName(target.result.os.tag), @tagName(target.result.abi) },
);
try env.put("CC", cc);
const cxx = b.fmt(
"zig c++ -target {s}-{s}-{s}",
.{ @tagName(target.result.cpu.arch), @tagName(target.result.os.tag), @tagName(target.result.abi) },
);
try env.put("CXX", cxx);
try env.put("GOOS", @tagName(target.result.os.tag));
// Tell the linker we are statically linking
go_args.appendSlice(&.{ "--ldflags", "-linkmode=external -extldflags=-static" }) catch @panic("OOM");
} else {
try env.put("CGO_ENABLED", "0");
}
// Output file always needs to be added last
try go_args.append(self.opts.package_path.getPath(b));
const cmd = std.mem.join(b.allocator, " ", go_args.items) catch @panic("OOM");
const node = progress.start(cmd, 1);
defer node.end();
// run the command
try self.evalChildProcess(go_args.items, &env);
if (self.generated_bin == null) {
const generated_bin = b.allocator.create(std.Build.GeneratedFile) catch unreachable;
generated_bin.* = .{ .step = step };
self.generated_bin = generated_bin;
}
self.generated_bin.?.path = output_file;
}
/// Return the LazyPath of the generated binary
pub fn getEmittedBin(self: *BuildStep) std.Build.LazyPath {
if (self.generated_bin) |generated_bin|
return .{ .generated = .{ .file = generated_bin } };
const b = self.step.owner;
const generated_bin = b.allocator.create(std.Build.GeneratedFile) catch unreachable;
generated_bin.* = .{ .step = &self.step };
self.generated_bin = generated_bin;
return .{ .generated = .{ .file = generated_bin } };
}
/// Add a run step which depends on the GoBuildStep
pub fn addRunStep(self: *BuildStep) *std.Build.Step.Run {
const b = self.step.owner;
const run_step = std.Build.Step.Run.create(b, b.fmt("run {s}", .{self.opts.name}));
run_step.step.dependOn(&self.step);
const bin_file = self.getEmittedBin();
const arg: std.Build.Step.Run.PrefixedLazyPath = .{ .prefix = "", .lazy_path = bin_file };
run_step.argv.append(b.allocator, .{ .lazy_path = arg }) catch unreachable;
return run_step;
}
// Add an install step which depends on the GoBuildStep
pub fn addInstallStep(self: *BuildStep) void {
const b = self.step.owner;
const bin_file = self.getEmittedBin();
const install_step = b.addInstallBinFile(bin_file, self.opts.name);
install_step.step.dependOn(&self.step);
b.getInstallStep().dependOn(&install_step.step);
}
fn evalChildProcess(self: *BuildStep, argv: []const []const u8, env: *const std.process.EnvMap) !void {
const s = &self.step;
const arena = s.owner.allocator;
try std.Build.Step.handleChildProcUnsupported(s, null, argv);
try std.Build.Step.handleVerbose(s.owner, null, argv);
const result = std.process.Child.run(.{
.allocator = arena,
.argv = argv,
.env_map = env,
}) catch |err| return s.fail("unable to spawn {s}: {s}", .{ argv[0], @errorName(err) });
if (result.stderr.len > 0) {
try s.result_error_msgs.append(arena, result.stderr);
}
try std.Build.Step.handleChildProcessTerm(s, result.term, null, argv);
}
};