Forráskód Böngészése

Added Linux functions throughout the code, but it segfaults.

Zac Pierson 8 éve
szülő
commit
5cfa4ba580
5 módosított fájl, 270 hozzáadás és 45 törlés
  1. 5 0
      .gitignore
  2. 6 0
      build.sh
  3. 78 4
      src/build.c
  4. 107 40
      src/gb/gb.h
  5. 74 1
      src/main.c

+ 5 - 0
.gitignore

@@ -251,7 +251,12 @@ paket-files/
 
 
 # Project Specific
+
+# - Windows
 *.sln
 !misc/llvm-bim/lli.exe
 !misc/llvm-bim/opt.exe
 builds
+
+# - Linux/MacOS
+odin

+ 6 - 0
build.sh

@@ -0,0 +1,6 @@
+#!/bin/sh
+
+WARNINGS_DISABLE="-Wno-attributes -Wno-implicit-function-declaration -Wno-incompatible-pointer-types"
+LIBRARIES="-pthread -ldl -lm"
+
+gcc src/main.c ${WARNINGS_DISABLE} ${LIBRARIES} -o odin

+ 78 - 4
src/build.c

@@ -126,7 +126,64 @@ String odin_root_dir(void) {
 	return path;
 }
 #else
-#error Implement system
+
+// NOTE: Linux / Unix is unfinished and not tested very well.
+#include <sys/stat.h>
+
+String odin_root_dir(void) {
+	String path = global_module_path;
+	Array(char) path_buf;
+	isize len, i;
+	gbTempArenaMemory tmp;
+	wchar_t *text;
+
+	if (global_module_path_set) {
+		return global_module_path;
+	}
+
+	array_init_count(&path_buf, heap_allocator(), 300);
+
+	len = 0;
+	for (;;) {
+		// This is not a 100% reliable system, but for the purposes
+		// of this compiler, it should be _good enough_.
+		// That said, there's no solid 100% method on Linux to get the program's
+		// path without checking this link. Sorry.
+		len = readlink("/proc/self/exe", &path_buf.e[0], path_buf.count);
+		if(len == 0) {
+			return make_string(NULL, 0);
+		}
+		printf("build.c:155 | Link value: \"%s\"\n", &path_buf.e[0]);
+		exit(1);
+		if (len < path_buf.count) {
+			break;
+		}
+		array_resize(&path_buf, 2*path_buf.count + 300);
+	}
+
+
+	tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
+	text = gb_alloc_array(string_buffer_allocator, u8, len + 1);
+	gb_memmove(text, &path_buf.e[0], len);
+
+	path = make_string(text, len);
+	for (i = path.len-1; i >= 0; i--) {
+		u8 c = path.text[i];
+		if (c == '/' || c == '\\') {
+			break;
+		}
+		path.len--;
+	}
+
+	global_module_path = path;
+	global_module_path_set = true;
+
+	gb_temp_arena_memory_end(tmp);
+
+	array_free(&path_buf);
+
+	return path;
+}
 #endif
 
 
@@ -250,18 +307,35 @@ void init_build_context(BuildContext *bc) {
 	bc->ODIN_ARCH    = str_lit("amd64");
 	bc->ODIN_ENDIAN  = str_lit("little");
 #else
-#error Implement system
+	bc->ODIN_OS      = str_lit("linux");
+	bc->ODIN_ARCH    = str_lit("amd64");
+	bc->ODIN_ENDIAN  = str_lit("little");
 #endif
 
+
+
+	// The linker flags to set the build architecture are different
+	// across OSs. It doesn't make sense to allocate extra data on the heap
+	// here, so I just #defined the linker flags to keep things concise.
+	#if defined(GB_SYSTEM_WINDOWS)
+	#define linker_flag_x64 "/machine:x64"
+	#define linker_flag_x86 "/machine:x86"
+	#elif defined(GB_SYSTEM_OSX)
+	#error Run "ld -V" to find out what to build programs as. It may be the same as Linux...?
+	#else
+	#define linker_flag_x64 "-m elf_x86_64"
+	#define linker_flag_x86 "-m elf_i386"
+	#endif
+
 	if (str_eq(bc->ODIN_ARCH, str_lit("amd64"))) {
 		bc->word_size = 8;
 		bc->max_align = 16;
 		bc->llc_flags = str_lit("-march=x86-64 ");
-		bc->link_flags = str_lit("/machine:x64 ");
+		bc->link_flags = str_lit(linker_flag_x64 " ");
 	} else if (str_eq(bc->ODIN_ARCH, str_lit("x86"))) {
 		bc->word_size = 4;
 		bc->max_align = 8;
 		bc->llc_flags = str_lit("-march=x86 ");
-		bc->link_flags = str_lit("/machine:x86 ");
+		bc->link_flags = str_lit(linker_flag_x86 " ");
 	}
 }

