From def5462d053d744a9f4c2c6874355a23d3371b3d Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Thu, 10 Oct 2019 21:58:47 +0200 Subject: [PATCH] build: initial support for using vcpkg libraries --- lib/std/build.zig | 82 +++++++++++++++++++++++++++++++++++++++++++++- lib/std/target.zig | 34 +++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 899e74105b..3388e35128 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); @@ -1046,6 +1047,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, @@ -1264,6 +1266,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; } @@ -1569,6 +1576,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; @@ -2341,6 +2385,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?