Browse Source

Add `-debug` command (still in development)

gingerBill 7 years ago
parent
commit
cec9f7abfe
8 changed files with 125 additions and 106 deletions
  1. 1 0
      src/build_settings.cpp
  2. 2 0
      src/common.cpp
  3. 23 1
      src/gb/gb.h
  4. 29 28
      src/ir.cpp
  5. 34 32
      src/ir_print.cpp
  6. 24 16
      src/main.cpp
  7. 1 1
      src/parser.cpp
  8. 11 28
      src/string.cpp

+ 1 - 0
src/build_settings.cpp

@@ -22,6 +22,7 @@ struct BuildContext {
 	i32    optimization_level;
 	i32    optimization_level;
 	bool   show_timings;
 	bool   show_timings;
 	bool   keep_temp_files;
 	bool   keep_temp_files;
+	bool   debug;
 
 
 	gbAffinity affinity;
 	gbAffinity affinity;
 	isize      thread_count;
 	isize      thread_count;

+ 2 - 0
src/common.cpp

@@ -112,6 +112,8 @@ u128 fnv128a(void const *data, isize len) {
 	return h;
 	return h;
 }
 }
 
 
+
+
 #include "map.cpp"
 #include "map.cpp"
 #include "ptr_set.cpp"
 #include "ptr_set.cpp"
 #include "string_set.cpp"
 #include "string_set.cpp"

+ 23 - 1
src/gb/gb.h

