#import "Basic"; #import "Compiler"; #import "File"; #import "File_Utilities"; #import "String"; #import "System"; #import "Process"; OUTPUT_EXECUTABLE_NAME_DESKTOP :: "mexplore"; SOURCE_ENTRY_POINT :: "src/main.jai"; DESKTOP_OS_BUILD_OUTPUT_PATH :: "bin"; #run Build_Project(); Build_Project :: () { // Get start time: // Compile prerequisites: set_build_options_dc(.{do_output=false}); args := get_build_options().compile_time_command_line; // Simplify targeting / command line interface? // [For now] assume x64 for Windows and Linux // Android defaults to ARM64, can be overriden with `x64`. `x64` is ignored on all other OS' target_windows = array_find(args, "windows"); target_linux = array_find(args, "linux"); target_macos = array_find(args, "macos"); target_x64 = array_find(args, "x64"); target_optimize = array_find(args, "release"); // NOTE(Charles): Proably makes sense to default os/cpu to OS/CPU then arguments override that. if target_windows { cpu_target = .X64; os_target = .WINDOWS; assert(os_target == OS); } else if target_linux { cpu_target = .X64; os_target = .LINUX; assert(os_target == OS); } else if target_macos { cpu_target = .ARM64; os_target = .MACOS; assert(os_target == OS); } else { assert(false, "Not a valid build configuration."); } set_working_directory(#filepath); compile_native_code(); // Also copies assets and libraries :ThisAintCompilingNativeCode! print("\n"); } compile_native_code :: () { VERSION :: "0.1"; JAI_VERSION := trim(compiler_get_version_info(null)); current_time := to_calendar(current_time_consensus(), .LOCAL); RELEASE_DATE := calendar_to_string(current_time); result, branch_name := run_command("git", "branch", "--show-current", capture_and_return_output = true); GIT_BRANCH := trim(branch_name); result=, revision := run_command("git", "rev-parse", "HEAD", capture_and_return_output = true); GIT_REVISION := trim(revision); log("Compiling for % %", os_target, cpu_target); start_time := GetUnixTimestamp(); defer log("Native code compilation time: %", GetUnixTimestamp()-start_time); // NOTE(Charles): The compiler already outputs this for us? build_output_directory: string; sdk_lib_path: string; android_main_directory: string; // #if OS != .MACOS { // target_triple, target_triple_with_sdk := get_android_target_triple(cpu_target); // if os_target == .ANDROID { // ndk := get_ndk_paths(); // sdk_lib_path = tprint("%/usr/lib/%", ndk.sysroot, target_triple); // // Create the library directory // android_main_directory = tprint("%/app/src/main", ANDROID_PROJECT_PATH); // assert(file_exists(android_main_directory)); // build_output_directory = tprint("%/jniLibs/%", android_main_directory, get_android_project_jni_architecture_name(cpu_target)); // make_directory_if_it_does_not_exist(build_output_directory, recursive = true); // } // } w := compiler_create_workspace("Target workspace"); options := get_build_options(w); copy_commonly_propagated_fields(get_build_options(), *options); options.cpu_target = cpu_target; options.os_target = os_target; if os_target == .WINDOWS || os_target == .LINUX || OS == .MACOS { if target_optimize { set_optimization(*options, .VERY_OPTIMIZED, preserve_debug_info=false); options.llvm_options.enable_split_modules = false; options.array_bounds_check = .OFF; options.null_pointer_check = .OFF; options.arithmetic_overflow_check = .OFF; options.cast_bounds_check = .OFF; options.output_executable_name = OUTPUT_EXECUTABLE_NAME_DESKTOP; } else { options.output_executable_name = tprint("%-debug", OUTPUT_EXECUTABLE_NAME_DESKTOP); } options.output_path = DESKTOP_OS_BUILD_OUTPUT_PATH; make_directory_if_it_does_not_exist(options.output_path, recursive=true); } import_path: [..] string; array_add(*import_path, "modules"); array_add(*import_path, ..options.import_path); options.import_path = import_path; if cpu_target == .ARM64 { options.backend = .LLVM; // Disable +lse for older ARM64 devices. // options.llvm_options.target_system_features = "+lse"; } set_build_options(options, w); compiler_begin_intercept(w); add_build_file(SOURCE_ENTRY_POINT, w); build_constants := tprint(#string STRING NAME :: "%"; VERSION :: "%"; JAI_VERSION :: "%"; RELEASE_DATE :: "%"; GIT_BRANCH :: "%"; GIT_REVISION :: "%"; DEBUG :: %; STRING, OUTPUT_EXECUTABLE_NAME_DESKTOP, VERSION, JAI_VERSION, RELEASE_DATE, GIT_BRANCH, GIT_REVISION, ifx target_optimize then "false" else "true", ); add_build_string(build_constants, w); while true { message := compiler_wait_for_message(); if message.kind == { case .PHASE; phase_message := cast(*Message_Phase) message; if phase_message.phase == .READY_FOR_CUSTOM_LINK_COMMAND { // #if OS != .MACOS { // run_android_link_command(phase_message, options, extra_args = .[ // tprint("-L%", sdk_lib_path), "-lc++"] // :AndroidStbImageThreadLocals // ); // } } case .ERROR; print("\n"); // Seems to be some issue with exit() not flushing output, we miss errors! exit(1); case .COMPLETE; break; } } compiler_end_intercept(w); // :ThisAintCompilingNativeCode! ASSETS :: string.[ // "extras/images/image_test.jpg", // "extras/fonts/JetBrainsMono-Regular.ttf", // "extras/fonts/RobotoMono-Regular.ttf", ]; if os_target == .WINDOWS { WINDOWS_LIBS :: string.[]; WINDOWS_LIBS_DEBUG :: string.[]; target_output_directory := tprint("%/bin", #filepath); make_directory_if_it_does_not_exist(options.output_path, recursive=true); for ASSETS { if !copy_file(it, tprint("%/%", target_output_directory, path_filename(it))) { compiler_report(tprint("Failed to copy file % to android project assets", it)); } } target_lib_array := ifx target_optimize then WINDOWS_LIBS else WINDOWS_LIBS_DEBUG; for target_lib_array { if !copy_file(it, tprint("%/%", target_output_directory, path_filename(it))) { compiler_report(tprint("Failed to copy file % to android project assets", it)); } } } if os_target == .LINUX { LINUX_LIBS :: string.[]; target_output_directory := tprint("%/bin", #filepath); make_directory_if_it_does_not_exist(options.output_path, recursive=true); for ASSETS { if !copy_file(it, tprint("%/%", target_output_directory, path_filename(it))) { compiler_report(tprint("Failed to copy file % to android project assets", it)); } } for LINUX_LIBS { if !copy_file(it, tprint("%/%", target_output_directory, path_filename(it))) { compiler_report(tprint("Failed to copy file % to android project assets", it)); } } } if os_target == .ANDROID { resources_output_directory := tprint("%/assets", android_main_directory); make_directory_if_it_does_not_exist(resources_output_directory, recursive = true); for ASSETS { if !copy_file(it, tprint("%/%", resources_output_directory, path_filename(it))) { compiler_report(tprint("Failed to copy file % to android project assets", it)); } } // #if OS != .MACOS { // // Package libc++ :AndroidStbImageThreadLocals // success := copy_android_libcpp(cpu_target, options.output_path); // if !success { // compiler_report(tprint("Could not copy Android libc++ to %", options.output_path)); // } // } } } // #if OS != .MACOS { // generate_android_project :: () { // GENERATE_ANDROID_FILES :: false; // if file_exists(ANDROID_PROJECT_PATH) && !GENERATE_ANDROID_FILES { // log("Project folder at %", ANDROID_PROJECT_PATH); // return; // } // log("Generating new project folder at %", ANDROID_PROJECT_PATH); // start_time := GetUnixTimestamp(); // config: Android_Project_Config; // config.project_path = ANDROID_PROJECT_PATH; // config.app_name = ANDROID_APP_NAME; // config.app_id = ANDROID_APP_ID; // config.android_gradle_plugin_version = "8.2.2"; // config.gradle_version = "8.6"; // config.lib_name = OUTPUT_EXECUTABLE_NAME_ANDROID; // // Hmmm. I wanna do portrait for phones and landscape for tablets, or allow the user to choose via device orientation. // // For now just roll with this. // config.screen_orientation = .PORTRAIT; // // config.screen_orientation = .LANDSCAPE; // if !generate_android_project(*config) { // compiler_report(tprint("Failed to create android project \"%\"", config.project_path)); // return; // } // log("Succesfully created or updated android project \"%\".", config.project_path); // log("Generate Android project time: %", GetUnixTimestamp()-start_time); // // NOTE(Charles): Android Icons! // // // // The apps icon is set with the icon attribute of application tag in manifest. This has to be set to a reference // // to a "drawable resource". This most direct way to do this is to put a png in the drawable directory, eg // // AndroidProject/app/src/main/res/drawable/my_icon.png. The attribute can then be set to // // android:icon="@drawable/my_icon". // // // // However, on my phone at least, this looks total ass. The image gets massively shrunk down and the rest of the // // icon is a white circle. Apparently this is because now android expects you to define "adaptive icons". Instead // // you now have to provide both a foreground and background image, and define your "image" in xml. So we now have // // two images drawable/icon_foreground.png, drawable/icon_background.png and the magic link file mipmap/icon.xml. // // // // This now looks ok on my phone, but I fully expect on other devices it might look weird and we will have to // // figure some more android configuration junk out. If we manage to figure out enough of the junk then I could // // maybe write some helper that generates all the required crap given some simpler inputs, for now it's all manually // // defined. // // // // Adaptive icons docs: https://developer.android.com/develop/ui/views/launch/icon_design_adaptive // // "Alternative resources" docs: https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources // } // } target_windows : bool; target_linux : bool; target_macos : bool; target_android : bool; target_optimize : bool; target_x64 : bool; cpu_target: CPU_Tag; os_target: Operating_System_Tag; android_make_apk := false; android_install := false; GetUnixTimestamp :: () -> float64 { #if OS == .WINDOWS { #import "Windows"; FILETIME_TO_UNIX :: 116444736000000000; ft: FILETIME; GetSystemTimePreciseAsFileTime(*ft); t: s64 = ((cast(s64)ft.dwHighDateTime) << 32) | (cast(s64)ft.dwLowDateTime); return (cast(float64)(t - FILETIME_TO_UNIX)) / (10.0 * 1000.0 * 1000.0); } #if OS == .LINUX || OS == .MACOS { #import "POSIX"; TIMESPEC_TO_SEC_DIV :: 1000000000.0; at := current_time_consensus(); ts := to_timespec(at); return cast(float64)(ts.tv_sec) + cast(float64)(ts.tv_nsec) / TIMESPEC_TO_SEC_DIV; } }