1pub fn build(b: *Build) !void {
2 const target = b.standardTargetOptions(.{});
3 const optimize = b.standardOptimizeOption(.{});
4
5 const pthread = WinPthreads.get(b, target, optimize);
6 const pthread_native = WinPthreads.get(b, b.graph.host, .Debug);
7
8 const src = b.dependency("quickjs", .{});
9
10 const version = std.mem.trim(
11 u8,
12 try src.builder.build_root.handle.readFileAlloc(b.graph.arena, "VERSION", 4096),
13 " \t\r\n",
14 );
15
16 const c_flags: []const []const u8 = &.{
17 "-Wall",
18 "-Wextra",
19 "-Wno-sign-compare",
20 "-Wno-missing-field-initializers",
21 "-Wundef",
22 "-Wuninitialized",
23 "-Wunused",
24 "-Wno-unused-parameter",
25 "-Wwrite-strings",
26 "-Wchar-subscripts",
27 "-funsigned-char",
28 "-fwrapv",
29 };
30
31 const defines: []const struct { name: []const u8, value: []const u8 } = &.{
32 .{ .name = "_GNU_SOURCE", .value = "1" },
33 .{ .name = "CONFIG_BIGNUM", .value = "1" },
34 .{ .name = "CONFIG_VERSION", .value = b.fmt("\"{s}\"", .{version}) },
35 };
36
37 const libquickjs = b.addStaticLibrary(.{
38 .name = "quickjs",
39 .target = target,
40 .optimize = optimize,
41 .link_libc = true,
42 });
43 pthread.configure(libquickjs);
44 libquickjs.addCSourceFiles(.{
45 .root = src.path(""),
46 .files = &.{
47 "quickjs.c",
48 "libregexp.c",
49 "libbf.c",
50 "libunicode.c",
51 "cutils.c",
52 },
53 .flags = c_flags,
54 });
55 for (defines) |def| {
56 libquickjs.root_module.addCMacro(def.name, def.value);
57 }
58
59 const libquickjs_libc = b.addStaticLibrary(.{
60 .name = "quickjs_libc",
61 .target = target,
62 .optimize = optimize,
63 .link_libc = true,
64 });
65 pthread.configure(libquickjs_libc);
66 libquickjs_libc.addCSourceFiles(.{
67 .root = src.path(""),
68 .files = &.{
69 "quickjs-libc.c",
70 },
71 .flags = c_flags,
72 });
73 for (defines) |def| {
74 libquickjs_libc.root_module.addCMacro(def.name, def.value);
75 }
76
77 const qjsc = b.addExecutable(.{
78 .name = "qjsc",
79 .target = b.graph.host,
80 .optimize = .Debug,
81 .link_libc = true,
82 });
83 pthread_native.configure(qjsc);
84 qjsc.addCSourceFiles(.{
85 .root = src.path(""),
86 .files = &.{
87 "qjsc.c",
88 "quickjs-libc.c",
89 "quickjs.c",
90 "libregexp.c",
91 "libbf.c",
92 "libunicode.c",
93 "cutils.c",
94 },
95 .flags = c_flags,
96 });
97 for (defines) |def| {
98 qjsc.root_module.addCMacro(def.name, def.value);
99 }
100
101 const qjs = b.addExecutable(.{
102 .name = "qjs",
103 .target = target,
104 .optimize = optimize,
105 .link_libc = true,
106 });
107 pthread.configure(qjs);
108 qjs.addCSourceFiles(.{
109 .root = src.path(""),
110 .files = &.{
111 "qjs.c",
112 },
113 .flags = c_flags,
114 });
115 qjs.root_module.addCSourceFile(.{
116 .file = runQjsc(b, qjsc, src.path("repl.js")),
117 .flags = c_flags,
118 });
119 qjs.root_module.addCSourceFile(.{
120 .file = runQjsc(b, qjsc, src.path("qjscalc.js")),
121 .flags = c_flags,
122 });
123 for (defines) |def| {
124 qjs.root_module.addCMacro(def.name, def.value);
125 }
126 qjs.linkLibrary(libquickjs);
127 qjs.linkLibrary(libquickjs_libc);
128
129 b.installArtifact(qjs);
130 b.installArtifact(libquickjs);
131 b.installArtifact(libquickjs_libc);
132
133 const translate = b.addTranslateC(.{
134 .root_source_file = src.path("quickjs.h"),
135 .target = target,
136 .optimize = optimize,
137 .link_libc = true,
138 });
139 if (pthread.pthreads) |pt| translate.addIncludePath(pt.include);
140 const module = translate.addModule("quickjs");
141 module.linkLibrary(libquickjs);
142
143 const translate_libc = b.addTranslateC(.{
144 .root_source_file = src.path("quickjs-libc.h"),
145 .target = target,
146 .optimize = optimize,
147 .link_libc = true,
148 });
149 const module2 = translate_libc.addModule("quickjs-libc");
150 if (pthread.pthreads) |pt| translate_libc.addIncludePath(pt.include);
151 module2.linkLibrary(libquickjs);
152 module2.linkLibrary(libquickjs_libc);
153}
154
155fn runQjsc(b: *Build, qjsc: *Build.Step.Compile, in: Build.LazyPath) Build.LazyPath {
156 const run = b.addRunArtifact(qjsc);
157 run.addArg("-c");
158 run.addArg("-fbignum");
159 run.addArg("-o");
160 const out = run.addOutputFileArg(b.fmt("{s}.c", .{in.getDisplayName()}));
161 run.addArg("-m");
162 run.addFileArg(in);
163 return out;
164}
165
166/// Zig doesnt include winpthreads, so it's built from source. This helper
167/// decides if it is needed, and provides a no-op `configure` function if it is
168/// not actually needed. Call .configure on any object files you need.
169const WinPthreads = struct {
170 pthreads: ?struct {
171 library: *Build.Step.Compile,
172 include: Build.LazyPath,
173 } = null,
174
175 pub fn get(
176 b: *Build,
177 target: Build.ResolvedTarget,
178 optimize: std.builtin.OptimizeMode,
179 ) WinPthreads {
180 if (target.result.os.tag == .windows) {
181 const dep = b.lazyDependency("mingw-w64", .{}) orelse
182 return .{};
183
184 const libpthread = b.addStaticLibrary(.{
185 .name = "winpthreads",
186 .target = target,
187 .optimize = optimize,
188 .link_libc = true,
189 });
190
191 libpthread.addCSourceFiles(.{
192 .root = dep.path("mingw-w64-libraries/winpthreads/src"),
193 .files = &.{
194 "barrier.c",
195 "clock.c",
196 "cond.c",
197 "misc.c",
198 "mutex.c",
199 "nanosleep.c",
200 "ref.c",
201 "rwlock.c",
202 "sched.c",
203 "sem.c",
204 "spinlock.c",
205 "thread.c",
206 },
207 });
208
209 libpthread.addIncludePath(dep.path("mingw-w64-libraries/winpthreads/include"));
210
211 return .{ .pthreads = .{
212 .library = libpthread,
213 .include = dep.path("mingw-w64-libraries/winpthreads/include"),
214 } };
215 }
216 return .{};
217 }
218
219 pub fn configure(this: WinPthreads, compile: *Build.Step.Compile) void {
220 if (this.pthreads) |pthreads| {
221 compile.linkLibrary(pthreads.library);
222 compile.addIncludePath(pthreads.include);
223 }
224 }
225};
226
227const std = @import("std");
228const Build = std.Build;