@@ -1515,6 +1515,7 @@ typedef struct gbStringHeader {
 
 
 #define GB_STRING_HEADER(str) (cast(gbStringHeader *)(str) - 1)
 #define GB_STRING_HEADER(str) (cast(gbStringHeader *)(str) - 1)
 
 
+GB_DEF gbString gb_string_make_reserve   (gbAllocator a, isize capacity);
 GB_DEF gbString gb_string_make           (gbAllocator a, char const *str);
 GB_DEF gbString gb_string_make           (gbAllocator a, char const *str);
 GB_DEF gbString gb_string_make_length    (gbAllocator a, void const *str, isize num_bytes);
 GB_DEF gbString gb_string_make_length    (gbAllocator a, void const *str, isize num_bytes);
 GB_DEF void     gb_string_free           (gbString str);
 GB_DEF void     gb_string_free           (gbString str);
@@ -6504,6 +6505,27 @@ gb_inline void gb__set_string_length  (gbString str, isize len) { GB_STRING_HEAD
 gb_inline void gb__set_string_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; }
 gb_inline void gb__set_string_capacity(gbString str, isize cap) { GB_STRING_HEADER(str)->capacity = cap; }
 
 
 
 
+gbString gb_string_make_reserve(gbAllocator a, isize capacity) {
+	isize header_size = gb_size_of(gbStringHeader);
+	void *ptr = gb_alloc(a, header_size + capacity + 1);
+
+	gbString str;
+	gbStringHeader *header;
+
+	if (ptr == NULL) return NULL;
+	gb_zero_size(ptr, header_size + capacity + 1);
+
+	str = cast(char *)ptr + header_size;
+	header = GB_STRING_HEADER(str);
+	header->allocator = a;
+	header->length    = 0;
+	header->capacity  = capacity;
+	str[capacity] = '\0';
+
+	return str;
+}
+
+
 gb_inline gbString gb_string_make(gbAllocator a, char const *str) {
 gb_inline gbString gb_string_make(gbAllocator a, char const *str) {
 	isize len = str ? gb_strlen(str) : 0;
 	isize len = str ? gb_strlen(str) : 0;
 	return gb_string_make_length(a, str, len);
 	return gb_string_make_length(a, str, len);
@@ -6516,8 +6538,8 @@ gbString gb_string_make_length(gbAllocator a, void const *init_str, isize num_by
 	gbString str;
 	gbString str;
 	gbStringHeader *header;
 	gbStringHeader *header;
 
 
-	if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1);
 	if (ptr == NULL) return NULL;
 	if (ptr == NULL) return NULL;
+	if (!init_str) gb_zero_size(ptr, header_size + num_bytes + 1);
 
 
 	str = cast(char *)ptr + header_size;
 	str = cast(char *)ptr + header_size;
 	header = GB_STRING_HEADER(str);
 	header = GB_STRING_HEADER(str);

+ 29 - 28
src/ir.cpp

@@ -109,6 +109,16 @@ struct irBranchBlocks {
 };
 };
 
 
 
 
+struct irDebugLocation {
+	TokenPos     pos;
+	irDebugInfo *debug_scope;
+};
+
+struct irDebugScope {
+	irDebugScope *  parent;
+	irDebugLocation loc;
+};
+
 struct irProcedure {
 struct irProcedure {
 	irProcedure *         parent;
 	irProcedure *         parent;
 	Array<irProcedure *>  children;
 	Array<irProcedure *>  children;
@@ -125,6 +135,8 @@ struct irProcedure {
 	bool                  is_export;
 	bool                  is_export;
 	bool                  is_entry_point;
 	bool                  is_entry_point;
 
 
+	irDebugInfo *         debug_scope;
+
 	irValue *             return_ptr;
 	irValue *             return_ptr;
 	Array<irValue *>      params;
 	Array<irValue *>      params;
 	Array<irDefer>        defer_stmts;
 	Array<irDefer>        defer_stmts;
@@ -146,6 +158,9 @@ struct irProcedure {
 	i32                   block_count;
 	i32                   block_count;
 };
 };
 
 
+
+
+
 #define IR_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
 #define IR_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
 #define IR_TYPE_INFO_DATA_NAME       "__$type_info_data"
 #define IR_TYPE_INFO_DATA_NAME       "__$type_info_data"
 #define IR_TYPE_INFO_TYPES_NAME      "__$type_info_types_data"
 #define IR_TYPE_INFO_TYPES_NAME      "__$type_info_types_data"
@@ -231,11 +246,10 @@ struct irProcedure {
 		irValue **args;                                               \
 		irValue **args;                                               \
 		isize     arg_count;                                          \
 		isize     arg_count;                                          \
 		irValue * context_ptr;                                        \
 		irValue * context_ptr;                                        \
-		irDebugInfo *debug_location;                                  \
 	})                                                                \
 	})                                                                \
 	IR_INSTR_KIND(StartupRuntime, i32)                                \
 	IR_INSTR_KIND(StartupRuntime, i32)                                \
 	IR_INSTR_KIND(DebugDeclare, struct {                              \
 	IR_INSTR_KIND(DebugDeclare, struct {                              \
-		irDebugInfo *debug_info;                                      \
+		irDebugInfo *scope;                                           \
 		AstNode *    expr;                                            \
 		AstNode *    expr;                                            \
 		Entity *     entity;                                          \
 		Entity *     entity;                                          \
 		bool         is_addr;                                         \
 		bool         is_addr;                                         \
@@ -388,10 +402,12 @@ struct irValueParam {
 	Array<irValue *> referrers;
 	Array<irValue *> referrers;
 };
 };
 
 
+
 struct irValue {
 struct irValue {
-	irValueKind kind;
-	i32         index;
-	bool        index_set;
+	irValueKind     kind;
+	i32             index;
+	bool            index_set;
+	irDebugLocation loc;
 	union {
 	union {
 		irValueConstant      Constant;
 		irValueConstant      Constant;
 		irValueConstantSlice ConstantSlice;
 		irValueConstantSlice ConstantSlice;
@@ -490,8 +506,6 @@ enum irDebugInfoKind {
 	irDebugInfo_Proc,
 	irDebugInfo_Proc,
 	irDebugInfo_AllProcs,
 	irDebugInfo_AllProcs,
 
 
-	irDebugInfo_Location,
-
 	irDebugInfo_BasicType,      // basic types
 	irDebugInfo_BasicType,      // basic types
 	irDebugInfo_ProcType,
 	irDebugInfo_ProcType,
 	irDebugInfo_DerivedType,    // pointer, typedef
 	irDebugInfo_DerivedType,    // pointer, typedef
@@ -534,11 +548,6 @@ struct irDebugInfo {
 		struct {
 		struct {
 			Array<irDebugInfo *> procs;
 			Array<irDebugInfo *> procs;
 		} AllProcs;
 		} AllProcs;
-		struct {
-			irDebugInfo *scope;
-			TokenPos     pos;
-		} Location;
-
 
 
 		struct {
 		struct {
 			String          name;
 			String          name;
@@ -1070,18 +1079,6 @@ irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, irVa
 	v->Instr.Call.arg_count   = arg_count;
 	v->Instr.Call.arg_count   = arg_count;
 	v->Instr.Call.type        = result_type;
 	v->Instr.Call.type        = result_type;
 	v->Instr.Call.context_ptr = context_ptr;
 	v->Instr.Call.context_ptr = context_ptr;
-
-	irDebugInfo **pp = map_get(&p->module->debug_info, hash_entity(p->entity));
-	if (pp != nullptr) {
-		GB_ASSERT_MSG(pp != nullptr, "%.*s %p", LIT(p->name), p->entity);
-		irDebugInfo *dl = ir_alloc_debug_info(p->module->allocator, irDebugInfo_Location);
-		dl->Location.scope = *pp;
-		dl->Location.pos = p->entity->token.pos;
-		map_set(&p->module->debug_info, hash_pointer(v), dl);
-
-		v->Instr.Call.debug_location = dl;
-	}
-
 	return v;
 	return v;
 }
 }
 
 
@@ -1100,9 +1097,9 @@ irValue *ir_instr_comment(irProcedure *p, String text) {
 	return v;
 	return v;
 }
 }
 
 
-irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) {
+irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *scope, AstNode *expr, Entity *entity, bool is_addr, irValue *value) {
 	irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare);
 	irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare);
-	v->Instr.DebugDeclare.debug_info = debug_info;
+	v->Instr.DebugDeclare.scope      = scope;
 	v->Instr.DebugDeclare.expr       = expr;
 	v->Instr.DebugDeclare.expr       = expr;
 	v->Instr.DebugDeclare.entity     = entity;
 	v->Instr.DebugDeclare.entity     = entity;
 	v->Instr.DebugDeclare.is_addr    = is_addr;
 	v->Instr.DebugDeclare.is_addr    = is_addr;
@@ -1130,7 +1127,6 @@ irValue *ir_value_constant_slice(gbAllocator a, Type *type, irValue *backing_arr
 }
 }
 
 
 
 
-
 irValue *ir_emit(irProcedure *proc, irValue *instr) {
 irValue *ir_emit(irProcedure *proc, irValue *instr) {
 	GB_ASSERT(instr->kind == irValue_Instr);
 	GB_ASSERT(instr->kind == irValue_Instr);
 	irBlock *b = proc->curr_block;
 	irBlock *b = proc->curr_block;
@@ -1519,6 +1515,8 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na
 	di->Proc.file = file;
 	di->Proc.file = file;
 	di->Proc.pos = entity->token.pos;
 	di->Proc.pos = entity->token.pos;
 
 
+	proc->debug_scope = di;
+
 	map_set(&proc->module->debug_info, hash_entity(entity), di);
 	map_set(&proc->module->debug_info, hash_entity(entity), di);
 	return di;
 	return di;
 }
 }
@@ -7665,7 +7663,10 @@ void ir_init_module(irModule *m, Checker *c) {
 	m->tmp_allocator = gb_arena_allocator(&m->tmp_arena);
 	m->tmp_allocator = gb_arena_allocator(&m->tmp_arena);
 	m->info = &c->info;
 	m->info = &c->info;
 
 
-	m->generate_debug_info = build_context.ODIN_OS == "windows" && build_context.word_size == 8;
+	m->generate_debug_info = false;
+	if (build_context.debug) {
+		m->generate_debug_info = build_context.ODIN_OS == "windows" && build_context.word_size == 8;
+	}
 
 
 	map_init(&m->values,                  heap_allocator());
 	map_init(&m->values,                  heap_allocator());
 	map_init(&m->members,                 heap_allocator());
 	map_init(&m->members,                 heap_allocator());

+ 34 - 32
src/ir_print.cpp

@@ -1465,8 +1465,19 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 		}
 		}
 		ir_write_string(f, ")");
 		ir_write_string(f, ")");
 
 
-		if (m->generate_debug_info && call->debug_location) {
-			ir_fprintf(f, ", !dbg !%d", call->debug_location->id);
+		if (m->generate_debug_info) {
+			TokenPos pos = value->loc.pos;
+			irDebugInfo *scope = value->loc.debug_scope;
+			i32 id = 0;
+			irProcedure *proc = instr->parent->parent;
+			if (scope != nullptr) {
+				id = scope->id;
+			} else if (proc->debug_scope != nullptr) {
+				id = proc->debug_scope->id;
+			}
+			if (id > 0) {
+				ir_fprintf(f, ", !dbg !DILocation(line: %td, column: %td, scope: !%d)", pos.line, pos.column, id);
+			}
 		}
 		}
 
 
 		ir_write_string(f, "\n");
 		ir_write_string(f, "\n");
@@ -1632,17 +1643,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
 	#endif
 	#endif
 
 
 	case irInstr_DebugDeclare: {
 	case irInstr_DebugDeclare: {
+		if (!m->generate_debug_info) {
+			break;
+		}
+
 		irInstrDebugDeclare *dd = &instr->DebugDeclare;
 		irInstrDebugDeclare *dd = &instr->DebugDeclare;
 		Type *vt = ir_type(dd->value);
 		Type *vt = ir_type(dd->value);
-		irDebugInfo *di = dd->debug_info;
+		irDebugInfo *di = dd->scope;
 		Entity *e = dd->entity;
 		Entity *e = dd->entity;
 		String name = e->token.string;
 		String name = e->token.string;
 		TokenPos pos = e->token.pos;
 		TokenPos pos = e->token.pos;
 
 
-
-		if (!m->generate_debug_info) {
-			ir_write_string(f, "; ");
-		}
 		ir_write_string(f, "call void @llvm.dbg.declare(");
 		ir_write_string(f, "call void @llvm.dbg.declare(");
 		ir_write_string(f, "metadata ");
 		ir_write_string(f, "metadata ");
 		ir_print_type(f, m, vt);
 		ir_print_type(f, m, vt);
@@ -1762,14 +1773,12 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
 		break;
 		break;
 	}
 	}
 
 
-	if (proc->entity != nullptr) {
-		if (proc->body != nullptr) {
-			irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
-			if (di_ != nullptr) {
-				irDebugInfo *di = *di_;
-				GB_ASSERT(di->kind == irDebugInfo_Proc);
-				ir_fprintf(f, "!dbg !%d ", di->id);
-			}
+	if (m->generate_debug_info && proc->entity != nullptr && proc->body != nullptr) {
+		irDebugInfo **di_ = map_get(&proc->module->debug_info, hash_pointer(proc->entity));
+		if (di_ != nullptr) {
+			irDebugInfo *di = *di_;
+			GB_ASSERT(di->kind == irDebugInfo_Proc);
+			ir_fprintf(f, "!dbg !%d ", di->id);
 		}
 		}
 	}
 	}
 
 
@@ -1846,14 +1855,15 @@ void print_llvm_ir(irGen *ir) {
 	irModule *m = &ir->module;
 	irModule *m = &ir->module;
 	irFileBuffer buf = {}, *f = &buf;
 	irFileBuffer buf = {}, *f = &buf;
 	ir_file_buffer_init(f, &ir->output_file);
 	ir_file_buffer_init(f, &ir->output_file);
+	defer (ir_file_buffer_destroy(f));
 
 
 	if (m->generate_debug_info) {
 	if (m->generate_debug_info) {
-		ir_write_string(f, "target datalayout = \"e-m:w-i64:64-f80:128-n8:16:32:64-S128\"\n");
-		ir_write_string(f, "target triple = \"x86_64-pc-windows-msvc19.11.25508\"\n\n");
+		i32 word_bits = cast(i32)(8*build_context.word_size);
+		ir_fprintf(f, "target datalayout = \"e-m:w-i%d:%d-f80:128-n8:16:32:64-S128\"\n", word_bits, word_bits);
+		ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc17\"\n\n", word_bits == 64 ? "-64" : "");
+		ir_fprintf(f, "\n\n");
 	}
 	}
 
 
-
-
 	ir_print_encoded_local(f, str_lit("..opaque"));
 	ir_print_encoded_local(f, str_lit("..opaque"));
 	ir_write_string(f, str_lit(" = type {};\n"));
 	ir_write_string(f, str_lit(" = type {};\n"));
 	ir_print_encoded_local(f, str_lit("..string"));
 	ir_print_encoded_local(f, str_lit("..string"));
@@ -1870,7 +1880,6 @@ void print_llvm_ir(irGen *ir) {
 	ir_print_encoded_local(f, str_lit("..complex128"));
 	ir_print_encoded_local(f, str_lit("..complex128"));
 	ir_write_string(f, str_lit(" = type {double, double} ; Basic_complex128\n"));
 	ir_write_string(f, str_lit(" = type {double, double} ; Basic_complex128\n"));
 
 
-
 	ir_print_encoded_local(f, str_lit("..any"));
 	ir_print_encoded_local(f, str_lit("..any"));
 	ir_write_string(f, str_lit(" = type {"));
 	ir_write_string(f, str_lit(" = type {"));
 	ir_print_type(f, m, t_rawptr);
 	ir_print_type(f, m, t_rawptr);
@@ -2016,16 +2025,17 @@ void print_llvm_ir(irGen *ir) {
 				            ", runtimeVersion: 0"
 				            ", runtimeVersion: 0"
 				            ", isOptimized: false"
 				            ", isOptimized: false"
 				            ", emissionKind: FullDebug"
 				            ", emissionKind: FullDebug"
+				            ", retainedTypes: !0"
+				            ", enums: !0"
+				            ", globals: !0"
 				            ")",
 				            ")",
 				            file->id, LIT(build_context.ODIN_VERSION));
 				            file->id, LIT(build_context.ODIN_VERSION));
 
 
 				break;
 				break;
 			}
 			}
 			case irDebugInfo_File:
 			case irDebugInfo_File:
-				ir_fprintf(f, "!DIFile(filename: \"");
-				ir_print_escape_path(f, di->File.filename);
-				ir_fprintf(f, "\", directory: \"");
-				ir_print_escape_path(f, di->File.directory);
+				ir_fprintf(f, "!DIFile(filename: \""); ir_print_escape_path(f, di->File.filename);
+				ir_fprintf(f, "\", directory: \""); ir_print_escape_path(f, di->File.directory);
 				ir_fprintf(f, "\"");
 				ir_fprintf(f, "\"");
 				ir_fprintf(f, ")");
 				ir_fprintf(f, ")");
 				break;
 				break;
@@ -2057,12 +2067,6 @@ void print_llvm_ir(irGen *ir) {
 				ir_write_byte(f, '}');
 				ir_write_byte(f, '}');
 				break;
 				break;
 
 
-			case irDebugInfo_Location:
-				GB_ASSERT(di->Location.scope != nullptr);
-				ir_fprintf(f, "!DILocation(line: %td, column: %td, scope: !%d)",
-				           di->Location.pos.line, di->Location.pos.column, di->Location.scope->id);
-				break;
-
 			default:
 			default:
 				GB_PANIC("Unhandled irDebugInfo kind %d", di->kind);
 				GB_PANIC("Unhandled irDebugInfo kind %d", di->kind);
 				break;
 				break;
@@ -2077,6 +2081,4 @@ void print_llvm_ir(irGen *ir) {
 		ir_fprintf(f, "!%d = !{i32 2, !\"CodeView\", i32 1}\n",           di_code_view);
 		ir_fprintf(f, "!%d = !{i32 2, !\"CodeView\", i32 1}\n",           di_code_view);
 		ir_fprintf(f, "!%d = !{i32 1, !\"wchar_size\", i32 2}\n",         di_wchar_size);
 		ir_fprintf(f, "!%d = !{i32 1, !\"wchar_size\", i32 2}\n",         di_wchar_size);
 	}
 	}
-
-	ir_file_buffer_destroy(f);
 }
 }

+ 24 - 16
src/main.cpp

@@ -209,6 +209,7 @@ enum BuildFlagKind {
 	BuildFlag_KeepTempFiles,
 	BuildFlag_KeepTempFiles,
 	BuildFlag_Collection,
 	BuildFlag_Collection,
 	BuildFlag_BuildMode,
 	BuildFlag_BuildMode,
+	BuildFlag_Debug,
 
 
 	BuildFlag_COUNT,
 	BuildFlag_COUNT,
 };
 };
