Browse Source

Merge pull request #154 from nakst/master

essence cross compile
gingerBill 7 years ago
parent
commit
df06236076
6 changed files with 206 additions and 6 deletions
  1. 1 0
      core/os.odin
  2. 115 0
      core/os_essence.odin
  3. 24 0
      core/sys/essence_linker_userland64.ld
  4. 11 1
      src/build_settings.cpp
  5. 8 0
      src/ir.cpp
  6. 47 5
      src/main.cpp

+ 1 - 0
core/os.odin

@@ -1,6 +1,7 @@
 when ODIN_OS == "windows" do export "core:os_windows.odin";
 when ODIN_OS == "windows" do export "core:os_windows.odin";
 when ODIN_OS == "osx"     do export "core:os_x.odin";
 when ODIN_OS == "osx"     do export "core:os_x.odin";
 when ODIN_OS == "linux"   do export "core:os_linux.odin";
 when ODIN_OS == "linux"   do export "core:os_linux.odin";
+when ODIN_OS == "essence" do export "core:os_essence.odin";
 
 
 import "mem.odin";
 import "mem.odin";
 
 

+ 115 - 0
core/os_essence.odin

@@ -0,0 +1,115 @@
+foreign import api "system:api"
+
+Handle    :: int;
+Errno     :: int;
+
+O_RDONLY   :: 1;
+O_WRONLY   :: 2;
+O_CREATE   :: 4;
+O_TRUNC    :: 4;
+
+OS_Node_Type :: enum i32 {
+	File      = 0,
+	Directory = 1,
+}
+
+OS_Node_Information :: struct #ordered {
+	handle: Handle,
+	id: [16]u8,
+	ntype: OS_Node_Type,
+	size: i64,
+	position: i64,
+}
+
+foreign api {
+	@(link_name="OSHelloWorld")		os_hello_world :: proc() ---;
+	@(link_name="OSPrintDirect")		os_print_direct :: proc(string: ^u8, length: int) ---;
+	@(link_name="OSHeapAllocate")		os_heap_allocate :: proc(bytes: int, zero: bool) -> rawptr ---;
+	@(link_name="OSHeapFree")		os_heap_free :: proc(address: rawptr) ---;
+	@(link_name="OSOpenNode")		os_open_node :: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---;
+	@(link_name="OSResizeFile")		os_resize_file :: proc(handle: Handle, new_size: u64) -> Errno ---;
+	@(link_name="OSCloseHandle")		os_close_handle :: proc(handle: Handle) ---;
+	@(link_name="OSWriteFileSync")		os_write_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
+	@(link_name="OSReadFileSync")		os_read_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
+	@(link_name="OSInitialiseAPI")		os_initialise_api :: proc() -> int ---;
+	@(link_name="OSTerminateProcess")	os_terminate_process :: proc(handle: Handle) ---;
+	@(link_name="realloc")			os_heap_reallocate :: proc(address: rawptr, size: int) -> rawptr ---;
+}
+
+stdin  := cast(Handle) -1; // Not implemented
+stdout := cast(Handle) 0;
+stderr := cast(Handle) 0;
+
+current_thread_id :: proc() -> int {
+	// Not implemented
+	return int(-1);
+}
+
+heap_alloc :: proc(size: int) -> rawptr {
+	return os_heap_allocate(size, true);
+}
+
+heap_free :: proc(address: rawptr) {
+	os_heap_free(address);
+}
+
+heap_resize :: proc(address: rawptr, new_size: int) -> rawptr {
+	return os_heap_reallocate(address, new_size);
+}
+
+open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
+	information := new(OS_Node_Information);
+	error := os_open_node(&path[0], len(path), cast(u64) mode, information);
+	if (error < -1) { return 0,1; }
+	information.position = 0;
+	if (mode&O_TRUNC==O_TRUNC) {
+		error := os_resize_file(information.handle, 0);
+		if (error < -1) { return 0,1; }
+	}
+	return cast(Handle) cast(uintptr) information,0;
+}
+
+close :: proc(fd: Handle) {
+	information := cast(^OS_Node_Information) cast(uintptr) fd;
+	os_close_handle(information.handle);
+	free(information);
+}
+
+file_size :: proc(fd: Handle) -> (i64, Errno) {
+	// Not (properly) implemented
+	information := cast(^OS_Node_Information) cast(uintptr) fd;
+	return information.size,0;
+}
+
+write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
+	if (fd == 0) {
+		os_print_direct(&data[0], len(data));
+		return len(data), 0;
+	} else if (fd == 1) {
+		assert(false);
+		return 0, 1;
+	} else {
+		information := cast(^OS_Node_Information) cast(uintptr) fd;
+		count := os_write_file_sync(information.handle, information.position, cast(i64) len(data), cast(rawptr) &data[0]);
+		if (count < 0) { return 0, 1; }
+		information.position += count;
+		return cast(int) count, 0;
+	}
+}
+
+read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
+	if (fd == 0 || fd == 1) {
+		assert(false);
+		return 0, 1;
+	} else {
+		information := cast(^OS_Node_Information) cast(uintptr) fd;
+		count := os_read_file_sync(information.handle, information.position, cast(i64) len(data), cast(rawptr) &data[0]);
+		if (count < 0) { return 0, 1; }
+		information.position += count;
+		return cast(int) count, 0;
+	}
+}
+
+os_terminate_this_process :: proc() {
+	os_terminate_process(0x1001);
+}

