| 1 | const InstallArtifact = @This(); |
| 2 | |
| 3 | const std = @import("std"); |
| 4 | const Step = std.Build.Step; |
| 5 | const InstallDir = std.Build.InstallDir; |
| 6 | const LazyPath = std.Build.LazyPath; |
| 7 | |
| 8 | step: Step, |
| 9 | |
| 10 | dest_dir: ?InstallDir, |
| 11 | dest_sub_path: ?[]const u8, |
| 12 | emitted_bin: ?LazyPath, |
| 13 | |
| 14 | implib_dir: ?InstallDir, |
| 15 | emitted_implib: ?LazyPath, |
| 16 | |
| 17 | pdb_dir: ?InstallDir, |
| 18 | emitted_pdb: ?LazyPath, |
| 19 | |
| 20 | h_dir: ?InstallDir, |
| 21 | emitted_h: ?LazyPath, |
| 22 | |
| 23 | dylib_symlinks: bool, |
| 24 | |
| 25 | artifact: *Step.Compile, |
| 26 | |
| 27 | const DylibSymlinkInfo = struct { |
| 28 | major_only_filename: []const u8, |
| 29 | name_only_filename: []const u8, |
| 30 | }; |
| 31 | |
| 32 | pub const base_tag: Step.Tag = .install_artifact; |
| 33 | |
| 34 | pub const Options = struct { |
| 35 | /// Which installation directory to put the main output file into. |
| 36 | dest_dir: Dir = .default, |
| 37 | pdb_dir: Dir = .default, |
| 38 | compiler_rt_dyn_lib_dir: Dir = .default, |
| 39 | h_dir: Dir = .default, |
| 40 | implib_dir: Dir = .default, |
| 41 | |
| 42 | /// Whether to install symlinks along with dynamic libraries. |
| 43 | dylib_symlinks: ?bool = null, |
| 44 | /// If non-null, adds additional path components relative to bin dir, and |
| 45 | /// overrides the basename of the Compile step for installation purposes. |
| 46 | dest_sub_path: ?[]const u8 = null, |
| 47 | |
| 48 | pub const Dir = union(enum) { |
| 49 | disabled, |
| 50 | default, |
| 51 | override: InstallDir, |
| 52 | }; |
| 53 | }; |
| 54 | |
| 55 | pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *InstallArtifact { |
| 56 | const install_artifact = owner.allocator.create(InstallArtifact) catch @panic("OOM"); |
| 57 | const dest_dir: ?InstallDir = switch (options.dest_dir) { |
| 58 | .disabled => null, |
| 59 | .default => switch (artifact.kind) { |
| 60 | .obj, .test_obj => @panic("object files have no standard installation procedure"), |
| 61 | .exe, .@"test" => .bin, |
| 62 | .lib => if (artifact.isDll()) .bin else .lib, |
| 63 | }, |
| 64 | .override => |o| o, |
| 65 | }; |
| 66 | const pdb_dir: ?InstallDir = switch (options.pdb_dir) { |
| 67 | .disabled => null, |
| 68 | .default => if (artifact.producesPdbFile()) dest_dir else null, |
| 69 | .override => |o| o, |
| 70 | }; |
| 71 | const implib_dir: ?InstallDir = switch (options.implib_dir) { |
| 72 | .disabled => null, |
| 73 | .default => if (artifact.producesImplib()) .lib else null, |
| 74 | .override => |o| o, |
| 75 | }; |
| 76 | install_artifact.* = .{ |
| 77 | .step = Step.init(.{ |
| 78 | .tag = base_tag, |
| 79 | .name = owner.fmt("install {s}", .{artifact.name}), |
| 80 | .owner = owner, |
| 81 | }), |
| 82 | .dest_dir = dest_dir, |
| 83 | .pdb_dir = pdb_dir, |
| 84 | .h_dir = switch (options.h_dir) { |
| 85 | .disabled => null, |
| 86 | .default => if (artifact.kind == .lib) .header else null, |
| 87 | .override => |o| o, |
| 88 | }, |
| 89 | .implib_dir = implib_dir, |
| 90 | |
| 91 | .dylib_symlinks = options.dylib_symlinks orelse (dest_dir != null and |
| 92 | artifact.isDynamicLibrary() and artifact.version != null and |
| 93 | std.Build.wantSharedLibSymLinks(artifact.rootModuleTarget())), |
| 94 | |
| 95 | .dest_sub_path = options.dest_sub_path, |
| 96 | |
| 97 | .emitted_bin = if (dest_dir != null) artifact.getEmittedBin() else null, |
| 98 | .emitted_pdb = if (pdb_dir != null) artifact.getEmittedPdb() else null, |
| 99 | // https://github.com/ziglang/zig/issues/9698 |
| 100 | .emitted_h = null, |
| 101 | .emitted_implib = if (implib_dir != null) artifact.getEmittedImplib() else null, |
| 102 | |
| 103 | .artifact = artifact, |
| 104 | }; |
| 105 | |
| 106 | install_artifact.step.dependOn(&artifact.step); |
| 107 | |
| 108 | return install_artifact; |
| 109 | } |