diff --git a/README.md b/README.md index 715e608..6aa6d79 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ The plan is to support releases once Zig 1.0 is released but this can still chan - [User defined SQL functions](#user-defined-sql-functions) - [Scalar functions](#scalar-functions) - [Aggregate functions](#aggregate-functions) +- [Setting Compile-time Options](#setting-compile-time-options) # Requirements @@ -88,6 +89,9 @@ const sqlite = b.dependency("sqlite", .{ exe.root_module.addImport("sqlite", sqlite.module("sqlite")); ``` +If you'd like to use specific features that can only be accessed by setting +compile-time options (like FTS5, R*Tree), you can define them here as build options. See [Setting Compile-time Options](#setting-compile-time-options) for instructions. + # Usage ## Demo @@ -650,3 +654,39 @@ The `finalize` function is called once at the end. The context (2nd argument of `createAggregateFunction`) can be whatever you want; both the `step` and `finalize` functions must have their first argument of the same type as the context. + +# Setting Compile-time Options + +SQLite compile-time options are added as build options for customizing the SQLite source code. + +```zig +// This is an example of a recommended config. +const sqlite = b.dependency("sqlite", .{ + .target = target, + .optimize = optimize, + .default_memstatus = 0, + .omit_deprecated = true, + .DQS = 0, + .null_trim = true, + .like_doesnt_match_blobs = true, + .omit_shared_cache = true, + .omit_autoinit = true, + .default_wal_synchronous = 1, + .strict_subtype = optimize == .Debug, + .api_armor = optimize == .Debug, + .max_expr_depth = if (optimize != .Debug) 0 else 1000, + .use_alloca = switch(target.result.os.tag) { + .linux, .windows => true, + else => false, + }, +}); +``` + +The options are shortened for easier reading. You can check them by running `zig build --help` in this project. Mostly they follow the rules below. + +- Upper-cases are converted into lower-cases, unless the word is already shortened, like "DQS" for "double-quoted strings" +- `SQLITE_ENABLE_` is trimmed. For example, `SQLITE_ENABLE_API_ARMOR` translates to `api_armor`. +- Otherwise, `SQLITE_` is trimmed. For example, `SQLITE_ZERO_MALLOC` translates to `zero_malloc`. +- If the option doesn't receive argument, or receives 0 or 1, it's defined as `bool`. + - If the option only accepts `1`, it's defined as `u1`; a int must be used as the argument. +- "Not recommended", "No-op" and "Deprecated" options are not added as build options. diff --git a/build.zig b/build.zig index df19ff6..6062b36 100644 --- a/build.zig +++ b/build.zig @@ -173,6 +173,43 @@ pub fn build(b: *std.Build) !void { } } + inline for (std.meta.fields(BoolFeatureOptions)) |field| { + comptime var buf: [field.name.len]u8 = undefined; + const name = comptime std.ascii.upperString(&buf, field.name); + const opt = b.option(bool, field.name, "Set SQLITE_" ++ name); + + if (opt) |v| { + const flag_value = if (v) "1" else "0"; + const flag = try std.fmt.allocPrint(b.allocator, "-DSQLITE_" ++ name ++ "={s}", .{flag_value}); + + try flags.append(b.allocator, flag); + } + } + + inline for (std.meta.fields(DefineFeatureOptions)) |field| { + comptime var buf: [field.name.len]u8 = undefined; + const name = comptime std.ascii.upperString(&buf, field.name); + const opt = b.option(bool, field.name, "Set SQLITE_" ++ name) orelse false; + + if (opt) { + const flag = try std.fmt.allocPrint(b.allocator, "-DSQLITE_" ++ name, .{}); + + try flags.append(b.allocator, flag); + } + } + + inline for (std.meta.fields(IntFeatureOptions)) |field| { + comptime var buf: [field.name.len]u8 = undefined; + const name = comptime std.ascii.upperString(&buf, field.name); + const opt = b.option(field.type, field.name, "Set SQLITE_" ++ name); + + if (opt) |v| { + const flag = try std.fmt.allocPrint(b.allocator, "-DSQLITE_" ++ name ++ "={}", .{v}); + + try flags.append(b.allocator, flag); + } + } + const c_flags = flags.items; // @@ -337,8 +374,67 @@ fn addZigcryptoTestRun(b: *std.Build, sqlite_mod: *std.Build.Module, target: std // See https://www.sqlite.org/compile.html for flags const EnableOptions = struct { + api_armor: bool = false, + atomic_write: bool = false, + batch_atomic_write: bool = false, + carray: bool = false, + column_metadata: bool = false, + dbpage_vtab: bool = false, + dbstat_vtab: bool = false, + explain_comments: bool = false, // https://www.sqlite.org/fts5.html fts5: bool = false, + geopoly: bool = false, + hidden_columns: bool = false, + icu: bool = false, + math_functions: bool = false, + memsys3: bool = false, + memsys5: bool = false, + null_trim: bool = false, + offset_sql_func: bool = false, + percentile: bool = false, + preupdate_hook: bool = false, + RBU: bool = false, + rtree: bool = false, + session: bool = false, + sorter_reference: bool = false, + stmtvtab: bool = false, + stat4: bool = false, +}; + +/// `false` = won't be defined +/// `true` = will be defined +const DefineFeatureOptions = enum { + like_doesnt_match_blobs, + omit_decltype, + omit_deprecated, + omit_progress_callback, + omit_shared_cache, + omit_autoinit, + use_alloca, + zero_malloc, + debug, + memdebug, + win32_malloc, + win32_heap_create, + win32_malloc_validate, +}; + +/// - `null` = default +/// - `true` = `1` +/// - `false` = `0` +const BoolFeatureOptions = enum { + default_memstatus, + strict_subtype, + os_other, +}; + +/// The compile-time options with an int argument. +const IntFeatureOptions = struct { + DQS: std.math.IntFittingRange(0, 3), + threadsafe: std.math.IntFittingRange(0, 2), + default_wal_synchronous: std.math.IntFittingRange(0, 3), + max_expr_depth: c_int, }; const PreprocessStep = struct {