123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- const std = @import("std");
- const builtin = @import("builtin");
- const Builder = std.build.Builder;
- const Pkg = std.build.Pkg;
- const GitRepoStep = @import("GitRepoStep.zig");
- const loggyrunstep = @import("loggyrunstep.zig");
- pub fn build(b: *Builder) !void {
- const target = b.standardTargetOptions(.{});
- const mode = b.standardReleaseOptions();
- const build_all_step = b.step("all", "Build ziget with all the 'enabled' backends");
- const nossl_exe = addExe(b, target, mode, null, build_all_step);
- var ssl_exes: [ssl_backends.len]*std.build.LibExeObjStep = undefined;
- inline for (ssl_backends) |field, i| {
- const enum_value = @field(SslBackend, field.name);
- ssl_exes[i] = addExe(b, target, mode, enum_value, build_all_step);
- }
- const test_all_step = b.step("test", "Run all the 'Enabled' tests");
- addTest(b, test_all_step, "nossl", nossl_exe, null);
- inline for (ssl_backends) |field, i| {
- const enum_value = @field(SslBackend, field.name);
- addTest(b, test_all_step, field.name, ssl_exes[i], enum_value);
- }
- // by default, install zig-iguana
- const default_exe = ssl_exes[@enumToInt(SslBackend.iguana)];
- b.getInstallStep().dependOn(&default_exe.install_step.?.step);
- const run_cmd = default_exe.run();
- run_cmd.step.dependOn(b.getInstallStep());
- if (b.args) |args| {
- run_cmd.addArgs(args);
- }
- const run_step = b.step("run", "Run ziget with the iguana backend");
- run_step.dependOn(&run_cmd.step);
- }
- fn getEnabledByDefault(optional_ssl_backend: ?SslBackend) bool {
- return if (optional_ssl_backend) |backend| switch (backend) {
- .iguana => true,
- .schannel => false, // schannel not supported yet
- .opensslstatic => (
- builtin.os.tag == .linux
- // or builtin.os.tag == .macos (not working yet, I think config is not working)
- ),
- .openssl => (
- builtin.os.tag == .linux
- // or builtin.os.tag == .macos (not working yet, not sure why)
- ),
- } else true;
- }
- fn addExe(
- b: *Builder,
- target: std.build.Target,
- mode: std.builtin.Mode,
- comptime optional_ssl_backend: ?SslBackend,
- build_all_step: *std.build.Step,
- ) *std.build.LibExeObjStep {
- const info: struct { name: []const u8, exe_suffix: []const u8 } = if (optional_ssl_backend) |backend| .{
- .name = @tagName(backend),
- .exe_suffix = if (backend == .iguana) "" else ("-" ++ @tagName(backend)),
- } else .{
- .name = "nossl",
- .exe_suffix = "-nossl",
- };
- const exe = b.addExecutable("ziget" ++ info.exe_suffix, "ziget-cmdline.zig");
- exe.setTarget(target);
- exe.single_threaded = true;
- exe.setBuildMode(mode);
- addZigetPkg(exe, optional_ssl_backend, ".");
- const install = b.addInstallArtifact(exe);
- const enabled_by_default = getEnabledByDefault(optional_ssl_backend);
- if (enabled_by_default) {
- build_all_step.dependOn(&install.step);
- }
- const abled_suffix: []const u8 = if (enabled_by_default) "" else " (DISABLED BY DEFAULT)";
- b.step(info.name, b.fmt("Build ziget with the {s} backend{s}", .{
- info.name,
- abled_suffix,
- })).dependOn(
- &install.step
- );
- return exe;
- }
- fn addTest(
- b: *Builder,
- test_all_step: *std.build.Step,
- comptime backend_name: []const u8,
- exe: *std.build.LibExeObjStep,
- optional_ssl_backend: ?SslBackend,
- ) void {
- const enabled_by_default = getEnabledByDefault(optional_ssl_backend);
- const abled_suffix: []const u8 = if (enabled_by_default) "" else " (DISABLED BY DEFAULT)";
- const test_backend_step = b.step(
- "test-" ++ backend_name,
- b.fmt("Test the {s} backend{s}", .{backend_name, abled_suffix})
- );
- {
- const run = exe.run();
- run.addArg("http://google.com");
- loggyrunstep.enable(run);
- test_backend_step.dependOn(&run.step);
- }
- if (optional_ssl_backend) |_| {
- {
- const run = exe.run();
- run.addArg("http://ziglang.org"); // NOTE: ziglang.org will redirect to HTTPS
- loggyrunstep.enable(run);
- test_backend_step.dependOn(&run.step);
- }
- {
- const run = exe.run();
- run.addArg("https://ziglang.org");
- loggyrunstep.enable(run);
- test_backend_step.dependOn(&run.step);
- }
- } else {
- const run = exe.run();
- run.addArg("google.com");
- loggyrunstep.enable(run);
- test_backend_step.dependOn(&run.step);
- }
- if (getEnabledByDefault(optional_ssl_backend)) {
- test_all_step.dependOn(test_backend_step);
- }
- }
- pub const SslBackend = enum {
- openssl,
- opensslstatic,
- iguana,
- schannel,
- };
- pub const ssl_backends = @typeInfo(SslBackend).Enum.fields;
- ///! Adds the ziget package to the given lib_exe_obj.
- ///! This function will add the necessary include directories, libraries, etc to be able to
- ///! include ziget and it's SSL backend dependencies into the given lib_exe_obj.
- pub fn addZigetPkg(
- lib_exe_obj: *std.build.LibExeObjStep,
- optional_ssl_backend: ?SslBackend,
- ziget_repo: []const u8,
- ) void {
- const b = lib_exe_obj.builder;
- const ziget_index = std.fs.path.join(b.allocator, &[_][]const u8 { ziget_repo, "ziget.zig" }) catch unreachable;
- const ssl_pkg = if (optional_ssl_backend) |backend| addSslBackend(lib_exe_obj, backend, ziget_repo)
- else Pkg{ .name = "ssl", .path = .{ .path = "nossl/ssl.zig" } };
- lib_exe_obj.addPackage(Pkg {
- .name = "ziget",
- .path = .{ .path = ziget_index },
- .dependencies = &[_]Pkg {ssl_pkg},
- });
- }
- fn addSslBackend(lib_exe_obj: *std.build.LibExeObjStep, backend: SslBackend, ziget_repo: []const u8) Pkg {
- const b = lib_exe_obj.builder;
- switch (backend) {
- .openssl => {
- lib_exe_obj.linkSystemLibrary("c");
- if (builtin.os.tag == .windows) {
- lib_exe_obj.linkSystemLibrary("libcrypto");
- lib_exe_obj.linkSystemLibrary("libssl");
- setupOpensslWindows(lib_exe_obj);
- } else {
- lib_exe_obj.linkSystemLibrary("crypto");
- lib_exe_obj.linkSystemLibrary("ssl");
- }
- return Pkg{
- .name = "ssl",
- .path = .{ .path = std.fs.path.join(b.allocator, &[_][]const u8 { ziget_repo, "openssl", "ssl.zig" }) catch unreachable}
- };
- },
- .opensslstatic => {
- const openssl_repo = GitRepoStep.create(b, .{
- .url = "https://github.com/openssl/openssl",
- .branch = "OpenSSL_1_1_1j",
- .sha = "52c587d60be67c337364b830dd3fdc15404a2f04",
- });
- // TODO: should we implement something to cache the configuration?
- // can the configure output be in a different directory?
- {
- const configure_openssl = std.build.RunStep.create(b, "configure openssl");
- configure_openssl.step.dependOn(&openssl_repo.step);
- configure_openssl.cwd = openssl_repo.getPath(&configure_openssl.step);
- configure_openssl.addArgs(&[_][]const u8 {
- "./config",
- // just a temporary path for now
- //"--openssl",
- //"/tmp/ziget-openssl-static-dir1",
- "-static",
- // just disable everything for now
- "no-threads",
- "no-shared",
- "no-asm",
- "no-sse2",
- "no-aria",
- "no-bf",
- "no-camellia",
- "no-cast",
- "no-des",
- "no-dh",
- "no-dsa",
- "no-ec",
- "no-idea",
- "no-md2",
- "no-mdc2",
- "no-rc2",
- "no-rc4",
- "no-rc5",
- "no-seed",
- "no-sm2",
- "no-sm3",
- "no-sm4",
- });
- configure_openssl.stdout_action = .{
- .expect_matches = &[_][]const u8 { "OpenSSL has been successfully configured" },
- };
- const make_openssl = std.build.RunStep.create(b, "configure openssl");
- make_openssl.cwd = configure_openssl.cwd;
- make_openssl.addArgs(&[_][]const u8 {
- "make",
- "include/openssl/opensslconf.h",
- "include/crypto/bn_conf.h",
- "include/crypto/dso_conf.h",
- });
- make_openssl.step.dependOn(&configure_openssl.step);
- lib_exe_obj.step.dependOn(&make_openssl.step);
- }
- const openssl_repo_path_for_step = openssl_repo.getPath(&lib_exe_obj.step);
- lib_exe_obj.addIncludeDir(openssl_repo_path_for_step);
- lib_exe_obj.addIncludeDir(std.fs.path.join(b.allocator, &[_][]const u8 {
- openssl_repo_path_for_step, "include" }) catch unreachable);
- lib_exe_obj.addIncludeDir(std.fs.path.join(b.allocator, &[_][]const u8 {
- openssl_repo_path_for_step, "crypto", "modes" }) catch unreachable);
- const cflags = &[_][]const u8 {
- "-Wall",
- // TODO: is this the right way to do this? is it a config option?
- "-DOPENSSL_NO_ENGINE",
- // TODO: --openssldir doesn't seem to be setting this?
- "-DOPENSSLDIR=\"/tmp/ziget-openssl-static-dir2\"",
- };
- {
- const sources = @embedFile("openssl/sources");
- var source_lines = std.mem.split(u8, sources, "\n");
- while (source_lines.next()) |src| {
- if (src.len == 0 or src[0] == '#') continue;
- lib_exe_obj.addCSourceFile(std.fs.path.join(b.allocator, &[_][]const u8 {
- openssl_repo_path_for_step, src }) catch unreachable, cflags);
- }
- }
- lib_exe_obj.linkLibC();
- return Pkg{
- .name = "ssl",
- .path = .{ .path = std.fs.path.join(b.allocator, &[_][]const u8 { ziget_repo, "openssl", "ssl.zig" }) catch unreachable},
- };
- },
- .iguana => {
- const iguana_repo = GitRepoStep.create(b, .{
- .url = "https://github.com/marler8997/iguanaTLS",
- .branch = null,
- .sha = "f997c1085470f2414a4bbc50ea170e1da82058ab",
- });
- lib_exe_obj.step.dependOn(&iguana_repo.step);
- const iguana_repo_path = iguana_repo.getPath(&lib_exe_obj.step);
- const iguana_index_file = std.fs.path.join(b.allocator, &[_][]const u8 {iguana_repo_path, "src", "main.zig"}) catch unreachable;
- return b.dupePkg(Pkg{
- .name = "ssl",
- .path = .{ .path = std.fs.path.join(b.allocator, &[_][]const u8 { ziget_repo, "iguana", "ssl.zig" }) catch unreachable },
- .dependencies = &[_]Pkg {
- .{ .name = "iguana", .path = .{ .path = iguana_index_file } },
- },
- });
- },
- .schannel => {
- {
- // NOTE: for now I'm using msspi from https://github.com/deemru/msspi
- // I'll probably port this to Zig at some point
- // Once I do remove this build config
- // NOTE: I tested using this commit: 7338760a4a2c6fb80c47b24a2abba32d5fc40635 tagged at version 0.1.42
- const msspi_repo = GitRepoStep.create(b, .{
- .url = "https://github.com/deemru/msspi",
- .branch = "0.1.42",
- .sha = "7338760a4a2c6fb80c47b24a2abba32d5fc40635"
- });
- lib_exe_obj.step.dependOn(&msspi_repo.step);
- const msspi_repo_path = msspi_repo.getPath(&lib_exe_obj.step);
- const msspi_src_dir = std.fs.path.join(b.allocator, &[_][]const u8 { msspi_repo_path, "src" }) catch unreachable;
- const msspi_main_cpp = std.fs.path.join(b.allocator, &[_][]const u8 { msspi_src_dir, "msspi.cpp" }) catch unreachable;
- const msspi_third_party_include = std.fs.path.join(b.allocator, &[_][]const u8 { msspi_repo_path, "third_party", "cprocsp", "include" }) catch unreachable;
- lib_exe_obj.addCSourceFile(msspi_main_cpp, &[_][]const u8 { });
- lib_exe_obj.addIncludeDir(msspi_src_dir);
- lib_exe_obj.addIncludeDir(msspi_third_party_include);
- lib_exe_obj.linkLibC();
- lib_exe_obj.linkSystemLibrary("ws2_32");
- lib_exe_obj.linkSystemLibrary("crypt32");
- lib_exe_obj.linkSystemLibrary("advapi32");
- }
- // TODO: this will be needed if/when msspi is ported to Zig
- //const zigwin32_index_file = try getGitRepoFile(b.allocator,
- // "https://github.com/marlersoft/zigwin32",
- // "src" ++ std.fs.path.sep_str ++ "win32.zig");
- return b.dupePkg(.{
- .name = "ssl",
- .path = .{ .path = std.fs.path.join(b.allocator, &[_][]const u8 { ziget_repo, "schannel", "ssl.zig" }) catch unreachable },
- //.dependencies = &[_]Pkg {
- // .{ .name = "win32", .path = .{ .path = zigwin32_index_file } },
- //},
- });
- }
- }
- }
- const OpensslPathOption = struct {
- // NOTE: I can't use ??[]const u8 because it exposes a bug in the compiler
- is_cached: bool = false,
- cached: ?[]const u8 = undefined,
- fn get(self: *OpensslPathOption, b: *std.build.Builder) ?[]const u8 {
- if (!self.is_cached) {
- self.cached = b.option(
- []const u8,
- "openssl-path",
- "path to openssl (for Windows)",
- );
- self.is_cached = true;
- }
- std.debug.assert(self.is_cached);
- return self.cached;
- }
- };
- var global_openssl_path_option = OpensslPathOption { };
- pub fn setupOpensslWindows(lib_exe_obj: *std.build.LibExeObjStep) void {
- const b = lib_exe_obj.builder;
- const openssl_path = global_openssl_path_option.get(b) orelse {
- lib_exe_obj.step.dependOn(&FailStep.create(b, "missing openssl-path",
- "-Dopenssl on windows requires -Dopenssl-path=DIR to be specified").step);
- return;
- };
- // NOTE: right now these files are hardcoded to the files expected when installing SSL via
- // this web page: https://slproweb.com/products/Win32OpenSSL.html and installed using
- // this exe installer: https://slproweb.com/download/Win64OpenSSL-1_1_1g.exe
- lib_exe_obj.addIncludeDir(std.fs.path.join(b.allocator, &[_][]const u8 {openssl_path, "include"}) catch unreachable);
- lib_exe_obj.addLibPath(std.fs.path.join(b.allocator, &[_][]const u8 {openssl_path, "lib"}) catch unreachable);
- // install dlls to the same directory as executable
- for ([_][]const u8 {"libcrypto-1_1-x64.dll", "libssl-1_1-x64.dll"}) |dll| {
- lib_exe_obj.step.dependOn(
- &b.addInstallFileWithDir(
- .{ .path = std.fs.path.join(b.allocator, &[_][]const u8 {openssl_path, dll}) catch unreachable },
- .bin,
- dll,
- ).step
- );
- }
- }
- const FailStep = struct {
- step: std.build.Step,
- fail_msg: []const u8,
- pub fn create(b: *Builder, name: []const u8, fail_msg: []const u8) *FailStep {
- var result = b.allocator.create(FailStep) catch unreachable;
- result.* = .{
- .step = std.build.Step.init(.custom, name, b.allocator, make),
- .fail_msg = fail_msg,
- };
- return result;
- }
- fn make(step: *std.build.Step) !void {
- const self = @fieldParentPtr(FailStep, "step", step);
- std.log.err("{s}", .{self.fail_msg});
- std.os.exit(0xff);
- }
- };
|