diff options
| author | 2025-01-12 18:31:10 +0100 | |
|---|---|---|
| committer | 2025-02-16 00:02:44 +0100 | |
| commit | 4a0483910c9752d69bbd91af1ab12a6443d3b0a6 (patch) | |
| tree | a0bcaee9d1b3f902f3b580210205ba6cd1f63515 /build.zig | |
| parent | Merge pull request #180 from nektro/patch-1 (diff) | |
| download | zig-sqlite-4a0483910c9752d69bbd91af1ab12a6443d3b0a6.tar.gz zig-sqlite-4a0483910c9752d69bbd91af1ab12a6443d3b0a6.tar.xz zig-sqlite-4a0483910c9752d69bbd91af1ab12a6443d3b0a6.zip | |
stop vendoring the sqlite C code, rework the build
* Use the zig package manager to fetch sqlite directly from upstream
* Integrate the preprocessing tool directly into the build script
This makes it simpler to upgrade the SQLite source code:
* use `zig fetch`
* run `zig build preprocess-headers`
Diffstat (limited to '')
| -rw-r--r-- | build.zig | 230 | ||||
| -rw-r--r-- | build.zig.zon | 8 |
2 files changed, 162 insertions, 76 deletions
| @@ -1,8 +1,12 @@ | |||
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const debug = std.debug; |
| 3 | const Step = std.Build.Step; | 3 | const heap = std.heap; |
| 4 | const mem = std.mem; | ||
| 4 | const ResolvedTarget = std.Build.ResolvedTarget; | 5 | const ResolvedTarget = std.Build.ResolvedTarget; |
| 5 | const Query = std.Target.Query; | 6 | const Query = std.Target.Query; |
| 7 | const builtin = @import("builtin"); | ||
| 8 | |||
| 9 | const Preprocessor = @import("build/Preprocessor.zig"); | ||
| 6 | 10 | ||
| 7 | fn getTarget(original_target: ResolvedTarget) ResolvedTarget { | 11 | fn getTarget(original_target: ResolvedTarget) ResolvedTarget { |
| 8 | var tmp = original_target; | 12 | var tmp = original_target; |
| @@ -104,6 +108,31 @@ fn computeTestTargets(isNative: bool, ci: ?bool) ?[]const TestTarget { | |||
| 104 | return null; | 108 | return null; |
| 105 | } | 109 | } |
| 106 | 110 | ||
| 111 | // This creates a SQLite static library from the SQLite dependency code. | ||
| 112 | 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 { | ||
| 113 | const lib = b.addStaticLibrary(.{ | ||
| 114 | .name = "sqlite", | ||
| 115 | .target = target, | ||
| 116 | .optimize = optimize, | ||
| 117 | }); | ||
| 118 | |||
| 119 | lib.addIncludePath(dep.path(".")); | ||
| 120 | lib.addIncludePath(b.path("c")); | ||
| 121 | if (sqlite_c == .with) { | ||
| 122 | lib.addCSourceFile(.{ | ||
| 123 | .file = dep.path("sqlite3.c"), | ||
| 124 | .flags = c_flags, | ||
| 125 | }); | ||
| 126 | } | ||
| 127 | lib.addCSourceFile(.{ | ||
| 128 | .file = b.path("c/workaround.c"), | ||
| 129 | .flags = c_flags, | ||
| 130 | }); | ||
| 131 | lib.linkLibC(); | ||
| 132 | |||
| 133 | return lib; | ||
| 134 | } | ||
| 135 | |||
| 107 | pub fn build(b: *std.Build) !void { | 136 | pub fn build(b: *std.Build) !void { |
| 108 | const in_memory = b.option(bool, "in_memory", "Should the tests run with sqlite in memory (default true)") orelse true; | 137 | const in_memory = b.option(bool, "in_memory", "Should the tests run with sqlite in memory (default true)") orelse true; |
| 109 | const dbfile = b.option([]const u8, "dbfile", "Always use this database file instead of a temporary one"); | 138 | const dbfile = b.option([]const u8, "dbfile", "Always use this database file instead of a temporary one"); |
| @@ -113,6 +142,14 @@ pub fn build(b: *std.Build) !void { | |||
| 113 | const target = b.resolveTargetQuery(query); | 142 | const target = b.resolveTargetQuery(query); |
| 114 | const optimize = b.standardOptimizeOption(.{}); | 143 | const optimize = b.standardOptimizeOption(.{}); |
| 115 | 144 | ||
| 145 | // Upstream dependency | ||
| 146 | const sqlite_dep = b.dependency("sqlite", .{ | ||
| 147 | .target = target, | ||
| 148 | .optimize = optimize, | ||
| 149 | }); | ||
| 150 | |||
| 151 | // Define C flags to use | ||
| 152 | |||
| 116 | var flags = std.ArrayList([]const u8).init(b.allocator); | 153 | var flags = std.ArrayList([]const u8).init(b.allocator); |
| 117 | defer flags.deinit(); | 154 | defer flags.deinit(); |
| 118 | try flags.append("-std=c99"); | 155 | try flags.append("-std=c99"); |
| @@ -131,50 +168,41 @@ pub fn build(b: *std.Build) !void { | |||
| 131 | 168 | ||
| 132 | const c_flags = flags.items; | 169 | const c_flags = flags.items; |
| 133 | 170 | ||
| 134 | const sqlite_lib = b.addStaticLibrary(.{ | 171 | // |
| 135 | .name = "sqlite", | 172 | // Main library and module |
| 136 | .target = target, | 173 | // |
| 137 | .optimize = optimize, | ||
| 138 | }); | ||
| 139 | 174 | ||
| 140 | sqlite_lib.addIncludePath(b.path("c/")); | 175 | const sqlite_lib, const sqlite_mod = blk: { |
| 141 | sqlite_lib.addCSourceFiles(.{ | 176 | const lib = makeSQLiteLib(b, sqlite_dep, c_flags, target, optimize, .with); |
| 142 | .files = &[_][]const u8{ | ||
| 143 | "c/sqlite3.c", | ||
| 144 | "c/workaround.c", | ||
| 145 | }, | ||
| 146 | .flags = c_flags, | ||
| 147 | }); | ||
| 148 | sqlite_lib.linkLibC(); | ||
| 149 | sqlite_lib.installHeader(b.path("c/sqlite3.h"), "sqlite3.h"); | ||
| 150 | 177 | ||
| 151 | b.installArtifact(sqlite_lib); | 178 | const mod = b.addModule("sqlite", .{ |
| 179 | .root_source_file = b.path("sqlite.zig"), | ||
| 180 | .link_libc = true, | ||
| 181 | }); | ||
| 182 | mod.addIncludePath(b.path("c")); | ||
| 183 | mod.addIncludePath(sqlite_dep.path(".")); | ||
| 184 | mod.linkLibrary(lib); | ||
| 152 | 185 | ||
| 153 | // Create the public 'sqlite' module to be exported | 186 | break :blk .{ lib, mod }; |
| 154 | const sqlite_mod = b.addModule("sqlite", .{ | 187 | }; |
| 155 | .root_source_file = b.path("sqlite.zig"), | 188 | _ = sqlite_lib; |
| 156 | .link_libc = true, | ||
| 157 | }); | ||
| 158 | sqlite_mod.addIncludePath(b.path("c/")); | ||
| 159 | sqlite_mod.linkLibrary(sqlite_lib); | ||
| 160 | 189 | ||
| 161 | // Tool to preprocess the sqlite header files. | 190 | const sqliteext_mod = blk: { |
| 162 | // | 191 | const lib = makeSQLiteLib(b, sqlite_dep, c_flags, target, optimize, .without); |
| 163 | // Due to limitations of translate-c the standard header files can't be used for building loadable extensions | ||
| 164 | // so we have this tool which creates usable header files. | ||
| 165 | 192 | ||
| 166 | const preprocess_files_tool = b.addExecutable(.{ | 193 | const mod = b.addModule("sqliteext", .{ |
| 167 | .name = "preprocess-files", | 194 | .root_source_file = b.path("sqlite.zig"), |
| 168 | .root_source_file = b.path("tools/preprocess_files.zig"), | 195 | .link_libc = true, |
| 169 | .target = getTarget(target), | 196 | }); |
| 170 | .optimize = optimize, | 197 | mod.addIncludePath(b.path("c")); |
| 171 | }); | 198 | mod.linkLibrary(lib); |
| 172 | 199 | ||
| 173 | // Add a top-level step to run the preprocess-files tool | 200 | break :blk mod; |
| 174 | const preprocess_files_run = b.step("preprocess-files", "Run the preprocess-files tool"); | 201 | }; |
| 175 | 202 | ||
| 176 | const preprocess_files_tool_run = b.addRunArtifact(preprocess_files_tool); | 203 | // |
| 177 | preprocess_files_run.dependOn(&preprocess_files_tool_run.step); | 204 | // Tests |
| 205 | // | ||
| 178 | 206 | ||
| 179 | const test_targets = computeTestTargets(query.isNative(), ci) orelse &[_]TestTarget{.{ | 207 | const test_targets = computeTestTargets(query.isNative(), ci) orelse &[_]TestTarget{.{ |
| 180 | .query = query, | 208 | .query = query, |
| @@ -195,19 +223,7 @@ pub fn build(b: *std.Build) !void { | |||
| 195 | single_threaded_txt, | 223 | single_threaded_txt, |
| 196 | }); | 224 | }); |
| 197 | 225 | ||
| 198 | const test_sqlite_lib = b.addStaticLibrary(.{ | 226 | const test_sqlite_lib = makeSQLiteLib(b, sqlite_dep, c_flags, cross_target, optimize, .with); |
| 199 | .name = "sqlite", | ||
| 200 | .target = cross_target, | ||
| 201 | .optimize = optimize, | ||
| 202 | }); | ||
| 203 | test_sqlite_lib.addCSourceFiles(.{ | ||
| 204 | .files = &[_][]const u8{ | ||
| 205 | "c/sqlite3.c", | ||
| 206 | "c/workaround.c", | ||
| 207 | }, | ||
| 208 | .flags = c_flags, | ||
| 209 | }); | ||
| 210 | test_sqlite_lib.linkLibC(); | ||
| 211 | 227 | ||
| 212 | const tests = b.addTest(.{ | 228 | const tests = b.addTest(.{ |
| 213 | .name = test_name, | 229 | .name = test_name, |
| @@ -217,6 +233,7 @@ pub fn build(b: *std.Build) !void { | |||
| 217 | .single_threaded = test_target.single_threaded, | 233 | .single_threaded = test_target.single_threaded, |
| 218 | }); | 234 | }); |
| 219 | tests.addIncludePath(b.path("c")); | 235 | tests.addIncludePath(b.path("c")); |
| 236 | tests.addIncludePath(sqlite_dep.path(".")); | ||
| 220 | tests.linkLibrary(test_sqlite_lib); | 237 | tests.linkLibrary(test_sqlite_lib); |
| 221 | 238 | ||
| 222 | const tests_options = b.addOptions(); | 239 | const tests_options = b.addOptions(); |
| @@ -229,51 +246,72 @@ pub fn build(b: *std.Build) !void { | |||
| 229 | test_step.dependOn(&run_tests.step); | 246 | test_step.dependOn(&run_tests.step); |
| 230 | } | 247 | } |
| 231 | 248 | ||
| 232 | const lib = b.addStaticLibrary(.{ | 249 | // This builds an example shared library with the extension and a binary that tests it. |
| 233 | .name = "sqlite", | 250 | |
| 234 | .target = getTarget(target), | 251 | const zigcrypto_install_artifact = addZigcrypto(b, sqliteext_mod, target, optimize); |
| 235 | .optimize = optimize, | 252 | test_step.dependOn(&zigcrypto_install_artifact.step); |
| 236 | }); | 253 | |
| 237 | lib.addCSourceFile(.{ .file = b.path("c/sqlite3.c"), .flags = c_flags }); | 254 | const zigcrypto_test_run = addZigcryptoTestRun(b, sqlite_mod, target, optimize); |
| 238 | lib.addIncludePath(b.path("c")); | 255 | test_step.dependOn(&zigcrypto_test_run.step); |
| 239 | lib.linkLibC(); | ||
| 240 | 256 | ||
| 241 | // | 257 | // |
| 242 | // Examples | 258 | // Tools |
| 243 | // | 259 | // |
| 244 | 260 | ||
| 245 | // Loadable extension | 261 | addPreprocessStep(b, sqlite_dep); |
| 246 | // | 262 | } |
| 247 | // This builds an example shared library with the extension and a binary that tests it. | 263 | |
| 264 | fn addPreprocessStep(b: *std.Build, sqlite_dep: *std.Build.Dependency) void { | ||
| 265 | var wf = b.addWriteFiles(); | ||
| 266 | |||
| 267 | // Preprocessing step | ||
| 268 | const preprocess = PreprocessStep.create(b, .{ | ||
| 269 | .source = sqlite_dep.path("."), | ||
| 270 | .target = wf.getDirectory(), | ||
| 271 | }); | ||
| 272 | preprocess.step.dependOn(&wf.step); | ||
| 273 | |||
| 274 | const w = b.addUpdateSourceFiles(); | ||
| 275 | w.addCopyFileToSource(preprocess.target.join(b.allocator, "loadable-ext-sqlite3.h") catch @panic("OOM"), "c/loadable-ext-sqlite3.h"); | ||
| 276 | w.addCopyFileToSource(preprocess.target.join(b.allocator, "loadable-ext-sqlite3ext.h") catch @panic("OOM"), "c/loadable-ext-sqlite3ext.h"); | ||
| 277 | w.step.dependOn(&preprocess.step); | ||
| 248 | 278 | ||
| 249 | const zigcrypto_loadable_ext = b.addSharedLibrary(.{ | 279 | const preprocess_headers = b.step("preprocess-headers", "Preprocess the headers for the loadable extensions"); |
| 280 | preprocess_headers.dependOn(&w.step); | ||
| 281 | } | ||
| 282 | |||
| 283 | fn addZigcrypto(b: *std.Build, sqlite_mod: *std.Build.Module, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.InstallArtifact { | ||
| 284 | const exe = b.addSharedLibrary(.{ | ||
| 250 | .name = "zigcrypto", | 285 | .name = "zigcrypto", |
| 251 | .root_source_file = b.path("examples/zigcrypto.zig"), | 286 | .root_source_file = b.path("examples/zigcrypto.zig"), |
| 252 | .version = null, | 287 | .version = null, |
| 253 | .target = getTarget(target), | 288 | .target = getTarget(target), |
| 254 | .optimize = optimize, | 289 | .optimize = optimize, |
| 255 | }); | 290 | }); |
| 256 | zigcrypto_loadable_ext.addIncludePath(b.path("c")); | 291 | exe.root_module.addImport("sqlite", sqlite_mod); |
| 257 | zigcrypto_loadable_ext.root_module.addImport("sqlite", sqlite_mod); | ||
| 258 | zigcrypto_loadable_ext.linkLibrary(lib); | ||
| 259 | 292 | ||
| 260 | const install_zigcrypto_loadable_ext = b.addInstallArtifact(zigcrypto_loadable_ext, .{}); | 293 | const install_artifact = b.addInstallArtifact(exe, .{}); |
| 294 | install_artifact.step.dependOn(&exe.step); | ||
| 261 | 295 | ||
| 296 | return install_artifact; | ||
| 297 | } | ||
| 298 | |||
| 299 | fn addZigcryptoTestRun(b: *std.Build, sqlite_mod: *std.Build.Module, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.Run { | ||
| 262 | const zigcrypto_test = b.addExecutable(.{ | 300 | const zigcrypto_test = b.addExecutable(.{ |
| 263 | .name = "zigcrypto-test", | 301 | .name = "zigcrypto-test", |
| 264 | .root_source_file = b.path("examples/zigcrypto_test.zig"), | 302 | .root_source_file = b.path("examples/zigcrypto_test.zig"), |
| 265 | .target = getTarget(target), | 303 | .target = getTarget(target), |
| 266 | .optimize = optimize, | 304 | .optimize = optimize, |
| 267 | }); | 305 | }); |
| 268 | zigcrypto_test.addIncludePath(b.path("c")); | ||
| 269 | zigcrypto_test.root_module.addImport("sqlite", sqlite_mod); | 306 | zigcrypto_test.root_module.addImport("sqlite", sqlite_mod); |
| 270 | zigcrypto_test.linkLibrary(lib); | ||
| 271 | 307 | ||
| 272 | const install_zigcrypto_test = b.addInstallArtifact(zigcrypto_test, .{}); | 308 | const install = b.addInstallArtifact(zigcrypto_test, .{}); |
| 309 | install.step.dependOn(&zigcrypto_test.step); | ||
| 310 | |||
| 311 | const run = b.addRunArtifact(zigcrypto_test); | ||
| 312 | run.step.dependOn(&zigcrypto_test.step); | ||
| 273 | 313 | ||
| 274 | const zigcrypto_compile_run = b.step("zigcrypto", "Build the 'zigcrypto' SQLite loadable extension"); | 314 | return run; |
| 275 | zigcrypto_compile_run.dependOn(&install_zigcrypto_loadable_ext.step); | ||
| 276 | zigcrypto_compile_run.dependOn(&install_zigcrypto_test.step); | ||
| 277 | } | 315 | } |
| 278 | 316 | ||
| 279 | // See https://www.sqlite.org/compile.html for flags | 317 | // See https://www.sqlite.org/compile.html for flags |
| @@ -281,3 +319,45 @@ const EnableOptions = struct { | |||
| 281 | // https://www.sqlite.org/fts5.html | 319 | // https://www.sqlite.org/fts5.html |
| 282 | fts5: bool = false, | 320 | fts5: bool = false, |
| 283 | }; | 321 | }; |
| 322 | |||
| 323 | const PreprocessStep = struct { | ||
| 324 | const Config = struct { | ||
| 325 | source: std.Build.LazyPath, | ||
| 326 | target: std.Build.LazyPath, | ||
| 327 | }; | ||
| 328 | |||
| 329 | step: std.Build.Step, | ||
| 330 | |||
| 331 | source: std.Build.LazyPath, | ||
| 332 | target: std.Build.LazyPath, | ||
| 333 | |||
| 334 | fn create(owner: *std.Build, config: Config) *PreprocessStep { | ||
| 335 | const step = owner.allocator.create(PreprocessStep) catch @panic("OOM"); | ||
| 336 | step.* = .{ | ||
| 337 | .step = std.Build.Step.init(.{ | ||
| 338 | .id = std.Build.Step.Id.custom, | ||
| 339 | .name = "preprocess", | ||
| 340 | .owner = owner, | ||
| 341 | .makeFn = make, | ||
| 342 | }), | ||
| 343 | .source = config.source, | ||
| 344 | .target = config.target, | ||
| 345 | }; | ||
| 346 | |||
| 347 | return step; | ||
| 348 | } | ||
| 349 | |||
| 350 | fn make(step: *std.Build.Step, _: std.Build.Step.MakeOptions) !void { | ||
| 351 | const ps: *PreprocessStep = @fieldParentPtr("step", step); | ||
| 352 | const owner = step.owner; | ||
| 353 | |||
| 354 | const sqlite3_h = try ps.source.path(owner, "sqlite3.h").getPath3(owner, step).toString(owner.allocator); | ||
| 355 | const sqlite3ext_h = try ps.source.path(owner, "sqlite3ext.h").getPath3(owner, step).toString(owner.allocator); | ||
| 356 | |||
| 357 | const loadable_sqlite3_h = try ps.target.path(owner, "loadable-ext-sqlite3.h").getPath3(owner, step).toString(owner.allocator); | ||
| 358 | const loadable_sqlite3ext_h = try ps.target.path(owner, "loadable-ext-sqlite3ext.h").getPath3(owner, step).toString(owner.allocator); | ||
| 359 | |||
| 360 | try Preprocessor.sqlite3(owner.allocator, sqlite3_h, loadable_sqlite3_h); | ||
| 361 | try Preprocessor.sqlite3ext(owner.allocator, sqlite3ext_h, loadable_sqlite3ext_h); | ||
| 362 | } | ||
| 363 | }; | ||
diff --git a/build.zig.zon b/build.zig.zon index edf75fe..3513d15 100644 --- a/build.zig.zon +++ b/build.zig.zon | |||
| @@ -1,5 +1,11 @@ | |||
| 1 | .{ | 1 | .{ |
| 2 | .name = "sqlite", | 2 | .name = "sqlite", |
| 3 | .version = "3.47.2", | 3 | .version = "3.48.0", |
| 4 | .dependencies = .{ | ||
| 5 | .sqlite = .{ | ||
| 6 | .url = "https://sqlite.org/2025/sqlite-amalgamation-3480000.zip", | ||
| 7 | .hash = "1220972595d70da33d69d519392742482cb9762935cecb99924e31f3898d2a330861", | ||
| 8 | }, | ||
| 9 | }, | ||
| 4 | .paths = .{"."}, | 10 | .paths = .{"."}, |
| 5 | } | 11 | } |