@@ -244,6 +245,7 @@ bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_KeepTempFiles,     str_lit("keep-temp-files"), BuildFlagParam_None);
 	add_flag(&build_flags, BuildFlag_KeepTempFiles,     str_lit("keep-temp-files"), BuildFlagParam_None);
 	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);
 
 
 
 
 	Array<String> flag_args = args;
 	Array<String> flag_args = args;
@@ -483,6 +485,10 @@ bool parse_build_flags(Array<String> args) {
 
 
 							break;
 							break;
 						}
 						}
+
+						case BuildFlag_Debug:
+							build_context.debug = true;
+							break;
 						}
 						}
 					}
 					}
 
 
@@ -778,19 +784,24 @@ int main(int arg_count, char **arg_ptr) {
 		}
 		}
 
 
 		char *output_ext = "exe";
 		char *output_ext = "exe";
-		char *link_settings = "";
+		gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
+		defer (gb_string_free(link_settings));
+
 		if (build_context.is_dll) {
 		if (build_context.is_dll) {
 			output_ext = "dll";
 			output_ext = "dll";
-			link_settings = "/DLL";
+			link_settings = gb_string_append_fmt(link_settings, "/DLL");
 		} else {
 		} else {
-			link_settings = "/ENTRY:mainCRTStartup";
+			link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup");
+		}
+
+		if (build_context.debug) {
+			link_settings = gb_string_append_fmt(link_settings, " /DEBUG /SYMBOLS");
 		}
 		}
 
 
 		exit_code = system_exec_command_line_app("msvc-link", true,
 		exit_code = system_exec_command_line_app("msvc-link", true,
 			"link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
 			"link \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
 			"/defaultlib:libcmt "
 			"/defaultlib:libcmt "
 			// "/nodefaultlib "
 			// "/nodefaultlib "
-			// "/debug "
 			"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
 			"/nologo /incremental:no /opt:ref /subsystem:CONSOLE "
 			" %.*s "
 			" %.*s "
 			" %s "
 			" %s "
@@ -840,9 +851,8 @@ int main(int arg_count, char **arg_ptr) {
 		// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
 		// NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library
 		//                files can be passed with -l:
 		//                files can be passed with -l:
 		gbString lib_str = gb_string_make(heap_allocator(), "-L/");
 		gbString lib_str = gb_string_make(heap_allocator(), "-L/");
-
 		defer (gb_string_free(lib_str));
 		defer (gb_string_free(lib_str));
-		char lib_str_buf[1024] = {0};
+
 		for_array(i, ir_gen.module.foreign_library_paths) {
 		for_array(i, ir_gen.module.foreign_library_paths) {
 			String lib = ir_gen.module.foreign_library_paths[i];
 			String lib = ir_gen.module.foreign_library_paths[i];
 
 
@@ -850,19 +860,18 @@ int main(int arg_count, char **arg_ptr) {
 			//   This allows you to specify '-f' in a #foreign_system_library,
 			//   This allows you to specify '-f' in a #foreign_system_library,
 			//   without having to implement any new syntax specifically for MacOS.
 			//   without having to implement any new syntax specifically for MacOS.
 			#if defined(GB_SYSTEM_OSX)
 			#if defined(GB_SYSTEM_OSX)
-				isize len;
-				if(lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
+				if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') {
 					// framework thingie
 					// framework thingie
-					len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
+					lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2);
 				} else if (string_has_extension(lib, str_lit("a"))) {
 				} else if (string_has_extension(lib, str_lit("a"))) {
 					// static libs, absolute full path relative to the file in which the lib was imported from
 					// static libs, absolute full path relative to the file in which the lib was imported from
-					len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " %.*s ", LIT(lib));
+					lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib));
 				} else if (string_has_extension(lib, str_lit("dylib"))) {
 				} else if (string_has_extension(lib, str_lit("dylib"))) {
 					// dynamic lib, relative path to executable
 					// dynamic lib, relative path to executable
-					len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
+					lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
 				} else {
 				} else {
 					// dynamic or static system lib, just link regularly searching system library paths
 					// dynamic or static system lib, just link regularly searching system library paths
-					len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib));
+					lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
 				}
 				}
 			#else
 			#else
 				// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
 				// NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path,
