build.zig 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. const std = @import("std");
  2. const builtin = @import("builtin");
  3. const Builder = std.build.Builder;
  4. const Pkg = std.build.Pkg;
  5. const zigetbuild = @import("ziget-build-files-copy/build.zig");
  6. // TODO: use this if/when we get @tryImport
  7. //const SslBackend = if (zigetbuild) zigetbuild.SslBackend else enum {};
  8. const SslBackend = zigetbuild.SslBackend;
  9. fn unwrapOptionalBool(optionalBool: ?bool) bool {
  10. if (optionalBool) |b| return b;
  11. return false;
  12. }
  13. pub fn build(b: *Builder) !void {
  14. const ziget_repo = try (GitRepo {
  15. .url = "https://github.com/marler8997/ziget",
  16. .branch = null,
  17. .sha = @embedFile("zigetsha"),
  18. }).resolve(b.allocator);
  19. // TODO: implement this if/when we get @tryImport
  20. //if (zigetbuild) |_| { } else {
  21. // std.log.err("TODO: add zigetbuild package and recompile/reinvoke build.d", .{});
  22. // return;
  23. //}
  24. //var github_release_step = b.step("github-release", "Build the github-release binaries");
  25. // TODO: need to implement some interesting logic to make this work without
  26. // having the iguana repo copied into this one
  27. //try addGithubReleaseExe(b, github_release_step, ziget_repo, "x86_64-linux", SslBackend.iguana);
  28. const ssl_backend = zigetbuild.getSslBackend(b);
  29. const target = b.standardTargetOptions(.{});
  30. const mode = b.standardReleaseOptions();
  31. const exe = try addZigupExe(b, ziget_repo, target, mode, ssl_backend);
  32. exe.install();
  33. const run_cmd = exe.run();
  34. run_cmd.step.dependOn(b.getInstallStep());
  35. const run_step = b.step("run", "Run the app");
  36. run_step.dependOn(&run_cmd.step);
  37. addTest(b, exe, target, mode);
  38. }
  39. fn addTest(b: *Builder, exe: *std.build.LibExeObjStep, target: std.zig.CrossTarget, mode: std.builtin.Mode) void {
  40. const test_exe = b.addExecutable("test", "test.zig");
  41. test_exe.setTarget(target);
  42. test_exe.setBuildMode(mode);
  43. const run_cmd = test_exe.run();
  44. // TODO: make this work, add exe install path as argument to test
  45. //run_cmd.addArg(exe.getInstallPath());
  46. _ = exe;
  47. run_cmd.step.dependOn(b.getInstallStep());
  48. const test_step = b.step("test", "test the executable");
  49. test_step.dependOn(&run_cmd.step);
  50. }
  51. fn addZigupExe(b: *Builder, ziget_repo: []const u8, target: std.zig.CrossTarget, mode: std.builtin.Mode, ssl_backend: ?SslBackend) !*std.build.LibExeObjStep {
  52. const require_ssl_backend = b.allocator.create(RequireSslBackendStep) catch unreachable;
  53. require_ssl_backend.* = RequireSslBackendStep.init(b, "the zigup exe", ssl_backend);
  54. const exe = b.addExecutable("zigup", "zigup.zig");
  55. exe.setTarget(target);
  56. exe.setBuildMode(mode);
  57. const ziget_ssl_pkg = blk: {
  58. if (ssl_backend) |backend| {
  59. break :blk zigetbuild.addSslBackend(exe, backend, ziget_repo) catch {
  60. const ssl_backend_failed = b.allocator.create(SslBackendFailedStep) catch unreachable;
  61. ssl_backend_failed.* = SslBackendFailedStep.init(b, "the zigup exe", backend);
  62. break :blk Pkg {
  63. .name = "missing-ssl-backend-files",
  64. .path = .{ .path = "missing-ssl-backend-files.zig" },
  65. };
  66. };
  67. }
  68. break :blk Pkg {
  69. .name = "no-ssl-backend-configured",
  70. .path = .{ .path = "no-ssl-backend-configured.zig" },
  71. };
  72. };
  73. exe.addPackage(Pkg {
  74. .name = "ziget",
  75. .path = .{ .path = try join(b, &[_][]const u8 { ziget_repo, "ziget.zig" }) },
  76. .dependencies = &[_]Pkg {ziget_ssl_pkg},
  77. });
  78. if (targetIsWindows(target)) {
  79. const zarc_repo = try (GitRepo {
  80. .url = "https://github.com/SuperAuguste/zarc",
  81. .branch = null,
  82. .sha = @embedFile("zarcsha"),
  83. }).resolve(b.allocator);
  84. exe.addPackage(Pkg {
  85. .name = "zarc",
  86. .path = .{ .path = try join(b, &[_][]const u8 { zarc_repo, "src", "main.zig" }) },
  87. });
  88. }
  89. exe.step.dependOn(&require_ssl_backend.step);
  90. return exe;
  91. }
  92. fn targetIsWindows(target: std.zig.CrossTarget) bool {
  93. if (target.os_tag) |tag|
  94. return tag == .windows;
  95. return builtin.target.os.tag == .windows;
  96. }
  97. const SslBackendFailedStep = struct {
  98. step: std.build.Step,
  99. context: []const u8,
  100. backend: SslBackend,
  101. pub fn init(b: *Builder, context: []const u8, backend: SslBackend) SslBackendFailedStep {
  102. return .{
  103. .step = std.build.Step.init(.custom, "SslBackendFailedStep", b.allocator, make),
  104. .context = context,
  105. .backend = backend,
  106. };
  107. }
  108. fn make(step: *std.build.Step) !void {
  109. const self = @fieldParentPtr(RequireSslBackendStep, "step", step);
  110. std.debug.print("error: the {s} failed to add the {s} SSL backend\n", .{self.context, self.backend});
  111. std.os.exit(1);
  112. }
  113. };
  114. const RequireSslBackendStep = struct {
  115. step: std.build.Step,
  116. context: []const u8,
  117. backend: ?SslBackend,
  118. pub fn init(b: *Builder, context: []const u8, backend: ?SslBackend) RequireSslBackendStep {
  119. return .{
  120. .step = std.build.Step.init(.custom, "RequireSslBackend", b.allocator, make),
  121. .context = context,
  122. .backend = backend,
  123. };
  124. }
  125. fn make(step: *std.build.Step) !void {
  126. const self = @fieldParentPtr(RequireSslBackendStep, "step", step);
  127. if (self.backend) |_| { } else {
  128. std.debug.print("error: {s} requires an SSL backend:\n", .{self.context});
  129. inline for (zigetbuild.ssl_backends) |field| {
  130. std.debug.print(" -D{s}\n", .{field.name});
  131. }
  132. std.os.exit(1);
  133. }
  134. }
  135. };
  136. fn addGithubReleaseExe(b: *Builder, github_release_step: *std.build.Step, ziget_repo: []const u8, comptime target_triple: []const u8, comptime ssl_backend: SslBackend) !void {
  137. const small_release = true;
  138. const target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = target_triple });
  139. const mode = if (small_release) .ReleaseSafe else .Debug;
  140. const exe = try addZigupExe(b, ziget_repo, target, mode, ssl_backend);
  141. if (small_release) {
  142. exe.strip = true;
  143. }
  144. exe.setOutputDir("github-release" ++ std.fs.path.sep_str ++ target_triple ++ std.fs.path.sep_str ++ @tagName(ssl_backend));
  145. github_release_step.dependOn(&exe.step);
  146. }
  147. fn join(b: *Builder, parts: []const []const u8) ![]const u8 {
  148. return try std.fs.path.join(b.allocator, parts);
  149. }
  150. pub const GitRepo = struct {
  151. url: []const u8,
  152. branch: ?[]const u8,
  153. sha: []const u8,
  154. path: ?[]const u8 = null,
  155. pub fn defaultReposDir(allocator: *std.mem.Allocator) ![]const u8 {
  156. const cwd = try std.process.getCwdAlloc(allocator);
  157. defer allocator.free(cwd);
  158. return try std.fs.path.join(allocator, &[_][]const u8 { cwd, "dep" });
  159. }
  160. pub fn resolve(self: GitRepo, allocator: *std.mem.Allocator) ![]const u8 {
  161. var optional_repos_dir_to_clean: ?[]const u8 = null;
  162. defer {
  163. if (optional_repos_dir_to_clean) |p| {
  164. allocator.free(p);
  165. }
  166. }
  167. const path = if (self.path) |p| try allocator.dupe(u8, p) else blk: {
  168. const repos_dir = try defaultReposDir(allocator);
  169. optional_repos_dir_to_clean = repos_dir;
  170. break :blk try std.fs.path.join(allocator, &[_][]const u8{ repos_dir, std.fs.path.basename(self.url) });
  171. };
  172. errdefer self.allocator.free(path);
  173. std.fs.accessAbsolute(path, std.fs.File.OpenFlags { .read = true }) catch {
  174. std.debug.print("Error: repository '{s}' does not exist\n", .{path});
  175. std.debug.print(" Run the following to clone it:\n", .{});
  176. const branch_args = if (self.branch) |b| &[2][]const u8 {" -b ", b} else &[2][]const u8 {"", ""};
  177. std.debug.print(" git clone {s}{s}{s} {s} && git -C {3s} checkout {s} -b for_zigup\n",
  178. .{self.url, branch_args[0], branch_args[1], path, self.sha});
  179. std.os.exit(1);
  180. };
  181. // TODO: check if the SHA matches an print a message and/or warning if it is different
  182. return path;
  183. }
  184. pub fn resolveOneFile(self: GitRepo, allocator: *std.mem.Allocator, index_sub_path: []const u8) ![]const u8 {
  185. const repo_path = try self.resolve(allocator);
  186. defer allocator.free(repo_path);
  187. return try std.fs.path.join(allocator, &[_][]const u8 { repo_path, index_sub_path });
  188. }
  189. };