diff --git a/lib/std/build.zig b/lib/std/build.zig index ade3dabea3..b124b12fef 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -53,7 +53,7 @@ pub const Builder = struct { release_mode: ?builtin.Mode, is_release: bool, override_lib_dir: ?[]const u8, - + vcpkg_root: VcpkgRoot, pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, const PkgConfigError = error{ @@ -159,6 +159,7 @@ pub const Builder = struct { .is_release = false, .override_lib_dir = null, .install_path = undefined, + .vcpkg_root = VcpkgRoot{ .Unattempted = {} }, }; try self.top_level_steps.append(&self.install_tls); try self.top_level_steps.append(&self.uninstall_tls); @@ -1047,6 +1048,7 @@ pub const LibExeObjStep = struct { output_dir: ?[]const u8, need_system_paths: bool, is_linking_libc: bool = false, + vcpkg_bin_path: ?[]const u8 = null, installed_path: ?[]const u8, install_step: ?*InstallArtifactStep, @@ -1265,6 +1267,11 @@ pub const LibExeObjStep = struct { // option is supplied. const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {}", exe.step.name)); run_step.addArtifactArg(exe); + + if (exe.vcpkg_bin_path) |path| { + run_step.addPathDir(path); + } + return run_step; } @@ -1570,6 +1577,43 @@ pub const LibExeObjStep = struct { }) catch unreachable; } + /// If Vcpkg was found on the system, it will be added to include and lib + /// paths for the specified target. + pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: VcpkgLinkage) !void { + // Ideally in the Unattempted case we would call the function recursively + // after findVcpkgRoot and have only one switch statement, but the compiler + // cannot resolve the error set. + switch (self.builder.vcpkg_root) { + .Unattempted => { + self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root| + VcpkgRoot{ .Found = root } + else + .NotFound; + }, + .NotFound => return error.VcpkgNotFound, + .Found => {}, + } + + switch (self.builder.vcpkg_root) { + .Unattempted => unreachable, + .NotFound => return error.VcpkgNotFound, + .Found => |root| { + const allocator = self.builder.allocator; + const triplet = try Target.vcpkgTriplet(allocator, self.target, linkage); + defer self.builder.allocator.free(triplet); + + const include_path = try fs.path.join(allocator, [_][]const u8{ root, "installed", triplet, "include" }); + errdefer allocator.free(include_path); + try self.include_dirs.append(IncludeDir{ .RawPath = include_path }); + + const lib_path = try fs.path.join(allocator, [_][]const u8{ root, "installed", triplet, "lib" }); + try self.lib_paths.append(lib_path); + + self.vcpkg_bin_path = try fs.path.join(allocator, [_][]const u8{ root, "installed", triplet, "bin" }); + }, + } + } + pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void { assert(self.kind == Kind.Test); self.exec_cmd_args = args; @@ -2342,6 +2386,42 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj }; } +/// Returned slice must be freed by the caller. +fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 { + const appdata_path = try fs.getAppDataDir(allocator, "vcpkg"); + defer allocator.free(appdata_path); + + const path_file = try fs.path.join(allocator, [_][]const u8{ appdata_path, "vcpkg.path.txt" }); + defer allocator.free(path_file); + + const file = fs.File.openRead(path_file) catch return null; + defer file.close(); + + const size = @intCast(usize, try file.getEndPos()); + const vcpkg_path = try allocator.alloc(u8, size); + const size_read = try file.read(vcpkg_path); + std.debug.assert(size == size_read); + + return vcpkg_path; +} + +const VcpkgRoot = union(VcpkgRootStatus) { + Unattempted: void, + NotFound: void, + Found: []const u8, +}; + +const VcpkgRootStatus = enum { + Unattempted, + NotFound, + Found, +}; + +pub const VcpkgLinkage = enum { + Static, + Dynamic, +}; + pub const InstallDir = enum { Prefix, Lib, diff --git a/lib/std/target.zig b/lib/std/target.zig index 4d600d4d38..5c0ac3d905 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -218,6 +218,40 @@ pub const Target = union(enum) { ); } + /// Returned slice must be freed by the caller. + pub fn vcpkgTriplet(allocator: *mem.Allocator, target: Target, linkage: std.build.VcpkgLinkage) ![]const u8 { + const arch = switch (target.getArch()) { + .i386 => "x86", + .x86_64 => "x64", + + .arm, + .armeb, + .thumb, + .thumbeb, + .aarch64_32, + => "arm", + + .aarch64, + .aarch64_be, + => "arm64", + + else => return error.VcpkgNoSuchArchitecture, + }; + + const os = switch (target.getOs()) { + .windows => "windows", + .linux => "linux", + .macosx => "macos", + else => return error.VcpkgNoSuchOs, + }; + + if (linkage == .Static) { + return try mem.join(allocator, "-", [_][]const u8{ arch, os, "static" }); + } else { + return try mem.join(allocator, "-", [_][]const u8{ arch, os }); + } + } + pub fn allocDescription(self: Target, allocator: *mem.Allocator) ![]u8 { // TODO is there anything else worthy of the description that is not // already captured in the triple?