+ 24 - 0
core/sys/essence_linker_userland64.ld

@@ -0,0 +1,24 @@
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0x100000;
+	.text BLOCK(4K) : ALIGN(4K)
+	{
+		*(.text)
+	}
+	.rodata BLOCK(4K) : ALIGN(4K)
+	{
+		*(.rodata)
+	}
+	.data BLOCK(4K) : ALIGN(4K)
+	{
+		*(.data)
+	}
+
+	.bss BLOCK(4K) : ALIGN(4K)
+	{
+		*(COMMON)
+		*(.bss)
+	}
+}

+ 11 - 1
src/build_settings.cpp

@@ -309,6 +309,8 @@ String get_fullpath_core(gbAllocator a, String path) {
 
 
 
 
 String const ODIN_VERSION = str_lit("0.7.1");
 String const ODIN_VERSION = str_lit("0.7.1");
+String cross_compile_target = str_lit("");
+String cross_compile_lib_dir = str_lit("");
 
 
 void init_build_context(void) {
 void init_build_context(void) {
 	BuildContext *bc = &build_context;
 	BuildContext *bc = &build_context;
@@ -330,6 +332,10 @@ void init_build_context(void) {
 	bc->ODIN_OS      = str_lit("linux");
 	bc->ODIN_OS      = str_lit("linux");
 #endif
 #endif
 
 
+	if (cross_compile_target.len) {
+		bc->ODIN_OS = cross_compile_target;
+	}
+
 #if defined(GB_ARCH_64_BIT)
 #if defined(GB_ARCH_64_BIT)
 	bc->ODIN_ARCH = str_lit("amd64");
 	bc->ODIN_ARCH = str_lit("amd64");
 #else
 #else
@@ -376,7 +382,11 @@ void init_build_context(void) {
 		bc->max_align = 16;
 		bc->max_align = 16;
 
 
 		bc->llc_flags = str_lit("-march=x86-64 ");
 		bc->llc_flags = str_lit("-march=x86-64 ");
-		bc->link_flags = str_lit(LINK_FLAG_X64 " ");
+		if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
+			bc->link_flags = str_lit(" ");
+		} else {
+			bc->link_flags = str_lit(LINK_FLAG_X64 " ");
+		}
 	} else if (bc->ODIN_ARCH == "x86") {
 	} else if (bc->ODIN_ARCH == "x86") {
 		bc->word_size = 4;
 		bc->word_size = 4;
 		bc->max_align = 8;
 		bc->max_align = 8;

+ 8 - 0
src/ir.cpp

@@ -8634,6 +8634,14 @@ void ir_gen_tree(irGen *s) {
 	if (!(build_context.is_dll && !has_dll_main)) {
 	if (!(build_context.is_dll && !has_dll_main)) {
 		// main :: proc(argc: i32, argv: ^^u8) -> i32
 		// main :: proc(argc: i32, argv: ^^u8) -> i32
 		String name = str_lit("main");
 		String name = str_lit("main");
+
+		if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
+			// This is a bit hacky,
+			// because this makes this function the first function run in the executable
+			// so it won't actually have the argc/argv arguments.
+			name = str_lit("ProgramEntry");
+		}
+
 		Type *proc_params = make_type_tuple(a);
 		Type *proc_params = make_type_tuple(a);
 		Type *proc_results = make_type_tuple(a);
 		Type *proc_results = make_type_tuple(a);
 
 

+ 47 - 5
src/main.cpp

@@ -77,6 +77,7 @@ i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
 	va_end(va);
 	va_end(va);
 	cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
 	cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1);
 
 
+	//printf("do: %s\n", cmd_line);
 	exit_code = system(&cmd_line[0]);
 	exit_code = system(&cmd_line[0]);
 
 
 	// pid_t pid = fork();
 	// pid_t pid = fork();
@@ -210,6 +211,8 @@ enum BuildFlagKind {
 	BuildFlag_Collection,
 	BuildFlag_Collection,
 	BuildFlag_BuildMode,
 	BuildFlag_BuildMode,
 	BuildFlag_Debug,
 	BuildFlag_Debug,
+	BuildFlag_CrossCompile,
+	BuildFlag_CrossLibDir,
 
 
 	BuildFlag_COUNT,
 	BuildFlag_COUNT,
 };
 };
@@ -246,6 +249,8 @@ bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_Collection,        str_lit("collection"),      BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_Collection,        str_lit("collection"),      BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_BuildMode,         str_lit("build-mode"),      BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_BuildMode,         str_lit("build-mode"),      BuildFlagParam_String);
 	add_flag(&build_flags, BuildFlag_Debug,             str_lit("debug"),           BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_Debug,             str_lit("debug"),           BuildFlagParam_None);
+	add_flag(&build_flags, BuildFlag_CrossCompile,      str_lit("cross-compile"),   BuildFlagParam_String);
+	add_flag(&build_flags, BuildFlag_CrossLibDir,       str_lit("cross-lib-dir"),   BuildFlagParam_String);
 
 
 
 
 	Array<String> flag_args = args;
 	Array<String> flag_args = args;
@@ -399,6 +404,33 @@ bool parse_build_flags(Array<String> args) {
 							build_context.keep_temp_files = true;
 							build_context.keep_temp_files = true;
 							break;
 							break;
 
 
+						case BuildFlag_CrossCompile: {
+							GB_ASSERT(value.kind == ExactValue_String);
+							cross_compile_target = value.value_string;
+#ifdef GB_SYSTEM_UNIX
+#ifdef GB_ARCH_64_BIT
+							if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
+#endif
+#endif
+							} else {
+								gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target));
+								gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n");
+								bad_flags = true;
+							}
+							break;
+						} 
+
+						case BuildFlag_CrossLibDir: {
+							GB_ASSERT(value.kind == ExactValue_String);
+							if (cross_compile_lib_dir.len) {
+								gb_printf_err("Multiple cross compilation library directories\n");
+								bad_flags = true;
+							} else {
+								cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string);
+							}
+							break;
+						}
+
 						case BuildFlag_Collection: {
 						case BuildFlag_Collection: {
 							GB_ASSERT(value.kind == ExactValue_String);
 							GB_ASSERT(value.kind == ExactValue_String);
 							String str = value.value_string;
 							String str = value.value_string;
@@ -831,10 +863,12 @@ int main(int arg_count, char **arg_ptr) {
 			"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
 			"llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d "
 			"%.*s "
 			"%.*s "
 			// "-debug-pass=Arguments "
 			// "-debug-pass=Arguments "
+			"%s"
 			"",
 			"",
 			LIT(output_base),
 			LIT(output_base),
 			build_context.optimization_level,
 			build_context.optimization_level,
-			LIT(build_context.llc_flags));
+			LIT(build_context.llc_flags),
+			str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : "");
 		if (exit_code != 0) {
 		if (exit_code != 0) {
 			return exit_code;
 			return exit_code;
 		}
 		}
@@ -916,14 +950,19 @@ int main(int arg_count, char **arg_ptr) {
 			//   It probably has to do with including the entire CRT, but
 			//   It probably has to do with including the entire CRT, but
 			//   that's quite a complicated issue to solve while remaining distro-agnostic.
 			//   that's quite a complicated issue to solve while remaining distro-agnostic.
 			//   Clang can figure out linker flags for us, and that's good enough _for now_.
 			//   Clang can figure out linker flags for us, and that's good enough _for now_.
-			linker = "clang -Wno-unused-command-line-argument";
+			if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
+				linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument";
+			} else {
+				linker = "clang -Wno-unused-command-line-argument";
+			}
 		#endif
 		#endif
 
 
 		exit_code = system_exec_command_line_app("ld-link", true,
 		exit_code = system_exec_command_line_app("ld-link", true,
 			"%s \"%.*s.o\" -o \"%.*s%s\" %s "
 			"%s \"%.*s.o\" -o \"%.*s%s\" %s "
-			"-lc -lm "
+			" %s "
 			" %.*s "
 			" %.*s "
 			" %s "
 			" %s "
+			" %.*s "
 			#if defined(GB_SYSTEM_OSX)
 			#if defined(GB_SYSTEM_OSX)
 				// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
 				// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
 				// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
 				// NOTE: If you change this (although this minimum is as low as you can go with Odin working)
@@ -933,8 +972,11 @@ int main(int arg_count, char **arg_ptr) {
 				" -e _main "
 				" -e _main "
 			#endif
 			#endif
 			, linker, LIT(output_base), LIT(output_base), output_ext,
 			, linker, LIT(output_base), LIT(output_base), output_ext,
-			lib_str, LIT(build_context.link_flags),
-			link_settings
+			lib_str, 
+			str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "" : "-lc -lm", 
+			LIT(build_context.link_flags),
+			link_settings,
+			LIT(cross_compile_lib_dir)
 			);
 			);
 		if (exit_code != 0) {
 		if (exit_code != 0) {
 			return exit_code;
 			return exit_code;