mirror of
https://github.com/sbrow/envr.git
synced 2026-06-27 10:38:33 -04:00
383 lines
13 KiB
Zig
383 lines
13 KiB
Zig
const std = @import("std");
|
|
const debug = std.debug;
|
|
const heap = std.heap;
|
|
const mem = std.mem;
|
|
const ResolvedTarget = std.Build.ResolvedTarget;
|
|
const Query = std.Target.Query;
|
|
const builtin = @import("builtin");
|
|
|
|
const Preprocessor = @import("build/Preprocessor.zig");
|
|
|
|
fn getTarget(original_target: ResolvedTarget) ResolvedTarget {
|
|
var tmp = original_target;
|
|
|
|
if (tmp.result.isGnuLibC()) {
|
|
const min_glibc_version = std.SemanticVersion{
|
|
.major = 2,
|
|
.minor = 28,
|
|
.patch = 0,
|
|
};
|
|
const ver = tmp.result.os.version_range.linux.glibc;
|
|
if (ver.order(min_glibc_version) == .lt) {
|
|
std.debug.panic("sqlite requires glibc version >= 2.28", .{});
|
|
}
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
const TestTarget = struct {
|
|
query: Query,
|
|
single_threaded: bool = false,
|
|
};
|
|
|
|
const ci_targets = switch (builtin.target.cpu.arch) {
|
|
.x86_64 => switch (builtin.target.os.tag) {
|
|
.linux => [_]TestTarget{
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64, .abi = .musl } },
|
|
TestTarget{ .query = .{ .cpu_arch = .x86, .abi = .musl } },
|
|
TestTarget{ .query = .{ .cpu_arch = .aarch64, .abi = .musl } },
|
|
},
|
|
.windows => [_]TestTarget{
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64, .abi = .gnu } },
|
|
// Disabled due to https://github.com/ziglang/zig/issues/20047
|
|
// TestTarget{ .query = .{ .cpu_arch = .x86, .abi = .gnu } },
|
|
},
|
|
.macos => [_]TestTarget{
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64 } },
|
|
},
|
|
else => [_]TestTarget{},
|
|
},
|
|
else => [_]TestTarget{},
|
|
};
|
|
|
|
const all_test_targets = switch (builtin.target.cpu.arch) {
|
|
.x86_64 => switch (builtin.target.os.tag) {
|
|
.linux => [_]TestTarget{
|
|
TestTarget{ .query = .{} },
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64, .abi = .musl } },
|
|
TestTarget{ .query = .{ .cpu_arch = .x86, .abi = .musl } },
|
|
TestTarget{ .query = .{ .cpu_arch = .aarch64, .abi = .musl } },
|
|
TestTarget{ .query = .{ .cpu_arch = .riscv64, .abi = .musl } },
|
|
// Disabled because it fails for some unknown reason
|
|
// TestTarget{ .query = .{ .cpu_arch = .mips, .abi = .musl } },
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64, .os_tag = .windows } },
|
|
// Disabled due to https://github.com/ziglang/zig/issues/20047
|
|
// TestTarget{ .query = .{ .cpu_arch = .x86, .os_tag = .windows } },
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64, .os_tag = .macos } },
|
|
TestTarget{ .query = .{ .cpu_arch = .aarch64, .os_tag = .macos } },
|
|
},
|
|
.windows => [_]TestTarget{
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64, .abi = .gnu } },
|
|
// Disabled due to https://github.com/ziglang/zig/issues/20047
|
|
// TestTarget{ .query = .{ .cpu_arch = .x86, .abi = .gnu } },
|
|
},
|
|
.freebsd => [_]TestTarget{
|
|
TestTarget{ .query = .{} },
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64 } },
|
|
},
|
|
.macos => [_]TestTarget{
|
|
TestTarget{ .query = .{ .cpu_arch = .x86_64 } },
|
|
},
|
|
else => [_]TestTarget{
|
|
TestTarget{ .query = .{} },
|
|
},
|
|
},
|
|
.aarch64 => switch (builtin.target.os.tag) {
|
|
.linux, .windows, .freebsd, .macos => [_]TestTarget{
|
|
TestTarget{ .query = .{} },
|
|
},
|
|
else => [_]TestTarget{
|
|
TestTarget{ .query = .{} },
|
|
},
|
|
},
|
|
else => [_]TestTarget{
|
|
TestTarget{ .query = .{} },
|
|
},
|
|
};
|
|
|
|
fn computeTestTargets(isNative: bool, ci: ?bool) ?[]const TestTarget {
|
|
if (ci != null and ci.?) return &ci_targets;
|
|
|
|
if (isNative) {
|
|
// If the target is native we assume the user didn't change it with -Dtarget and run all test targets.
|
|
return &all_test_targets;
|
|
}
|
|
|
|
// Otherwise we run a single test target.
|
|
return null;
|
|
}
|
|
|
|
// This creates a SQLite static library from the SQLite dependency code.
|
|
fn makeSQLiteLib(b: *std.Build, dep: *std.Build.Dependency, c_flags: []const []const u8, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, sqlite_c: enum { with, without }) *std.Build.Step.Compile {
|
|
const mod = b.addModule("lib-sqlite", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
.link_libc = true,
|
|
});
|
|
const lib = b.addLibrary(.{
|
|
.name = "sqlite",
|
|
.linkage = .static,
|
|
.root_module = mod,
|
|
});
|
|
|
|
mod.addIncludePath(dep.path("."));
|
|
mod.addIncludePath(b.path("c"));
|
|
if (sqlite_c == .with) {
|
|
mod.addCSourceFile(.{
|
|
.file = dep.path("sqlite3.c"),
|
|
.flags = c_flags,
|
|
});
|
|
}
|
|
mod.addCSourceFile(.{
|
|
.file = b.path("c/workaround.c"),
|
|
.flags = c_flags,
|
|
});
|
|
|
|
return lib;
|
|
}
|
|
|
|
pub fn build(b: *std.Build) !void {
|
|
const in_memory = b.option(bool, "in_memory", "Should the tests run with sqlite in memory (default true)") orelse true;
|
|
const dbfile = b.option([]const u8, "dbfile", "Always use this database file instead of a temporary one");
|
|
const ci = b.option(bool, "ci", "Build and test in the CI on GitHub");
|
|
|
|
const query = b.standardTargetOptionsQueryOnly(.{});
|
|
const target = b.resolveTargetQuery(query);
|
|
const optimize = b.standardOptimizeOption(.{});
|
|
|
|
// Upstream dependency
|
|
const sqlite_dep = b.dependency("sqlite", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
});
|
|
|
|
// Define C flags to use
|
|
|
|
var flags: std.ArrayList([]const u8) = .empty;
|
|
defer flags.deinit(b.allocator);
|
|
try flags.append(b.allocator, "-std=c99");
|
|
|
|
inline for (std.meta.fields(EnableOptions)) |field| {
|
|
const opt = b.option(bool, field.name, "Enable " ++ field.name) orelse field.defaultValue().?;
|
|
|
|
if (opt) {
|
|
var buf: [field.name.len]u8 = undefined;
|
|
const name = std.ascii.upperString(&buf, field.name);
|
|
const flag = try std.fmt.allocPrint(b.allocator, "-DSQLITE_ENABLE_{s}", .{name});
|
|
|
|
try flags.append(b.allocator, flag);
|
|
}
|
|
}
|
|
|
|
const c_flags = flags.items;
|
|
|
|
//
|
|
// Main library and module
|
|
//
|
|
|
|
// const sqlite_lib, const sqlite_mod = blk: {
|
|
const sqlite_lib, _ = blk: {
|
|
const lib = makeSQLiteLib(b, sqlite_dep, c_flags, target, optimize, .with);
|
|
|
|
const mod = b.addModule("sqlite", .{
|
|
.root_source_file = b.path("sqlite.zig"),
|
|
.link_libc = true,
|
|
});
|
|
mod.addIncludePath(b.path("c"));
|
|
mod.addIncludePath(sqlite_dep.path("."));
|
|
mod.linkLibrary(lib);
|
|
|
|
break :blk .{ lib, mod };
|
|
};
|
|
b.installArtifact(sqlite_lib);
|
|
|
|
// const sqliteext_mod = blk: {
|
|
_ = blk: {
|
|
const lib = makeSQLiteLib(b, sqlite_dep, c_flags, target, optimize, .without);
|
|
|
|
const mod = b.addModule("sqliteext", .{
|
|
.root_source_file = b.path("sqlite.zig"),
|
|
.link_libc = true,
|
|
});
|
|
mod.addIncludePath(b.path("c"));
|
|
mod.linkLibrary(lib);
|
|
|
|
break :blk mod;
|
|
};
|
|
|
|
//
|
|
// Tests
|
|
//
|
|
|
|
const test_targets = computeTestTargets(query.isNative(), ci) orelse &[_]TestTarget{.{
|
|
.query = query,
|
|
}};
|
|
const test_step = b.step("test", "Run library tests");
|
|
|
|
// By default the tests will only be execute for native test targets, however they will be compiled
|
|
// for _all_ targets defined in `test_targets`.
|
|
//
|
|
// If you want to execute tests for other targets you can pass -fqemu, -fdarling, -fwine, -frosetta.
|
|
|
|
for (test_targets) |test_target| {
|
|
const cross_target = getTarget(b.resolveTargetQuery(test_target.query));
|
|
const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
|
|
const test_name = b.fmt("{s}-{s}-{s}", .{
|
|
try cross_target.result.zigTriple(b.allocator),
|
|
@tagName(optimize),
|
|
single_threaded_txt,
|
|
});
|
|
|
|
const test_sqlite_lib = makeSQLiteLib(b, sqlite_dep, c_flags, cross_target, optimize, .with);
|
|
|
|
const mod = b.addModule(test_name, .{
|
|
.target = cross_target,
|
|
.optimize = optimize,
|
|
.root_source_file = b.path("sqlite.zig"),
|
|
.single_threaded = test_target.single_threaded,
|
|
});
|
|
|
|
const tests = b.addTest(.{
|
|
.name = test_name,
|
|
.root_module = mod,
|
|
});
|
|
tests.root_module.addIncludePath(b.path("c"));
|
|
tests.root_module.addIncludePath(sqlite_dep.path("."));
|
|
tests.root_module.linkLibrary(test_sqlite_lib);
|
|
|
|
const tests_options = b.addOptions();
|
|
tests.root_module.addImport("build_options", tests_options.createModule());
|
|
|
|
tests_options.addOption(bool, "in_memory", in_memory);
|
|
tests_options.addOption(?[]const u8, "dbfile", dbfile);
|
|
|
|
const run_tests = b.addRunArtifact(tests);
|
|
test_step.dependOn(&run_tests.step);
|
|
}
|
|
|
|
// This builds an example shared library with the extension and a binary that tests it.
|
|
|
|
//\ const zigcrypto_install_artifact = addZigcrypto(b, sqliteext_mod, target, optimize);
|
|
//\ test_step.dependOn(&zigcrypto_install_artifact.step);
|
|
//\ const zigcrypto_test_run = addZigcryptoTestRun(b, sqlite_mod, target, optimize);
|
|
//\ zigcrypto_test_run.step.dependOn(&zigcrypto_install_artifact.step);
|
|
//\ test_step.dependOn(&zigcrypto_test_run.step);
|
|
|
|
//
|
|
// Tools
|
|
//
|
|
|
|
addPreprocessStep(b, sqlite_dep);
|
|
}
|
|
|
|
fn addPreprocessStep(b: *std.Build, sqlite_dep: *std.Build.Dependency) void {
|
|
var wf = b.addWriteFiles();
|
|
|
|
// Preprocessing step
|
|
const preprocess = PreprocessStep.create(b, .{
|
|
.source = sqlite_dep.path("."),
|
|
.target = wf.getDirectory(),
|
|
});
|
|
preprocess.step.dependOn(&wf.step);
|
|
|
|
const w = b.addUpdateSourceFiles();
|
|
w.addCopyFileToSource(preprocess.target.join(b.allocator, "loadable-ext-sqlite3.h") catch @panic("OOM"), "c/loadable-ext-sqlite3.h");
|
|
w.addCopyFileToSource(preprocess.target.join(b.allocator, "loadable-ext-sqlite3ext.h") catch @panic("OOM"), "c/loadable-ext-sqlite3ext.h");
|
|
w.step.dependOn(&preprocess.step);
|
|
|
|
const preprocess_headers = b.step("preprocess-headers", "Preprocess the headers for the loadable extensions");
|
|
preprocess_headers.dependOn(&w.step);
|
|
}
|
|
|
|
fn addZigcrypto(b: *std.Build, sqlite_mod: *std.Build.Module, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.InstallArtifact {
|
|
const mod = b.addModule("zigcryto", .{
|
|
.root_source_file = b.path("examples/zigcrypto.zig"),
|
|
.target = getTarget(target),
|
|
.optimize = optimize,
|
|
});
|
|
const exe = b.addLibrary(.{
|
|
.name = "zigcrypto",
|
|
.root_module = mod,
|
|
.version = null,
|
|
.linkage = .dynamic,
|
|
});
|
|
exe.root_module.addImport("sqlite", sqlite_mod);
|
|
|
|
const install_artifact = b.addInstallArtifact(exe, .{});
|
|
install_artifact.step.dependOn(&exe.step);
|
|
|
|
return install_artifact;
|
|
}
|
|
|
|
fn addZigcryptoTestRun(b: *std.Build, sqlite_mod: *std.Build.Module, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.Run {
|
|
const mod = b.addModule("zigcryto-test", .{
|
|
.root_source_file = b.path("examples/zigcrypto_test.zig"),
|
|
.target = getTarget(target),
|
|
.optimize = optimize,
|
|
});
|
|
const zigcrypto_test = b.addExecutable(.{
|
|
.name = "zigcrypto-test",
|
|
.root_module = mod,
|
|
});
|
|
zigcrypto_test.root_module.addImport("sqlite", sqlite_mod);
|
|
|
|
const install = b.addInstallArtifact(zigcrypto_test, .{});
|
|
install.step.dependOn(&zigcrypto_test.step);
|
|
|
|
const run = b.addRunArtifact(zigcrypto_test);
|
|
run.step.dependOn(&zigcrypto_test.step);
|
|
|
|
return run;
|
|
}
|
|
|
|
// See https://www.sqlite.org/compile.html for flags
|
|
const EnableOptions = struct {
|
|
// https://www.sqlite.org/fts5.html
|
|
fts5: bool = false,
|
|
};
|
|
|
|
const PreprocessStep = struct {
|
|
const Config = struct {
|
|
source: std.Build.LazyPath,
|
|
target: std.Build.LazyPath,
|
|
};
|
|
|
|
step: std.Build.Step,
|
|
|
|
source: std.Build.LazyPath,
|
|
target: std.Build.LazyPath,
|
|
|
|
fn create(owner: *std.Build, config: Config) *PreprocessStep {
|
|
const step = owner.allocator.create(PreprocessStep) catch @panic("OOM");
|
|
step.* = .{
|
|
.step = std.Build.Step.init(.{
|
|
.id = std.Build.Step.Id.custom,
|
|
.name = "preprocess",
|
|
.owner = owner,
|
|
.makeFn = make,
|
|
}),
|
|
.source = config.source,
|
|
.target = config.target,
|
|
};
|
|
|
|
return step;
|
|
}
|
|
|
|
fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void {
|
|
const ps: *PreprocessStep = @fieldParentPtr("step", step);
|
|
const owner = step.owner;
|
|
|
|
const sqlite3_h = try ps.source.path(owner, "sqlite3.h").getPath3(owner, step).toString(owner.allocator);
|
|
const sqlite3ext_h = try ps.source.path(owner, "sqlite3ext.h").getPath3(owner, step).toString(owner.allocator);
|
|
|
|
const loadable_sqlite3_h = try ps.target.path(owner, "loadable-ext-sqlite3.h").getPath3(owner, step).toString(owner.allocator);
|
|
const loadable_sqlite3ext_h = try ps.target.path(owner, "loadable-ext-sqlite3ext.h").getPath3(owner, step).toString(owner.allocator);
|
|
|
|
var threaded: std.Io.Threaded = .init_single_threaded;
|
|
const io = threaded.io();
|
|
try Preprocessor.sqlite3(io, owner.allocator, sqlite3_h, loadable_sqlite3_h);
|
|
try Preprocessor.sqlite3ext(io, owner.allocator, sqlite3ext_h, loadable_sqlite3ext_h);
|
|
}
|
|
};
|