@@ -872,18 +881,17 @@ int main(int arg_count, char **arg_ptr) {
 				//                the system library paths for the library file).
 				//                the system library paths for the library file).
 				if (string_has_extension(lib, str_lit("a"))) {
 				if (string_has_extension(lib, str_lit("a"))) {
 					// static libs, absolute full path relative to the file in which the lib was imported from
 					// static libs, absolute full path relative to the file in which the lib was imported from
-					isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%.*s ", LIT(lib));
+					lib_str = gb_string_append_fmt(lib_str, " -l:%.*s ", LIT(lib));
 				} else if (string_has_extension(lib, str_lit("so"))) {
 				} else if (string_has_extension(lib, str_lit("so"))) {
 					// dynamic lib, relative path to executable
 					// dynamic lib, relative path to executable
 					// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
 					// NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible
 					//                at runtimeto the executable
 					//                at runtimeto the executable
-					isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l:%s/%.*s ", cwd, LIT(lib));
+					lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib));
 				} else {
 				} else {
 					// dynamic or static system lib, just link regularly searching system library paths
 					// dynamic or static system lib, just link regularly searching system library paths
-					isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), " -l%.*s ", LIT(lib));
+					lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib));
 				}
 				}
 			#endif
 			#endif
-			lib_str = gb_string_appendc(lib_str, lib_str_buf);
 		}
 		}
 
 
 		// Unlike the Win32 linker code, the output_ext includes the dot, because
 		// Unlike the Win32 linker code, the output_ext includes the dot, because

