Skip to content

Instantly share code, notes, and snippets.

@dbechrd
Created July 3, 2026 22:24
Show Gist options
  • Select an option

  • Save dbechrd/05d5bda0cafaa824ce1d91b70469fd9b to your computer and use it in GitHub Desktop.

Select an option

Save dbechrd/05d5bda0cafaa824ce1d91b70469fd9b to your computer and use it in GitHub Desktop.
Firebrick build.jai
SRC_MAIN :: "src/main.jai"; // main file to build
EXE_NAME :: "firebrick"; // required
ICO_FILE :: "icon.ico"; // set to "" to disable
IMPORT_DIR :: "../jai-modules"; // this should probably be an array heh
IPROF :: false; // enable on-screen performance profiler
PERF_REPORT :: false; // print perf report in build output
VERBOSE :: false; // log debug info during build (apparently options.verbose is not a thing that works, mailed this)
#run,stallable build();
build :: () {
context.print_style.default_format_struct.use_long_form_if_more_than_this_many_members = -1;
context.print_style.default_format_struct.use_newlines_if_long_form = true;
w := compiler_create_workspace("Target Program (via build.jai)");
args := get_build_options(w).compile_time_command_line;
options := get_build_options(w);
copy_commonly_propagated_fields(get_build_options(), *options);
#if VERBOSE {
log("args: %", args);
}
success, plugins_to_create := parse_plugin_arguments(args);
if !success {
log_error("Failed to parse plugin arguments.\n");
exit(1);
}
// Only Default_Metaprogram should load the Jails plugin
for * plugins_to_create {
if it.name == "jails_diagnostics" {
remove it;
break;
}
}
#if VERBOSE {
log("plugins_to_create: %", plugins_to_create);
}
array_add(*plugins_to_create, .{name="Check"});
#if ICO_FILE {
// image_to_ico("icon.png", "icon.ico");
icon_options: [..] string;
array_copy(*icon_options, .["-icon", ICO_FILE]);
array_add(*plugins_to_create, .{"Icon", icon_options});
}
#if IPROF {
iprof_options: [..] string;
array_copy(*iprof_options, .[
"-modules",
// "-min_size", "10" // default is 30
]);
array_add(*plugins_to_create, .{"Iprof", iprof_options});
}
#if PERF_REPORT {
perf_options: [..] string;
array_add(*plugins_to_create, .{"Performance_Report", perf_options});
}
// Now that we know what the plugins are, init them.
success = init_plugins(plugins_to_create, *plugins, w);
if !success {
log_error("A plugin init() failed. Exiting.\n");
exit(0);
}
set_working_directory(#filepath);
modules_paths: [..] string;
array_add(*modules_paths, IMPORT_DIR);
array_add(*modules_paths, ..options.import_path);
options.import_path = modules_paths;
options.output_path = "bin";
options.output_executable_name = EXE_NAME;
// MUST be used with LLVM back-end (i.e. MUST NOT pass '-x64' )
// MUST be used in release mode (i.e. MUST pass '-release')
options.llvm_options.command_line = string.[
"anything.exe", // your .exe name (can be any string as far as i can tell)
// "-version", // display LLVM version info
// "--help-list-hidden", // show advanced LLVM help
// "--pass-remarks=.*", // dump info about all optimizations
// "--pass-remarks-missed=.*", // dump info about missed optimizations
// "--pass-remarks-analysis=.*", // honestly idk what this is.. a bunch of info about spills and alignment
// "--debug-pass=Arguments", // Various LLVM pass reports that work
// "--debug-pass=Structure", // Various LLVM pass reports that work
// "--debug-pass=Executions", // Various LLVM pass reports that work
// "--debug-pass=Details", // Various LLVM pass reports that work
];
set_build_options(options, w);
set_build_options_dc(.{do_output=false, write_added_strings=false});
#if VERBOSE {
print("build_options: %\n", options);
}
intercept_flags: Intercept_Flags;
for plugins if it.before_intercept it.before_intercept(it, *intercept_flags);
compiler_begin_intercept(w, intercept_flags);
for plugins if it.add_source it.add_source(it);
#if IPROF {
add_build_string("IPROF :: true;\n", w);
} else {
add_build_string("IPROF :: false;\n", w);
}
add_build_file(SRC_MAIN, w);
message_loop(w);
compiler_end_intercept(w);
for plugins if it.finish it.finish (it);
for plugins if it.shutdown it.shutdown(it);
}
message_loop :: (w: Workspace) {
decls_by_module: Table(string, [..] *Code_Declaration);
while true {
message := compiler_wait_for_message();
for plugins if it.message it.message(it, message);
if message.kind == {
case .COMPLETE; break;
case .IMPORT;
#if VERBOSE {
import := cast(*Message_Import) message;
print("Import: '%'\n", import.module_name);
}
case .FILE;
#if VERBOSE {
file := cast(*Message_File) message;
print("File: '%'\n", file.fully_pathed_filename);
}
// case .PHASE;
// phase := cast(*Message_Phase) message;
// case .TYPECHECKED;
// tc := cast(*Message_Typechecked) message;
// for tc_decl: tc.declarations {
// decl := tc_decl.expression;
// }
}
}
builder: String_Builder;
for module_decls, module_name: decls_by_module {
print_to_builder(*builder, "%\n", ifx module_name else "[Application]");
for module_decls {
print_to_builder(*builder, " %\n", it.name);
}
}
log("%", builder_to_string(*builder));
}
plugins: [..] *Metaprogram_Plugin;
#import "Basic";
#import "Compiler";
#import "Metaprogram_Plugins";
#import "Hash_Table";
#import "String";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment