<commit_before>// #define NO_ARRAY_BOUNDS_CHECK

#include "common.cpp"
#include "timings.cpp"
#include "tokenizer.cpp"
#include "big_int.cpp"
#include "exact_value.cpp"
#include "build_settings.cpp"


gb_global Timings global_timings = {0};

#if defined(GB_SYSTEM_WINDOWS)
#include "llvm-c/Types.h"
#else
#include <llvm-c/Types.h>
#endif

#include "parser.hpp"
#include "checker.hpp"

#include "parser.cpp"
#include "checker.cpp"
#include "docs.cpp"


#include "llvm_backend.cpp"

#if defined(GB_SYSTEM_OSX)
	#include <llvm/Config/llvm-config.h>
	#if LLVM_VERSION_MAJOR < 11
	#error LLVM Version 11+ is required => "brew install llvm@11"
	#endif
#endif

#include "query_data.cpp"


#if defined(GB_SYSTEM_WINDOWS)
// NOTE(IC): In order to find Visual C++ paths without relying on environment variables.
#include "microsoft_craziness.h"
#endif


// NOTE(bill): 'name' is used in debugging and profiling modes
i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
#if defined(GB_SYSTEM_WINDOWS)
	STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
	PROCESS_INFORMATION pi = {0};
	isize cmd_len = 0;
	isize const cmd_cap = 4096;
	char cmd_line[cmd_cap] = {};
	va_list va;
	gbTempArenaMemory tmp;
	String16 cmd;
	i32 exit_code = 0;


	start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	start_info.wShowWindow = SW_SHOW;
	start_info.hStdInput   = GetStdHandle(STD_INPUT_HANDLE);
	start_info.hStdOutput  = GetStdHandle(STD_OUTPUT_HANDLE);
	start_info.hStdError   = GetStdHandle(STD_ERROR_HANDLE);

	va_start(va, fmt);
	cmd_len = gb_snprintf_va(cmd_line, cmd_cap-1, fmt, va);
	va_end(va);

	if (build_context.show_system_calls) {
		gb_printf_err("[SYSTEM CALL] %s\n", name);
		gb_printf_err("%.*s\n\n", cast(int)(cmd_len-1), cmd_line);
	}

	tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
	defer (gb_temp_arena_memory_end(tmp));

	cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
	if (CreateProcessW(nullptr, cmd.text,
	                   nullptr, nullptr, true, 0, nullptr, nullptr,
	                   &start_info, &pi)) {
		WaitForSingleObject(pi.hProcess, INFINITE);
		GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);

		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	} else {
		// NOTE(bill): failed to create process
		gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
		exit_code = -1;
	}

	if (exit_code) {
		exit(exit_code);
	}

	return exit_code;

#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)

	char cmd_line[4096] = {0};
	isize cmd_len;
	va_list va;
	String cmd;
	i32 exit_code = 0;

	va_start(va, fmt);
	cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
	va_end(va);
	cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);

	if (build_context.show_system_calls) {
		gb_printf_err("[SYSTEM CALL] %s\n", name);
		gb_printf_err("%s\n\n", cmd_line);
	}
	exit_code = system(cmd_line);
	// pid_t pid = fork();
	// int status = 0;

	// if(pid == 0) {
	// 	// in child, pid == 0.
	// 	int ret = execvp(cmd.text, (char* const*) cmd.text);

	// 	if(ret == -1) {
	// 		gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);

	// 		// we're in the child, so returning won't do us any good -- just quit.
	// 		exit(-1);
	// 	}

	// 	// unreachable
	// 	abort();
	// } else {
	// 	// wait for child to finish, then we can continue cleanup

	// 	int s = 0;
	// 	waitpid(pid, &s, 0);

	// 	status = WEXITSTATUS(s);
	// }

	// exit_code = status
	return exit_code;
#endif
}




i32 linker_stage(lbGenerator *gen) {
  i32 result = 0;
  Timings *timings = &global_timings;

	String output_base = gen->output_base;

	if (is_arch_wasm()) {
		timings_start_section(timings, str_lit("wasm-ld"));
		system_exec_command_line_app("wasm-ld",
			"\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm-obj\" -o \"%.*s.wasm\" %.*s %.*s",
			LIT(build_context.ODIN_ROOT),
			LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
	}

	if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
#ifdef GB_SYSTEM_UNIX
		result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
			LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
#else
		gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
			LIT(target_os_names[build_context.metrics.os]),
			LIT(target_arch_names[build_context.metrics.arch])
		);
#endif
	} else if (build_context.cross_compiling && build_context.different_os) {
		gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
			LIT(target_os_names[build_context.metrics.os]),
			LIT(target_arch_names[build_context.metrics.arch])
		);
		build_context.keep_object_files = true;
	} else {
	#if defined(GB_SYSTEM_WINDOWS)
		timings_start_section(timings, str_lit("msvc-link"));

		gbString lib_str = gb_string_make(heap_allocator(), "");
		defer (gb_string_free(lib_str));
		char lib_str_buf[1024] = {0};

		char const *output_ext = "exe";
		gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
		defer (gb_string_free(link_settings));


		// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.<commit_msg>Fix show-timings header for -lld on windows<commit_after>// #define NO_ARRAY_BOUNDS_CHECK

#include "common.cpp"
#include "timings.cpp"
#include "tokenizer.cpp"
#include "big_int.cpp"
#include "exact_value.cpp"
#include "build_settings.cpp"


gb_global Timings global_timings = {0};

#if defined(GB_SYSTEM_WINDOWS)
#include "llvm-c/Types.h"
#else
#include <llvm-c/Types.h>
#endif

#include "parser.hpp"
#include "checker.hpp"

#include "parser.cpp"
#include "checker.cpp"
#include "docs.cpp"


#include "llvm_backend.cpp"

#if defined(GB_SYSTEM_OSX)
	#include <llvm/Config/llvm-config.h>
	#if LLVM_VERSION_MAJOR < 11
	#error LLVM Version 11+ is required => "brew install llvm@11"
	#endif
#endif

#include "query_data.cpp"


#if defined(GB_SYSTEM_WINDOWS)
// NOTE(IC): In order to find Visual C++ paths without relying on environment variables.
#include "microsoft_craziness.h"
#endif


// NOTE(bill): 'name' is used in debugging and profiling modes
i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
#if defined(GB_SYSTEM_WINDOWS)
	STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
	PROCESS_INFORMATION pi = {0};
	isize cmd_len = 0;
	isize const cmd_cap = 4096;
	char cmd_line[cmd_cap] = {};
	va_list va;
	gbTempArenaMemory tmp;
	String16 cmd;
	i32 exit_code = 0;


	start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
	start_info.wShowWindow = SW_SHOW;
	start_info.hStdInput   = GetStdHandle(STD_INPUT_HANDLE);
	start_info.hStdOutput  = GetStdHandle(STD_OUTPUT_HANDLE);
	start_info.hStdError   = GetStdHandle(STD_ERROR_HANDLE);

	va_start(va, fmt);
	cmd_len = gb_snprintf_va(cmd_line, cmd_cap-1, fmt, va);
	va_end(va);

	if (build_context.show_system_calls) {
		gb_printf_err("[SYSTEM CALL] %s\n", name);
		gb_printf_err("%.*s\n\n", cast(int)(cmd_len-1), cmd_line);
	}

	tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
	defer (gb_temp_arena_memory_end(tmp));

	cmd = string_to_string16(string_buffer_allocator, make_string(cast(u8 *)cmd_line, cmd_len-1));
	if (CreateProcessW(nullptr, cmd.text,
	                   nullptr, nullptr, true, 0, nullptr, nullptr,
	                   &start_info, &pi)) {
		WaitForSingleObject(pi.hProcess, INFINITE);
		GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code);

		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	} else {
		// NOTE(bill): failed to create process
		gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);
		exit_code = -1;
	}

	if (exit_code) {
		exit(exit_code);
	}

	return exit_code;

#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)

	char cmd_line[4096] = {0};
	isize cmd_len;
	va_list va;
	String cmd;
	i32 exit_code = 0;

	va_start(va, fmt);
	cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
	va_end(va);
	cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);

	if (build_context.show_system_calls) {
		gb_printf_err("[SYSTEM CALL] %s\n", name);
		gb_printf_err("%s\n\n", cmd_line);
	}
	exit_code = system(cmd_line);
	// pid_t pid = fork();
	// int status = 0;

	// if(pid == 0) {
	// 	// in child, pid == 0.
	// 	int ret = execvp(cmd.text, (char* const*) cmd.text);

	// 	if(ret == -1) {
	// 		gb_printf_err("Failed to execute command:\n\t%s\n", cmd_line);

	// 		// we're in the child, so returning won't do us any good -- just quit.
	// 		exit(-1);
	// 	}

	// 	// unreachable
	// 	abort();
	// } else {
	// 	// wait for child to finish, then we can continue cleanup

	// 	int s = 0;
	// 	waitpid(pid, &s, 0);

	// 	status = WEXITSTATUS(s);
	// }

	// exit_code = status
	return exit_code;
#endif
}




i32 linker_stage(lbGenerator *gen) {
  i32 result = 0;
  Timings *timings = &global_timings;

	String output_base = gen->output_base;

	if (is_arch_wasm()) {
		timings_start_section(timings, str_lit("wasm-ld"));
		system_exec_command_line_app("wasm-ld",
			"\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm-obj\" -o \"%.*s.wasm\" %.*s %.*s",
			LIT(build_context.ODIN_ROOT),
			LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
	}

	if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) {
#ifdef GB_SYSTEM_UNIX
		result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s",
			LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags));
#else
		gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
			LIT(target_os_names[build_context.metrics.os]),
			LIT(target_arch_names[build_context.metrics.arch])
		);
#endif
	} else if (build_context.cross_compiling && build_context.different_os) {
		gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n",
			LIT(target_os_names[build_context.metrics.os]),
			LIT(target_arch_names[build_context.metrics.arch])
		);
		build_context.keep_object_files = true;
	} else {
	#if defined(GB_SYSTEM_WINDOWS)
		String section_name = str_lit("msvc-link");
		if (build_context.use_lld) {
			section_name = str_lit("lld-link");
		}
		timings_start_section(timings, section_name);

		gbString lib_str = gb_string_make(heap_allocator(), "");
		defer (gb_string_free(lib_str));
		char lib_str_buf[1024] = {0};

		char const *output_ext = "exe";
		gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
		defer (gb_string_free(link_settings));


		// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
{'fraction_non_alphanumeric': 0.1458750682935713, 'fraction_numerical': 0.011655436168275359, 'mean_word_length': 4.544169611307421, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6364129', 'n_tokens_mistral': 4505, 'n_tokens_neox': 4241, 'n_words': 866}