375 lines
12 KiB
Zig
375 lines
12 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
|
|
var sqlite3: ?*std.Build.Step.Compile = null;
|
|
|
|
fn linkSqlite(b: *std.Build.Step.Compile) void {
|
|
if (sqlite3) |lib| {
|
|
b.linkLibrary(lib);
|
|
} else {
|
|
b.linkLibC();
|
|
b.linkSystemLibrary("sqlite3");
|
|
}
|
|
}
|
|
|
|
fn getTarget(original_target: std.zig.CrossTarget, bundled: bool) std.zig.CrossTarget {
|
|
if (bundled) {
|
|
var tmp = original_target;
|
|
|
|
if (tmp.isGnuLibC()) {
|
|
const min_glibc_version = std.builtin.Version{
|
|
.major = 2,
|
|
.minor = 28,
|
|
.patch = 0,
|
|
};
|
|
if (tmp.glibc_version) |ver| {
|
|
if (ver.order(min_glibc_version) == .lt) {
|
|
std.debug.panic("sqlite requires glibc version >= 2.28", .{});
|
|
}
|
|
} else {
|
|
tmp.setGnuLibCVersion(2, 28, 0);
|
|
}
|
|
}
|
|
|
|
return tmp;
|
|
}
|
|
|
|
return original_target;
|
|
}
|
|
|
|
const TestTarget = struct {
|
|
target: std.zig.CrossTarget = @as(std.zig.CrossTarget, .{}),
|
|
single_threaded: bool = false,
|
|
bundled: bool,
|
|
};
|
|
|
|
const all_test_targets = switch (builtin.target.cpu.arch) {
|
|
.x86_64 => switch (builtin.target.os.tag) {
|
|
.linux => [_]TestTarget{
|
|
// Targets linux but other CPU archs.
|
|
TestTarget{
|
|
.target = .{},
|
|
.bundled = false,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86_64,
|
|
.abi = .musl,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86,
|
|
.abi = .musl,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .aarch64,
|
|
.abi = .musl,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .riscv64,
|
|
.abi = .musl,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .mips,
|
|
.abi = .musl,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
// TODO(vincent): failing for some time for unknown reasons
|
|
// TestTarget{
|
|
// .target = .{
|
|
// .cpu_arch = .arm,
|
|
// .abi = .musleabihf,
|
|
// },
|
|
// .bundled = true,
|
|
// },
|
|
// Targets windows
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86_64,
|
|
.os_tag = .windows,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86,
|
|
.os_tag = .windows,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
// Targets macOS
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86_64,
|
|
.os_tag = .macos,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .aarch64,
|
|
.os_tag = .macos,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
},
|
|
.windows => [_]TestTarget{
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86_64,
|
|
.abi = .gnu,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86,
|
|
.abi = .gnu,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
},
|
|
.freebsd => [_]TestTarget{
|
|
TestTarget{
|
|
.target = .{},
|
|
.bundled = false,
|
|
},
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86_64,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
},
|
|
.macos => [_]TestTarget{
|
|
TestTarget{
|
|
.target = .{
|
|
.cpu_arch = .x86_64,
|
|
},
|
|
.bundled = true,
|
|
},
|
|
},
|
|
else => [_]TestTarget{
|
|
TestTarget{
|
|
.target = .{},
|
|
.bundled = false,
|
|
},
|
|
},
|
|
},
|
|
else => [_]TestTarget{
|
|
TestTarget{
|
|
.target = .{},
|
|
.bundled = false,
|
|
},
|
|
},
|
|
};
|
|
|
|
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 use_bundled = b.option(bool, "use_bundled", "Use the bundled sqlite3 source instead of linking the system library (default false)");
|
|
|
|
const target = b.standardTargetOptions(.{});
|
|
const optimize = b.standardOptimizeOption(.{});
|
|
|
|
// Tool to preprocess the sqlite header files.
|
|
//
|
|
// Due to limitations of translate-c the standard header files can't be used for building loadable extensions
|
|
// so we have this tool which creates usable header files.
|
|
|
|
const preprocess_files_tool = b.addExecutable(.{
|
|
.name = "preprocess-files",
|
|
.root_source_file = .{ .path = "tools/preprocess_files.zig" },
|
|
.target = getTarget(target, true),
|
|
.optimize = optimize,
|
|
});
|
|
|
|
// Add a top-level step to run the preprocess-files tool
|
|
const preprocess_files_run = b.step("preprocess-files", "Run the preprocess-files tool");
|
|
|
|
const preprocess_files_tool_run = b.addRunArtifact(preprocess_files_tool);
|
|
preprocess_files_run.dependOn(&preprocess_files_tool_run.step);
|
|
|
|
// If the target is native we assume the user didn't change it with -Dtarget and run all test targets.
|
|
// Otherwise we run a single test target.
|
|
const test_targets = if (target.isNative())
|
|
&all_test_targets
|
|
else
|
|
&[_]TestTarget{.{
|
|
.target = target,
|
|
.bundled = use_bundled orelse false,
|
|
}};
|
|
|
|
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 bundled = use_bundled orelse test_target.bundled;
|
|
const cross_target = getTarget(test_target.target, bundled);
|
|
const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
|
|
const test_name = b.fmt("{s}-{s}-{s}", .{
|
|
try cross_target.zigTriple(b.allocator),
|
|
@tagName(optimize),
|
|
single_threaded_txt,
|
|
});
|
|
|
|
const tests = b.addTest(.{
|
|
.name = test_name,
|
|
.target = cross_target,
|
|
.optimize = optimize,
|
|
.root_source_file = .{ .path = "sqlite.zig" },
|
|
.single_threaded = test_target.single_threaded,
|
|
});
|
|
|
|
if (bundled) {
|
|
const lib = b.addStaticLibrary(.{
|
|
.name = "sqlite",
|
|
.target = cross_target,
|
|
.optimize = optimize,
|
|
});
|
|
lib.addCSourceFile("c/sqlite3.c", &[_][]const u8{"-std=c99"});
|
|
lib.linkLibC();
|
|
sqlite3 = lib;
|
|
}
|
|
|
|
if (bundled) tests.addIncludePath("c");
|
|
linkSqlite(tests);
|
|
|
|
const lib = b.addStaticLibrary(.{
|
|
.name = "zig-sqlite",
|
|
.root_source_file = .{ .path = "sqlite.zig" },
|
|
.target = cross_target,
|
|
.optimize = optimize,
|
|
});
|
|
if (bundled) lib.addIncludePath("c");
|
|
linkSqlite(lib);
|
|
|
|
const tests_options = b.addOptions();
|
|
tests.addOptions("build_options", tests_options);
|
|
|
|
tests_options.addOption(bool, "in_memory", in_memory);
|
|
tests_options.addOption(?[]const u8, "dbfile", dbfile);
|
|
|
|
test_step.dependOn(&tests.step);
|
|
}
|
|
|
|
// Fuzzing
|
|
|
|
const lib = b.addStaticLibrary(.{
|
|
.name = "sqlite",
|
|
.target = getTarget(target, true),
|
|
.optimize = optimize,
|
|
});
|
|
lib.addCSourceFile("c/sqlite3.c", &[_][]const u8{"-std=c99"});
|
|
lib.addIncludePath("c");
|
|
lib.linkLibC();
|
|
|
|
// The library
|
|
const fuzz_lib = b.addStaticLibrary(.{
|
|
.name = "fuzz-lib",
|
|
.root_source_file = .{ .path = "fuzz/main.zig" },
|
|
.target = getTarget(target, true),
|
|
.optimize = optimize,
|
|
});
|
|
fuzz_lib.addIncludePath("c");
|
|
fuzz_lib.linkLibrary(lib);
|
|
fuzz_lib.want_lto = true;
|
|
fuzz_lib.bundle_compiler_rt = true;
|
|
fuzz_lib.addAnonymousModule("sqlite", .{
|
|
.source_file = .{ .path = "sqlite.zig" },
|
|
});
|
|
|
|
// Setup the output name
|
|
const fuzz_executable_name = "fuzz";
|
|
const fuzz_exe_path = try b.cache_root.join(b.allocator, &.{fuzz_executable_name});
|
|
|
|
// We want `afl-clang-lto -o path/to/output path/to/library`
|
|
const fuzz_compile = b.addSystemCommand(&.{ "afl-clang-lto", "-o", fuzz_exe_path });
|
|
fuzz_compile.addArtifactArg(lib);
|
|
fuzz_compile.addArtifactArg(fuzz_lib);
|
|
|
|
// Install the cached output to the install 'bin' path
|
|
const fuzz_install = b.addInstallBinFile(.{ .path = fuzz_exe_path }, fuzz_executable_name);
|
|
|
|
// Add a top-level step that compiles and installs the fuzz executable
|
|
const fuzz_compile_run = b.step("fuzz", "Build executable for fuzz testing using afl-clang-lto");
|
|
// fuzz_compile_run.dependOn(&fuzz_lib.step);
|
|
fuzz_compile_run.dependOn(&fuzz_compile.step);
|
|
fuzz_compile_run.dependOn(&fuzz_install.step);
|
|
|
|
// Compile a companion exe for debugging crashes
|
|
const fuzz_debug_exe = b.addExecutable(.{
|
|
.name = "fuzz-debug",
|
|
.root_source_file = .{ .path = "fuzz/main.zig" },
|
|
.target = getTarget(target, true),
|
|
.optimize = optimize,
|
|
});
|
|
fuzz_debug_exe.addIncludePath("c");
|
|
fuzz_debug_exe.linkLibrary(lib);
|
|
fuzz_debug_exe.addAnonymousModule("sqlite", .{
|
|
.source_file = .{ .path = "sqlite.zig" },
|
|
});
|
|
|
|
// Only install fuzz-debug when the fuzz step is run
|
|
const install_fuzz_debug_exe = b.addInstallArtifact(fuzz_debug_exe);
|
|
fuzz_compile_run.dependOn(&install_fuzz_debug_exe.step);
|
|
|
|
//
|
|
// Examples
|
|
//
|
|
|
|
// Loadable extension
|
|
//
|
|
// This builds an example shared library with the extension and a binary that tests it.
|
|
|
|
const zigcrypto_loadable_ext = b.addSharedLibrary(.{
|
|
.name = "zigcrypto",
|
|
.root_source_file = .{ .path = "examples/zigcrypto.zig" },
|
|
.version = null,
|
|
.target = getTarget(target, true),
|
|
.optimize = optimize,
|
|
});
|
|
zigcrypto_loadable_ext.force_pic = true;
|
|
zigcrypto_loadable_ext.addIncludePath("c");
|
|
zigcrypto_loadable_ext.addAnonymousModule("sqlite", .{
|
|
.source_file = .{ .path = "sqlite.zig" },
|
|
});
|
|
zigcrypto_loadable_ext.linkLibrary(lib);
|
|
|
|
const install_zigcrypto_loadable_ext = b.addInstallArtifact(zigcrypto_loadable_ext);
|
|
|
|
const zigcrypto_test = b.addExecutable(.{
|
|
.name = "zigcrypto-test",
|
|
.root_source_file = .{ .path = "examples/zigcrypto_test.zig" },
|
|
.target = getTarget(target, true),
|
|
.optimize = optimize,
|
|
});
|
|
zigcrypto_test.addIncludePath("c");
|
|
zigcrypto_test.addAnonymousModule("sqlite", .{
|
|
.source_file = .{ .path = "sqlite.zig" },
|
|
});
|
|
zigcrypto_test.linkLibrary(lib);
|
|
|
|
const install_zigcrypto_test = b.addInstallArtifact(zigcrypto_test);
|
|
|
|
const zigcrypto_compile_run = b.step("zigcrypto", "Build the 'zigcrypto' SQLite loadable extension");
|
|
zigcrypto_compile_run.dependOn(&install_zigcrypto_loadable_ext.step);
|
|
zigcrypto_compile_run.dependOn(&install_zigcrypto_test.step);
|
|
}
|