+ 1 - 1
src/parser.cpp

@@ -4679,7 +4679,7 @@ Array<AstNode *> parse_stmt_list(AstFile *f) {
 
 
 ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) {
 ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) {
 	f->fullpath = string_trim_whitespace(fullpath); // Just in case
 	f->fullpath = string_trim_whitespace(fullpath); // Just in case
-	if (!string_has_extension(f->fullpath, str_lit("odin"))) {
+	if (!string_ends_with(f->fullpath, str_lit(".odin"))) {
 		return ParseFile_WrongExtension;
 		return ParseFile_WrongExtension;
 	}
 	}
 	TokenizerInitError err = init_tokenizer(&f->tokenizer, f->fullpath);
 	TokenizerInitError err = init_tokenizer(&f->tokenizer, f->fullpath);

+ 11 - 28
src/string.cpp

@@ -180,17 +180,20 @@ template <isize N> bool operator >= (String const &a, char const (&b)[N]) { retu
 
 
 
 
 
 
-gb_inline bool str_has_prefix(String s, String prefix) {
-	isize i;
-	if (prefix.len < s.len) {
+gb_inline bool string_starts_with(String s, String prefix) {
+	if (prefix.len > s.len) {
 		return false;
 		return false;
 	}
 	}
-	for (i = 0; i < prefix.len; i++) {
-		if (s[i] != prefix[i]) {
-			return false;
-		}
+
+	return substring(s, 0, prefix.len) == prefix;
+}
+
+gb_inline bool string_ends_with(String s, String suffix) {
+	if (suffix.len > s.len) {
+		return false;
 	}
 	}
-	return true;
+
+	return substring(s, s.len-suffix.len, s.len) == suffix;
 }
 }
 
 
 gb_inline isize string_extension_position(String str) {
 gb_inline isize string_extension_position(String str) {
@@ -225,26 +228,6 @@ String string_trim_whitespace(String str) {
 	return str;
 	return str;
 }
 }
 
 
-gb_inline bool string_has_extension(String str, String ext) {
-	str = string_trim_whitespace(str);
-	if (str.len <= ext.len+1) {
-		return false;
-	}
-	isize len = str.len;
-	for (isize i = len-1; i >= 0; i--) {
-		if (str[i] == '.') {
-			break;
-		}
-		len--;
-	}
-	if (len == 0) {
-		return false;
-	}
-
-	u8 *s = str.text + len;
-	return gb_memcompare(s, ext.text, ext.len) == 0;
-}
-
 bool string_contains_char(String s, u8 c) {
 bool string_contains_char(String s, u8 c) {
 	isize i;
 	isize i;
 	for (i = 0; i < s.len; i++) {
 	for (i = 0; i < s.len; i++) {