| 1 | const InstallArtifact = @This(); |
| 2 | |
| 3 | const std = @import("std"); |
| 4 | const Io = std.Io; |
| 5 | const Configuration = std.Build.Configuration; |
| 6 | const assert = std.debug.assert; |
| 7 | |
| 8 | const Step = @import("../Step.zig"); |
| 9 | const Maker = @import("../../Maker.zig"); |
| 10 | |
| 11 | pub fn make( |
| 12 | install_artifact: *InstallArtifact, |
| 13 | step_index: Configuration.Step.Index, |
| 14 | maker: *Maker, |
| 15 | progress_node: std.Progress.Node, |
| 16 | ) Step.ExtendedMakeError!void { |
| 17 | _ = install_artifact; |
| 18 | _ = progress_node; |
| 19 | const step = maker.stepByIndex(step_index); |
| 20 | const conf = &maker.scanned_config.configuration; |
| 21 | const graph = maker.graph; |
| 22 | const gpa = maker.gpa; |
| 23 | const arena = graph.arena; // TODO don't leak into process arena |
| 24 | const io = graph.io; |
| 25 | const conf_step = step_index.ptr(conf); |
| 26 | const conf_ia = conf_step.extended.get(conf.extra).install_artifact; |
| 27 | const compile_step_index = conf_step.deps.get(conf).steps.slice[0]; |
| 28 | const conf_comp_step = compile_step_index.ptr(conf); |
| 29 | const conf_comp = conf_comp_step.extended.get(conf.extra).compile; |
| 30 | const root_module = conf_comp.root_module.get(conf); |
| 31 | const target = root_module.resolved_target.get(conf).?.result.get(conf); |
| 32 | |
| 33 | var all_cached = true; |
| 34 | |
| 35 | if (conf_ia.bin_dir.value) |bin_dir| { |
| 36 | if (conf_comp.generated_bin.value) |generated_bin| { |
| 37 | const bin_sub_path = if (conf_ia.bin_sub_path.value) |s| s.slice(conf) else try std.zig.binNameAlloc(arena, .{ |
| 38 | .root_name = conf_comp.root_name.slice(conf), |
| 39 | .cpu_arch = target.flags.cpu_arch.unwrap().?, |
| 40 | .os_tag = target.flags.os_tag.unwrap().?, |
| 41 | .ofmt = target.flags.object_format.unwrap().?, |
| 42 | .abi = target.flags.abi.unwrap().?, |
| 43 | .output_mode = conf_comp.flags3.kind.toOutputMode(), |
| 44 | .link_mode = conf_comp.flags2.linkage.unwrap(), |
| 45 | .version = v: { |
| 46 | const string = conf_comp.version.value orelse break :v null; |
| 47 | const slice = string.slice(conf); |
| 48 | break :v std.SemanticVersion.parse(slice) catch @panic("bad semver string"); |
| 49 | }, |
| 50 | }); |
| 51 | const dest_dir = try maker.resolveInstallDir(arena, bin_dir); |
| 52 | const dest_path = try dest_dir.join(arena, bin_sub_path); |
| 53 | const src_path = maker.generatedPath(generated_bin).*; |
| 54 | const p = try maker.installPath(arena, src_path, dest_path, step_index); |
| 55 | all_cached = all_cached and p == .fresh; |
| 56 | |
| 57 | if (conf_ia.flags.dylib_symlinks) |
| 58 | try maker.installSymLinks(arena, dest_path, compile_step_index, step_index); |
| 59 | |
| 60 | const make_comp_step = maker.stepByIndex(compile_step_index); |
| 61 | const make_comp = &make_comp_step.extended.compile; |
| 62 | make_comp.installed_path = dest_path; |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | if (conf_ia.implib_dir.value) |implib_dir| { |
| 67 | if (conf_comp.generated_implib.value) |generated_implib| { |
| 68 | const p = try maker.installGenerated(arena, generated_implib, implib_dir, step_index); |
| 69 | all_cached = all_cached and p == .fresh; |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | if (conf_ia.pdb_dir.value) |pdb_dir| { |
| 74 | if (conf_comp.generated_pdb.value) |generated_pdb| { |
| 75 | const p = try maker.installGenerated(arena, generated_pdb, pdb_dir, step_index); |
| 76 | all_cached = all_cached and p == .fresh; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | if (conf_ia.h_dir.value) |h_dir| { |
| 81 | const h_prefix = try maker.resolveInstallDir(arena, h_dir); |
| 82 | |
| 83 | if (conf_comp.generated_h.value) |generated_h| { |
| 84 | const p = try maker.installGenerated(arena, generated_h, h_dir, step_index); |
| 85 | all_cached = all_cached and p == .fresh; |
| 86 | } |
| 87 | |
| 88 | for (conf_comp.installed_headers.slice) |installation| switch (installation.get(conf.extra)) { |
| 89 | .file => |file| { |
| 90 | const src_path = try maker.resolveLazyPathIndex(arena, file.source, step_index); |
| 91 | const dest_path = try h_prefix.join(arena, file.dest_sub_path.slice(conf)); |
| 92 | const p = try maker.installPath(arena, src_path, dest_path, step_index); |
| 93 | all_cached = all_cached and p == .fresh; |
| 94 | }, |
| 95 | .directory => |dir| { |
| 96 | const src_dir_path = try maker.resolveLazyPathIndex(arena, dir.source, step_index); |
| 97 | const full_h_prefix = try h_prefix.join(arena, dir.dest_sub_path.slice(conf)); |
| 98 | |
| 99 | var src_dir = src_dir_path.root_dir.handle.openDir(io, src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { |
| 100 | return step.fail(maker, "unable to open source directory {f}: {t}", .{ src_dir_path, err }); |
| 101 | }; |
| 102 | defer src_dir.close(io); |
| 103 | |
| 104 | var it = try src_dir.walk(gpa); |
| 105 | defer it.deinit(); |
| 106 | next_entry: while (it.next(io) catch |err| switch (err) { |
| 107 | error.Canceled, error.OutOfMemory => |e| return e, |
| 108 | else => |e| return step.fail(maker, "failed to iterate directory {f}: {t}", .{ src_dir_path, e }), |
| 109 | }) |entry| { |
| 110 | for (dir.exclude_extensions.slice) |ext| { |
| 111 | if (std.mem.endsWith(u8, entry.path, ext.slice(conf))) continue :next_entry; |
| 112 | } |
| 113 | if (dir.flags.include_extensions) { |
| 114 | for (dir.include_extensions.slice) |inc| { |
| 115 | if (std.mem.endsWith(u8, entry.path, inc.slice(conf))) break; |
| 116 | } else { |
| 117 | continue :next_entry; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | const full_dest_path = try full_h_prefix.join(arena, entry.path); |
| 122 | switch (entry.kind) { |
| 123 | .directory => { |
| 124 | const p = try maker.installDir(arena, full_dest_path, step_index); |
| 125 | all_cached = all_cached and p == .existed; |
| 126 | }, |
| 127 | .file => { |
| 128 | const entry_dir_path = try maker.resolveLazyPathIndex(arena, dir.source, step_index); |
| 129 | const entry_path = try entry_dir_path.join(arena, entry.path); |
| 130 | const p = try maker.installPath(arena, entry_path, full_dest_path, step_index); |
| 131 | all_cached = all_cached and p == .fresh; |
| 132 | }, |
| 133 | else => continue, |
| 134 | } |
| 135 | } |
| 136 | }, |
| 137 | }; |
| 138 | } |
| 139 | |
| 140 | step.result_cached = all_cached; |
| 141 | } |