Author:ptrace
Comitter:ptrace
Date:2025-11-04 12:38:08 UTC
diff --git a/README.md b/README.md
index 1ff3b29..d0f1f41 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,31 @@ Smol program that creates some basic files and folders for Jai development.
Adapt it to your own needs.
## Build
```plain
$ jai -version
Version: beta 0.2.018, built on 11 October 2025.
```
```plain
$ jai jinit.jai
```
## Usage
- `jai jinit.jai`
- add the binary to your $PATH or symlink it where appropriate
- `$ jinit -help` for available args
## Templates
You can create multiple `build.jai` templates and invoke them with args.
For example, there's a template inside `jinit.jai` called `CONTENT_BUILD_VARIANT_MINIMAL`,
it contains a very small `build.jai` script.
You can create it with `jinit -v1`.
You can also add own templates:
- create a new multiline string that contains your build template
- inside the struct `Arguments`, add a new argument
- inside the proc `create_files()`, add it to the `if args` construct
- optionally, define a default template by adapting the constant `DEFAULT_CONTENT_BUILD_FILE`
diff --git a/jinit.jai b/jinit.jai
index e26e156..ecd1c30 100755
--- a/jinit.jai
+++ b/jinit.jai
@@ -16,6 +16,11 @@ OTHER_EMPTY_FILES :: string.[
"README.md",
];
// You can choose between multiple template via CLI args.
// But you can also set a default template here.
DEFAULT_CONTENT_BUILD_FILE :: CONTENT_BUILD_VARIANT_MINIMAL;
CONTENT_GIT_IGNORE :: #string END
# Jai
.build
@@ -23,47 +28,15 @@ bin
*.codex
END;
CONTENT_MAIN_JAI :: #string END
#import "Basic";
main :: () {
print("Hello, Sailor!\n");
}
END;
CONTENT_BUILD_JAI :: #string END
#import "Basic";
#import "Compiler";
#import "File";
build :: () {
w := compiler_create_workspace();
if !w {
print("Workspace creation failed.\n");
return;
}
print("The workspace w is %\n", w);
make_directory_if_it_does_not_exist("bin");
target_options := get_build_options(w);
target_options.output_executable_name = "program";
target_options.output_path = "bin";
//import_path: [..] string;
//array_add(*import_path, ..target_options.import_path);
//array_add(*import_path, "modules");
//target_options.import_path = import_path;
set_build_options_dc(.{do_output = false});
set_build_options(target_options, w);
add_build_file(tprint("%src/main.jai", #filepath), w);
}
main :: () {}
#run build();
END;
@@ -80,8 +53,8 @@ create_git_project :: (root_fp: string, args: Arguments) {
);
if process_result.exit_code != 0 {
if error_str print("Error: %\n", error_str);
if output_str print("Error: %\n", output_str);
if error_str log("Error: %", error_str);
if output_str log("Error: %", output_str);
exit(1);
}
}
@@ -89,7 +62,7 @@ create_git_project :: (root_fp: string, args: Arguments) {
create_directories :: (root_fp: string) {
for FP_SRC_DIR {
if String.starts_with(it, "/") {
print("Are you sure you want to create it at the root dir? Input: %\n", it);
log("Are you sure you want to create it at the root dir? Input: %", it);
exit(1);
}
File.make_directory_if_it_does_not_exist(tprint("%/%", root_fp, it));
@@ -97,9 +70,12 @@ create_directories :: (root_fp: string) {
}
create_file :: (fp: string, content: string = "") {
if FileUtils.file_exists(fp) return;
if FileUtils.file_exists(fp) {
log("[Info]: The file '%' already exists.", fp);
return;
}
if !File.write_entire_file(fp, content) {
print("Cannot create or write into file: '%'\n", fp);
log("Cannot create or write into file: %", fp);
exit(1);
}
}
@@ -108,8 +84,17 @@ create_files :: (root_fp: string, args: Arguments) {
fp_entrypoint := tprint("%/%", root_fp, JAI_ENTRYPOINT);
fp_jai_build := tprint("%/%", root_fp, JAI_BUILD);
fp_gitignore := tprint("%/%", root_fp, GIT_IGNORE);
content_build_file := DEFAULT_CONTENT_BUILD_FILE;
if args.v1 {
content_build_file = CONTENT_BUILD_VARIANT_MINIMAL;
} else if args.v2 {
content_build_file = CONTENT_BUILD_VARIANT_WITH_ARGS;
}
create_file(fp_entrypoint, CONTENT_MAIN_JAI);
create_file(fp_jai_build, CONTENT_BUILD_JAI);
create_file(fp_jai_build, content_build_file);
if !args.g {
create_file(fp_gitignore, CONTENT_GIT_IGNORE);
@@ -120,8 +105,11 @@ create_files :: (root_fp: string, args: Arguments) {
}
}
Arguments :: struct {
g: bool; @"?If provided, no Git repository and .gitignore file will be created."
g: bool; @"?If provided, no Git repository and .gitignore file will be created"
v1: bool; @"?Creates a minimal build.jai script"
v2: bool; @"?a build.jai script with more features (Args support, release builds, ...)"
}
@@ -129,17 +117,177 @@ main :: () {
success, args, is_set := Cli.parse_arguments(Arguments);
if !success {
log("[Error]: Cannot parse arguments");
exit(1);
}
current_path := get_working_directory();
if !current_path {
print("Cannot resolve root path\n");
log("Cannot resolve project path");
exit(1);
}
create_directories(current_path);
create_files(current_path, args);
create_git_project(current_path, args);
print("[Jai Init]: Done\n");
log("[Jai Init]: Done");
}
// --------------------------------------
// Build Templates
// ---------------
CONTENT_BUILD_VARIANT_MINIMAL :: #string _JINIT_END_
#import "Basic";
#import "Compiler";
#import "File";
build :: () {
w := compiler_create_workspace();
if !w {
print("Workspace creation failed.\n");
return;
}
print("The workspace w is %\n", w);
make_directory_if_it_does_not_exist("bin");
target_options := get_build_options(w);
target_options.output_executable_name = "program";
target_options.output_path = "bin";
//import_path: [..] string;
//array_add(*import_path, ..target_options.import_path);
//array_add(*import_path, "modules");
//target_options.import_path = import_path;
set_build_options_dc(.{do_output = false});
set_build_options(target_options, w);
add_build_file(tprint("%src/main.jai", #filepath), w);
}
main :: () {}
#run build();
_JINIT_END_;
CONTENT_BUILD_VARIANT_WITH_ARGS :: #string _JINIT_END_
#import "Basic";
#import "Compiler";
#import "File";
#import "Autorun";
build :: () {
args := get_build_options().compile_time_command_line;
// args
args_help := array_find(args, "help");
args_compiler_silent := array_find(args, "silent");
args_program_run := array_find(args, "run");
args_build_release := array_find(args, "release");
// -----------------------------------------
w := compiler_create_workspace();
if !w {
log("Workspace creation failed.");
return;
}
set_build_options_dc(.{ do_output = false });
if args_help {
args_help_print();
return;
}
print("The workspace w is %\n", w);
make_directory_if_it_does_not_exist("bin");
target_options := get_build_options(w);
target_options.output_executable_name = "program";
target_options.output_path = "bin";
if args_compiler_silent target_options.text_output_flags = 0;
if args_build_release {
build_release(w, *target_options);
} else {
build_debug(w, *target_options);
}
compiler_begin_intercept(w);
add_build_file(tprint("%src/main.jai", #filepath), w);
jinit_compiler_response := jinit_compiler_intercept();
compiler_end_intercept(w);
if !jinit_compiler_response {
log("Compiler response failed.");
return;
}
if args_program_run run_build_result(w);
}
// adapted from: https://github.com/Ivo-Balbaert/The_Way_to_Jai/blob/main/book/30B_Manipulating_the_build_process.md
build_debug :: (w: Workspace, target_options: *Build_Options) {
log("Choosing debug options...");
target_options.backend =.X64;
set_optimization(target_options, Optimization_Type.DEBUG, true);
set_build_options(target_options.*, w);
}
build_release :: (w: Workspace, target_options: *Build_Options) {
log("Choosing release options...");
target_options.backend = .LLVM;
set_optimization(target_options, Optimization_Type.VERY_OPTIMIZED);
set_build_options(target_options.*, w);
}
args_help_print :: () {
help_message := #string _END_
Usage: jai build.jai - [ARGS]
Options:
help Prints this help menu
silent Disables compiler/linker statistics
run Runs your program afterwards
release Builds with release options. If omitted, it builds a debug build.
_END_;
log(help_message);
}
jinit_compiler_intercept :: () -> success: bool {
while true {
message := compiler_wait_for_message();
if !message break;
if message.kind == {
case .COMPLETE;
message_complete := cast(*Message_Complete) message;
return message_complete.error_code == 0;
}
}
return false;
}
main :: () {}
#run build();
_JINIT_END_