summaryrefslogtreecommitdiff
path: root/build.zig
diff options
context:
space:
mode:
authorGravatar Vincent Rischmann2025-01-12 18:31:10 +0100
committerGravatar Vincent Rischmann2025-02-16 00:02:44 +0100
commit4a0483910c9752d69bbd91af1ab12a6443d3b0a6 (patch)
treea0bcaee9d1b3f902f3b580210205ba6cd1f63515 /build.zig
parentMerge pull request #180 from nektro/patch-1 (diff)
downloadzig-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 'build.zig')
-rw-r--r--build.zig230
1 files changed, 155 insertions, 75 deletions
diff --git a/build.zig b/build.zig
index 7833a54..964c89d 100644
--- a/build.zig
+++ b/build.zig
@@ -1,8 +1,12 @@
1const std = @import("std"); 1const std = @import("std");
2const builtin = @import("builtin"); 2const debug = std.debug;
3const Step = std.Build.Step; 3const heap = std.heap;
4const mem = std.mem;
4const ResolvedTarget = std.Build.ResolvedTarget; 5const ResolvedTarget = std.Build.ResolvedTarget;
5const Query = std.Target.Query; 6const Query = std.Target.Query;
7const builtin = @import("builtin");
8
9const Preprocessor = @import("build/Preprocessor.zig");
6 10
7fn getTarget(original_target: ResolvedTarget) ResolvedTarget { 11fn 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.
112fn 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
107pub fn build(b: *std.Build) !void { 136pub 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
264fn 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
283fn 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
299fn 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
323const 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};