aboutsummaryrefslogtreecommitdiff
path: root/lib/std/Build/InstallArtifactStep.zig
blob: 50cf6ff323b35a9daae286b7601e042e3a9a5879 (plain)
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
const std = @import("../std.zig");
const Step = std.Build.Step;
const CompileStep = std.Build.CompileStep;
const InstallDir = std.Build.InstallDir;
const InstallArtifactStep = @This();
const fs = std.fs;

pub const base_id = .install_artifact;

step: Step,
artifact: *CompileStep,
dest_dir: InstallDir,
pdb_dir: ?InstallDir,
h_dir: ?InstallDir,
/// If non-null, adds additional path components relative to dest_dir, and
/// overrides the basename of the CompileStep.
dest_sub_path: ?[]const u8,

pub fn create(owner: *std.Build, artifact: *CompileStep) *InstallArtifactStep {
    const self = owner.allocator.create(InstallArtifactStep) catch @panic("OOM");
    self.* = InstallArtifactStep{
        .step = Step.init(.{
            .id = base_id,
            .name = owner.fmt("install {s}", .{artifact.name}),
            .owner = owner,
            .makeFn = make,
        }),
        .artifact = artifact,
        .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
            .obj => @panic("Cannot install a .obj build artifact."),
            .exe, .@"test" => InstallDir{ .bin = {} },
            .lib => InstallDir{ .lib = {} },
        },
        .pdb_dir = if (artifact.producesPdbFile()) blk: {
            if (artifact.kind == .exe or artifact.kind == .@"test") {
                break :blk InstallDir{ .bin = {} };
            } else {
                break :blk InstallDir{ .lib = {} };
            }
        } else null,
        .h_dir = if (artifact.kind == .lib and artifact.emit_h) .header else null,
        .dest_sub_path = null,
    };
    self.step.dependOn(&artifact.step);

    owner.pushInstalledFile(self.dest_dir, artifact.out_filename);
    if (self.artifact.isDynamicLibrary()) {
        if (artifact.major_only_filename) |name| {
            owner.pushInstalledFile(.lib, name);
        }
        if (artifact.name_only_filename) |name| {
            owner.pushInstalledFile(.lib, name);
        }
        if (self.artifact.target.isWindows()) {
            owner.pushInstalledFile(.lib, artifact.out_lib_filename);
        }
    }
    if (self.pdb_dir) |pdb_dir| {
        owner.pushInstalledFile(pdb_dir, artifact.out_pdb_filename);
    }
    if (self.h_dir) |h_dir| {
        owner.pushInstalledFile(h_dir, artifact.out_h_filename);
    }
    return self;
}

fn make(step: *Step, prog_node: *std.Progress.Node) !void {
    _ = prog_node;
    const self = @fieldParentPtr(InstallArtifactStep, "step", step);
    const src_builder = self.artifact.step.owner;
    const dest_builder = step.owner;

    const dest_sub_path = if (self.dest_sub_path) |sub_path| sub_path else self.artifact.out_filename;
    const full_dest_path = dest_builder.getInstallPath(self.dest_dir, dest_sub_path);
    const cwd = fs.cwd();

    var all_cached = true;

    {
        const full_src_path = self.artifact.getOutputSource().getPath(src_builder);
        const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_dest_path, .{}) catch |err| {
            return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
                full_src_path, full_dest_path, @errorName(err),
            });
        };
        all_cached = all_cached and p == .fresh;
    }

    if (self.artifact.isDynamicLibrary() and
        self.artifact.version != null and
        self.artifact.target.wantSharedLibSymLinks())
    {
        try CompileStep.doAtomicSymLinks(step, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);
    }
    if (self.artifact.isDynamicLibrary() and
        self.artifact.target.isWindows() and
        self.artifact.emit_implib != .no_emit)
    {
        const full_src_path = self.artifact.getOutputLibSource().getPath(src_builder);
        const full_implib_path = dest_builder.getInstallPath(self.dest_dir, self.artifact.out_lib_filename);
        const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_implib_path, .{}) catch |err| {
            return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
                full_src_path, full_implib_path, @errorName(err),
            });
        };
        all_cached = all_cached and p == .fresh;
    }
    if (self.pdb_dir) |pdb_dir| {
        const full_src_path = self.artifact.getOutputPdbSource().getPath(src_builder);
        const full_pdb_path = dest_builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename);
        const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_pdb_path, .{}) catch |err| {
            return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
                full_src_path, full_pdb_path, @errorName(err),
            });
        };
        all_cached = all_cached and p == .fresh;
    }
    if (self.h_dir) |h_dir| {
        const full_src_path = self.artifact.getOutputHSource().getPath(src_builder);
        const full_h_path = dest_builder.getInstallPath(h_dir, self.artifact.out_h_filename);
        const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| {
            return step.fail("unable to update file from '{s}' to '{s}': {s}", .{
                full_src_path, full_h_path, @errorName(err),
            });
        };
        all_cached = all_cached and p == .fresh;
    }
    self.artifact.installed_path = full_dest_path;
    step.result_cached = all_cached;
}