Logo

index : blog

---

  • summary
  • about
  • tree
  • log
  • branches
<< path: root/public/blog.git/html/build.jai blob: 3af44725300c96cea70141cbcf6b08abd36cf4e0 [raw] [clear marker]

        
0#import "Basic";
1#import "Compiler";
2#import "File";
3#import "Process";
4#import "Autorun";
5
6
7#placeholder MEMORY_DEBUGGER_ENABLED;
8#placeholder IS_DEVELOPER;
9#placeholder IS_UA_ALLOCATOR;
10
11
12program_args: [..]string;
13
14/** TODO: Different parsing regime.
15 This is very ugly to maintain, maybe we just use `Command_Line` here.
16*/
17args_help: bool;
18args_compiler_silent: bool;
19args_program_run: bool;
20args_build_release: bool;
21args_build_lib: bool;
22args_memory_debug: bool;
23args_dev_server: bool;
24args_dev_server_only: bool;
25args_gen: bool;
26args_search: bool;
27args_fuzz_request: bool;
28args_fuzz_e2e: bool;
29args_fuzzer: bool;
30args_tests: bool;
31args_um_alloc: bool;
32
33
34build :: () {
35 args := get_build_options().compile_time_command_line;
36
37 // args
38 args_help = array_find(args, "help");
39 args_compiler_silent = array_find(args, "silent");
40 args_program_run = array_find(args, "run");
41 args_build_release = array_find(args, "release");
42 args_build_lib = array_find(args, "lib");
43 args_memory_debug = array_find(args, "memory");
44 args_dev_server = array_find(args, "server");
45 args_dev_server_only = array_find(args, "oserver");
46 args_gen = array_find(args, "gen");
47 args_search = array_find(args, "search");
48 args_fuzz_request = array_find(args, "request");
49 args_fuzz_e2e = array_find(args, "e2e");
50 args_fuzzer = array_find(args, "fuzzer");
51 args_tests = array_find(args, "tests");
52 args_um_alloc = array_find(args, "unmap");
53
54
55 // program args
56 program_args = program_args_collect(args); // @OS GC
57
58 // -----------------------------------------
59
60 prog_gen := compiler_create_workspace();
61 if !prog_gen {
62 log("Workspace creation failed: Gen");
63 return;
64 }
65
66 prog_search := compiler_create_workspace();
67 if !prog_search {
68 log("Workspace creation failed: Search");
69 return;
70 }
71
72 prog_fuzzer := compiler_create_workspace();
73 if !prog_fuzzer {
74 log("Workspace creation failed: Fuzzer");
75 return;
76 }
77
78 prog_tests := compiler_create_workspace();
79 if !prog_tests {
80 log("Workspace creation failed: Tests");
81 return;
82 }
83
84 prog_store := compiler_create_workspace();
85 if !prog_store {
86 log("Workspace creation failed: store");
87 return;
88 }
89
90
91 set_build_options_dc(.{ do_output = false });
92
93 if args_help {
94 args_help_print();
95 return;
96 }
97
98 if args_dev_server || args_dev_server_only {
99 dev_server_run();
100 if args_dev_server_only return;
101 }
102
103 make_directory_if_it_does_not_exist("bin");
104 make_directory_if_it_does_not_exist("bin/debug");
105 make_directory_if_it_does_not_exist("bin/release");
106 make_directory_if_it_does_not_exist("bin/lib");
107
108 if args_fuzzer {
109 if args_search {
110 corpus_dir :: "fuzzer/corpus_search/";
111 code :: #code {
112 add_build_file(tprint("%src/fuzzer/fuzzer_search.jai", #filepath), w);
113 }
114
115 fuzzer_run_pipeline(prog_fuzzer, "fuzzer_search", corpus_dir, intercept=code);
116 }
117 else if args_fuzz_request {
118 corpus_dir :: "fuzzer/corpus_request/";
119 code :: #code {
120 add_build_file(tprint("%src/fuzzer/fuzzer_request.jai", #filepath), w);
121 }
122
123 fuzzer_run_pipeline(prog_fuzzer, "fuzzer_request", corpus_dir, intercept=code);
124 }
125 else if args_fuzz_e2e {
126 corpus_dir :: "fuzzer/corpus_e2e/";
127 code :: #code {
128 add_build_file(tprint("%src/fuzzer/fuzzer_e2e.jai", #filepath), w);
129 }
130
131 fuzzer_run_pipeline(prog_fuzzer, "fuzzer_e2e", corpus_dir, intercept=code);
132 }
133 }
134 else if args_gen {
135 workspace_setup(prog_gen, "generator", #code {
136 add_build_file(tprint("%src/gen/main.jai", #filepath), w);
137 add_build_string(
138 tprint("MEMORY_DEBUGGER_ENABLED :: %;", args_memory_debug), w
139 );
140 });
141 }
142 else if args_search {
143 workspace_setup(prog_search, "search", #code {
144 add_build_file(tprint("%src/search/main.jai", #filepath), w);
145 add_build_string(
146 tprint("MEMORY_DEBUGGER_ENABLED :: %;", args_memory_debug), w
147 );
148 });
149 }
150 else if args_tests {
151 workspace_setup(prog_tests, "tests", #code {
152 add_build_file(tprint("%tests/main.jai", #filepath), w);
153 });
154 }
155}
156
157build_debug :: (w: Workspace, target_options: *Build_Options) {
158 log("Choosing debug options ...");
159 target_options.backend =.X64;
160 target_options.output_path = "bin/debug";
161 set_optimization(target_options, Optimization_Type.DEBUG, true);
162 set_build_options(target_options.*, w);
163}
164
165build_release :: (w: Workspace, target_options: *Build_Options) {
166 log("Choosing release options ...");
167 target_options.backend = .LLVM;
168 target_options.output_path = "bin/release";
169 target_options.stack_trace = false;
170 target_options.backtrace_on_crash = .OFF;
171 target_options.emit_debug_info = .DEFAULT;
172 set_optimization(target_options, Optimization_Type.VERY_OPTIMIZED);
173 set_build_options(target_options.*, w);
174}
175
176build_lib_static :: (w: Workspace, target_options: *Build_Options) {
177 log("Choosing dyn lib options ...");
178 target_options.backend = .LLVM;
179 target_options.output_type = .DYNAMIC_LIBRARY;
180 target_options.output_path = "bin/lib";
181 set_optimization(target_options, Optimization_Type.VERY_OPTIMIZED);
182 set_build_options(target_options.*, w);
183}
184
185workspace_setup :: (w: Workspace, program_name: string, $intercept: Code) #expand {
186 print("The workspace w is %\n", w);
187 target_options := get_build_options(w);
188 target_options.output_executable_name = program_name;
189
190 if args_compiler_silent target_options.text_output_flags = 0;
191
192 if args_build_release {
193 build_release(w, *target_options);
194 }
195 else if args_build_lib {
196 build_lib_static(w, *target_options);
197 }
198 else {
199 build_debug(w, *target_options);
200 }
201
202 compiler_begin_intercept(w);
203
204 #insert,scope() intercept;
205
206 if args_build_release {
207 add_build_string("IS_DEVELOPER :: false;", w);
208 } else {
209 add_build_string("IS_DEVELOPER :: true;", w);
210 }
211
212 if args_um_alloc {
213 add_build_string("IS_UA_ALLOCATOR :: true;", w);
214 } else {
215 add_build_string("IS_UA_ALLOCATOR :: false;", w);
216 }
217
218 compiler_response := message_loop();
219 compiler_end_intercept(w);
220
221 if !compiler_response {
222 log("Compiler response failed.");
223 return;
224 }
225
226 if args_program_run run_build_result_of_workspace(w, program_args);
227}
228
229dev_server_run :: () {
230 cmd :: string.[ "python", "dev/server.py" ];
231 run_command(..cmd);
232}
233
234fuzzer_run_pipeline :: (
235 w: Workspace,
236 program_name: string,
237 corpus_dir: string,
238 runs := 1_000_000,
239 $intercept: Code
240) {
241 log("The workspace w is %", w);
242 target_options := get_build_options(w);
243 target_options.output_executable_name = program_name;
244 target_options.text_output_flags = 0;
245
246 fp_exec := tprint("fuzzer/%", program_name);
247
248 build_lib_static(w, *target_options);
249 compiler_begin_intercept(w);
250
251 #insert,scope() intercept;
252
253 compiler_response := message_loop();
254 compiler_end_intercept(w);
255
256 if !compiler_response {
257 log("Compiler response failed.");
258 return;
259 }
260
261 log("Building fuzzer via clang ...");
262 clang_cmd := string.[
263 "clang++",
264 "-fsanitize=fuzzer,address",
265 tprint("bin/lib/%.so", program_name),
266 "-o",
267 fp_exec
268 ];
269 run_command(..clang_cmd);
270
271 fuzz_cmd := string.[
272 fp_exec,
273 tprint("-runs=%", runs),
274 "-max_total_time=60",
275 "-rss_limit_mb=512",
276 "-max_total_time=60",
277 "-artifact_prefix=fuzzer/",
278 corpus_dir
279 ];
280 if args_program_run then run_command(..fuzz_cmd);
281}
282
283program_args_collect :: (args: []string, divider: string = "::") -> [..]string {
284 buf: [..]string;
285
286 success, match := array_find(args, divider);
287 if success for i: match+1..args.count-1 array_add(*buf, args[i]);
288
289 return buf;
290}
291
292message_loop :: () -> ok: bool {
293 while true {
294 message := compiler_wait_for_message();
295 if !message break;
296 if message.kind == {
297 case .COMPLETE;
298 message_complete := cast(*Message_Complete) message;
299 return message_complete.error_code == 0;
300 }
301 }
302 return false;
303}
304
305args_help_print :: () {
306 help_message :: #string _END_
307Usage: jai build.jai - [OPTIONS] :: [PROGRAM ARGS]
308
309Options:
310 help Prints this help menu.
311 silent Disables compiler/linker statistics.
312 run Runs your program afterwards.
313 release Builds with release options. If omitted, it builds a debug build.
314 memory Enables the memory leak detector.
315
316Passing Args to your Program:
317 If you want to supply args to your program, pass it like that:
318
319 `jai build.jai - run :: my_arg1 foo bar abc ABC`
320
321 Everything after the `::` get's forwarded to your program.
322
323_END_;
324 log(help_message);
325}
326
327main :: () {}
328
329#run build();
330
331
Copyright 2026  E766CB298A6D1E64 | Git-Thing heavily inspired by cgit