+ 107 - 40
src/gb/gb.h

@@ -1,4 +1,4 @@
-/* gb.h - v0.27  - Ginger Bill's C Helper Library - public domain
+/* gb.h - v0.26d - Ginger Bill's C Helper Library - public domain
                  - no warranty implied; use at your own risk
 
 	This is a single header file with a bunch of useful stuff
@@ -276,8 +276,6 @@ extern "C" {
 #include <stdarg.h>
 #include <stddef.h>
 
-
-
 #if defined(GB_SYSTEM_WINDOWS)
 	#if !defined(GB_NO_WINDOWS_H)
 		#define NOMINMAX            1
@@ -298,9 +296,6 @@ extern "C" {
 	#include <errno.h>
 	#include <fcntl.h>
 	#include <pthread.h>
-	#ifndef _IOSC11_SOURCE
-	#define _IOSC11_SOURCE
-	#endif
 	#include <stdlib.h> // NOTE(bill): malloc on linux
 	#include <sys/mman.h>
 	#if !defined(GB_SYSTEM_OSX)
@@ -314,18 +309,18 @@ extern "C" {
 #endif
 
 #if defined(GB_SYSTEM_OSX)
-	#include <mach/mach.h>
-	#include <mach/mach_init.h>
-	#include <mach/mach_time.h>
-	#include <mach/thread_act.h>
-	#include <mach/thread_policy.h>
-	#include <sys/sysctl.h>
-	#include <copyfile.h>
-	#include <mach/clock.h>
+#include <mach/mach.h>
+#include <mach/mach_init.h>
+#include <mach/mach_time.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <sys/sysctl.h>
+#include <copyfile.h>
+#include <mach/clock.h>
 #endif
 
 #if defined(GB_SYSTEM_UNIX)
-	#include <semaphore.h>
+#include <semaphore.h>
 #endif
 
 
@@ -417,20 +412,21 @@ typedef i32 Rune; // NOTE(bill): Unicode codepoint
 #define GB_RUNE_EOF     cast(Rune)(-1)
 
 
+// NOTE(bill): I think C99 and C++ `bool` is stupid for numerous reasons but there are too many
+// to write in this small comment.
 typedef i8  b8;
 typedef i16 b16;
 typedef i32 b32; // NOTE(bill): Prefer this!!!
 
 // NOTE(bill): Get true and false
 #if !defined(__cplusplus)
-	#if (defined(_MSC_VER) && _MSC_VER <= 1800) || (!defined(_MSC_VER) && !defined(__STDC_VERSION__))
+	#if (defined(_MSC_VER) && _MSC_VER <= 1800) || !defined(__STDC_VERSION__)
 		#ifndef true
 		#define true  (0 == 0)
 		#endif
 		#ifndef false
 		#define false (0 != 0)
 		#endif
-		typedef b8 bool;
 	#else
 		#include <stdbool.h>
 	#endif
@@ -619,7 +615,7 @@ extern "C++" {
 //
 // NOTE: C++11 (and above) only!
 //
-#if !defined(GB_NO_DEFER) && defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1400) || (__cplusplus >= 201103L))
+#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1400) || (__cplusplus >= 201103L))
 extern "C++" {
 	// NOTE(bill): Stupid fucking templates
 	template <typename T> struct gbRemoveReference       { typedef T Type; };
@@ -1008,7 +1004,12 @@ typedef struct gbAffinity {
 } gbAffinity;
 
 #elif defined(GB_SYSTEM_LINUX)
-#error TODO(bill): Implement gbAffinity for linux
+typedef struct gbAffinity {
+	b32   is_accurate;
+	isize core_count;
+	isize thread_count;
+	isize threads_per_core;
+} gbAffinity;
 #else
 #error TODO(bill): Unknown system
 #endif
@@ -4117,7 +4118,7 @@ gb_inline i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand) {
 
 gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) {
 #if defined(GB_ARCH_64_BIT)
-	return _InterlockedOr64(cast(i64 volatile *)a, operand);
+	return _InterlockedAnd64(cast(i64 volatile *)a, operand);
 #elif GB_CPU_X86
 	i64 expected = a->value;
 	for (;;) {
@@ -4824,15 +4825,18 @@ GB_ALLOCATOR_PROC(gb_heap_allocator_proc) {
 #else
 	// TODO(bill): *nix version that's decent
 	case gbAllocation_Alloc: {
-		posix_memalign(&ptr, alignment, size);
-
-		if (flags & gbAllocatorFlag_ClearToZero) {
+		gbAllocationHeader *header;
+		isize total_size = size + alignment + gb_size_of(gbAllocationHeader);
+		ptr = malloc(total_size);
+		header = cast(gbAllocationHeader *)ptr;
+		ptr = gb_align_forward(header+1, alignment);
+		gb_allocation_header_fill(header, ptr, size);
+		if (flags & gbAllocatorFlag_ClearToZero)
 			gb_zero_size(ptr, size);
-		}
 	} break;
 
 	case gbAllocation_Free: {
-		free(old_memory);
+		free(gb_allocation_header(old_memory));
 	} break;
 
 	case gbAllocation_Resize: {
@@ -4929,7 +4933,7 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
 void gb_affinity_init(gbAffinity *a) {
 	usize count, count_size = gb_size_of(count);
 
-	a->is_accurate      = false;
+	a->is_accurate               = false;
 	a->thread_count     = 1;
 	a->core_count       = 1;
 	a->threads_per_core = 1;
@@ -4960,6 +4964,7 @@ void gb_affinity_destroy(gbAffinity *a) {
 b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
 	isize index;
 	thread_t thread;
+	GB_ASSERT(thread < gb_affinity_thread_count
 	thread_affinity_policy_data_t info;
 	kern_return_t result;
 
@@ -4979,7 +4984,81 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
 }
 
 #elif defined(GB_SYSTEM_LINUX)
-#error TODO(bill): Implement gbAffinity for linux
+#warning gbAffinity is mostly mostly untested on Linux. All I know is that it compiles and runs.
+#warning TODO(bill): gb_affinity_set on Linux is a stub
+
+// I have to read /proc/cpuinfo to get the number of threads per core.
+#include <stdio.h>
+
+void gb_affinity_init(gbAffinity *a) {
+	usize count, count_size = gb_size_of(count);
+
+	b32 accurate = true;
+
+	a->thread_count     = 1;
+	a->core_count       = sysconf(_SC_NPROCESSORS_ONLN);
+	a->threads_per_core = 1;
+
+
+	if(a->core_count <= 0) {
+		a->core_count = 1;
+		accurate = false;
+	}
+
+	// Parsing /proc/cpuinfo to get the number of threads per core.
+	// NOTE: This calls the CPU's threads "cores", although the wording
+	//   is kind of weird. This should be right, though.
+	FILE* cpu_info = fopen("/proc/cpuinfo", "r");
+
+	int threads = 0;
+
+	if(cpu_info) {
+		while(1) {
+			// The 'temporary char'. Everything goes into this char,
+			// so that we can check against EOF at the end of this loop.
+			char c;
+
+			#define check(letter) ((c = getc(cpu_info)) == letter)
+			if(check('c') && check('p') && check('u') && check(' ') &&
+				check('c') && check('o') && check('r') && check('e') && check('s')) {
+				// We're on a CPU info line.
+				while(!check(EOF)) {
+					if(c == '\n') break;
+					else if(c < '0' || c > '9') continue;
+					threads = threads * 10 + (c - '0');
+				}
+				break;
+			} else {
+				while(!check('\n')) {if(c==EOF) break;}
+			}
+			if(c == EOF) break;
+		}
+	}
+
+	if(threads == 0) {
+		threads = 1;
+		accurate = false;
+	}
+
+	a->threads_per_core = threads;
+	a->thread_count = a->threads_per_core * a->core_count;
+
+	a->is_accurate = accurate;
+
+}
+
+void gb_affinity_destroy(gbAffinity *a) {
+	gb_unused(a);
+}
+
+b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
+	return true;
+}
+
+isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
+	GB_ASSERT(core >= 0 && core < a->core_count);
+	return a->threads_per_core;
+}
 #else
 #error TODO(bill): Unknown system
 #endif
@@ -7760,18 +7839,7 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) {
 	return gb_alloc_str_len(a, buf, len+1);
 #else
 // TODO(bill): Make work on *nix, etc.
-	char* p = realpath(path, 0);
-	GB_ASSERT(p && "file does not exist");
-
-	isize len = gb_strlen(p);
-
-	// bill... gb_alloc_str_len refused to work for this...
-	char* ret = gb_alloc(a, sizeof(char) * len + 1);
-	gb_memmove(ret, p, len);
-	ret[len] = 0;
-	free(p);
-
-	return ret;
+	return gb_alloc_str_len(a, path, gb_strlen(path));
 #endif
 }
 
@@ -10385,4 +10453,3 @@ GB_COMPARE_PROC(gb_video_mode_dsc_cmp) {
 #endif
 
 #endif // GB_IMPLEMENTATION
-

+ 74 - 1
src/main.c

@@ -16,6 +16,11 @@ extern "C" {
 #include "ir_print.c"
 // #include "vm.c"
 
+#if defined(GB_SYSTEM_UNIX)
+// Required for intrinsics on GCC
+#include <xmmintrin.h>
+#endif
+
 #if defined(GB_SYSTEM_WINDOWS)
 // NOTE(bill): `name` is used in debugging and profiling modes
 i32 system_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
@@ -326,7 +331,75 @@ int main(int argc, char **argv) {
 	}
 
 	#else
-	#error Implement build stuff for this platform
+
+	// NOTE: Linux / Unix is unfinished and not tested very well.
+
+
+	timings_start_section(&timings, str_lit("llvm-llc"));
+	// For more arguments: http://llvm.org/docs/CommandGuide/llc.html
+	exit_code = system_exec_command_line_app("llc", false,
+		"llc \"%.*s.bc\" -filetype=obj -O%d "
+		"%.*s "
+		// "-debug-pass=Arguments "
+		"",
+		LIT(output),
+		optimization_level,
+		LIT(build_context.llc_flags));
+	if (exit_code != 0) {
+		return exit_code;
+	}
+
+	timings_start_section(&timings, str_lit("ld-link"));
+
+	gbString lib_str = gb_string_make(heap_allocator(), "");
+	// defer (gb_string_free(lib_str));
+	char lib_str_buf[1024] = {0};
+	for_array(i, ir_gen.module.foreign_library_paths) {
+		String lib = ir_gen.module.foreign_library_paths.e[i];
+		// gb_printf_err("Linking lib: %.*s\n", LIT(lib));
+		isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
+		                        " \"%.*s\"", LIT(lib));
+		lib_str = gb_string_appendc(lib_str, lib_str_buf);
+	}
+
+	// Unlike the Win32 linker code, the output_ext includes the dot, because
+	// typically executable files on *NIX systems don't have extensions.
+	char *output_ext = "";
+	char *link_settings = "";
+	if (build_context.is_dll) {
+		// Shared libraries are .dylib on MacOS and .so on Linux.
+		#if defined(GB_SYSTEM_OSX)
+		output_ext = ".dylib";
+		#else
+		output_ext = ".so";
+		#endif
+
+		link_settings = "-shared";
+	} else {
+		// TODO: Do I need anything here?
+		link_settings = "";
+	}
+
+	exit_code = system_exec_command_line_app("msvc-link", true,
+		"ld \"%.*s\".obj -o \"%.*s.%s\" %s "
+		"-lc "
+		" %.*s "
+		" %s "
+		"",
+		LIT(output), LIT(output), output_ext,
+		lib_str, LIT(build_context.link_flags),
+		link_settings
+		);
+	if (exit_code != 0) {
+		return exit_code;
+	}
+
+	// timings_print_all(&timings);
+
+	if (run_output) {
+		system_exec_command_line_app("odin run", false, "%.*s", cast(int)base_name_len, output_name);
+	}
+
 	#endif
 #endif
 #endif