Browse Source

Merge pull request #3673 from laytan/implement-foreign-import-improvements-on-vendor

Implement `#exists(path)` and use it to provide good errors for common missing vendor libraries
gingerBill 1 year ago
parent
commit
a0b1b8d1c3

+ 18 - 0
.github/workflows/ci.yml

@@ -54,6 +54,12 @@ jobs:
       - name: Odin report
         run: ./odin report
         timeout-minutes: 1
+      - name: Compile needed Vendor
+        run: |
+          make -C $(./odin root)/vendor/stb/src
+          make -C $(./odin root)/vendor/cgltf/src
+          make -C $(./odin root)/vendor/miniaudio/src
+        timeout-minutes: 10
       - name: Odin check
         run: ./odin check examples/demo -vet
         timeout-minutes: 10
@@ -115,6 +121,12 @@ jobs:
       - name: Odin report
         run: ./odin report
         timeout-minutes: 1
+      - name: Compile needed Vendor
+        run: |
+          make -C $(./odin root)/vendor/stb/src
+          make -C $(./odin root)/vendor/cgltf/src
+          make -C $(./odin root)/vendor/miniaudio/src
+        timeout-minutes: 10
       - name: Odin check
         run: ./odin check examples/demo -vet
         timeout-minutes: 10
@@ -159,6 +171,12 @@ jobs:
       - name: Odin report
         run: ./odin report
         timeout-minutes: 1
+      - name: Compile needed Vendor
+        run: |
+          make -C $(./odin root)/vendor/stb/src
+          make -C $(./odin root)/vendor/cgltf/src
+          make -C $(./odin root)/vendor/miniaudio/src
+        timeout-minutes: 10
       - name: Odin check
         run: ./odin check examples/demo -vet
         timeout-minutes: 10

+ 72 - 24
src/check_builtin.cpp

@@ -1079,7 +1079,7 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
 	return false;
 }
 
-gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) {
+gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_, LoadFileTier tier) {
 	ast_node(ce, CallExpr, call);
 	ast_node(bd, BasicDirective, ce->proc);
 	String builtin_name = bd->name.string;
@@ -1105,12 +1105,16 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String
 
 	gbFileError file_error = gbFileError_None;
 	String data = {};
+	bool exists = false;
+	LoadFileTier cache_tier = LoadFileTier_Invalid;
 
 	LoadFileCache **cache_ptr = string_map_get(&c->info->load_file_cache, path);
 	LoadFileCache *cache = cache_ptr ? *cache_ptr : nullptr;
 	if (cache) {
 		file_error = cache->file_error;
 		data = cache->data;
+		exists = cache->exists;
+		cache_tier = cache->tier;
 	}
 	defer ({
 		if (cache == nullptr) {
@@ -1118,60 +1122,78 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String
 			new_cache->path = path;
 			new_cache->data = data;
 			new_cache->file_error = file_error;
+			new_cache->exists = exists;
+			new_cache->tier = cache_tier;
 			string_map_init(&new_cache->hashes, 32);
 			string_map_set(&c->info->load_file_cache, path, new_cache);
 			if (cache_) *cache_ = new_cache;
 		} else {
 			cache->data = data;
 			cache->file_error = file_error;
+			cache->exists = exists;
+			cache->tier = cache_tier;
 			if (cache_) *cache_ = cache;
 		}
 	});
 
-	TEMPORARY_ALLOCATOR_GUARD();
-	char *c_str = alloc_cstring(temporary_allocator(), path);
+	if (tier > cache_tier) {
+		cache_tier = tier;
 
-	gbFile f = {};
-	if (cache == nullptr) {
+		TEMPORARY_ALLOCATOR_GUARD();
+		char *c_str = alloc_cstring(temporary_allocator(), path);
+
+		gbFile f = {};
 		file_error = gb_file_open(&f, c_str);
+		defer (gb_file_close(&f));
+
+		if (file_error == gbFileError_None) {
+			exists = true;
+
+			switch(tier) {
+			case LoadFileTier_Exists:
+				// Nothing to do.
+				break;
+			case LoadFileTier_Contents: {
+				isize file_size = cast(isize)gb_file_size(&f);
+				if (file_size > 0) {
+					u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1);
+					gb_file_read_at(&f, ptr, file_size, 0);
+					ptr[file_size] = '\0';
+					data.text = ptr;
+					data.len = file_size;
+				}
+				break;
+			}
+			default:
+				GB_PANIC("Unhandled LoadFileTier");
+			};
+		}
 	}
-	defer (gb_file_close(&f));
 
 	switch (file_error) {
 	default:
 	case gbFileError_Invalid:
 		if (err_on_not_found) {
-			error(ce->proc, "Failed to `#%.*s` file: %s; invalid file or cannot be found", LIT(builtin_name), c_str);
+			error(ce->proc, "Failed to `#%.*s` file: %.*s; invalid file or cannot be found", LIT(builtin_name), LIT(path));
 		}
 		call->state_flags |= StateFlag_DirectiveWasFalse;
 		return false;
 	case gbFileError_NotExists:
 		if (err_on_not_found) {
-			error(ce->proc, "Failed to `#%.*s` file: %s; file cannot be found", LIT(builtin_name), c_str);
+			error(ce->proc, "Failed to `#%.*s` file: %.*s; file cannot be found", LIT(builtin_name), LIT(path));
 		}
 		call->state_flags |= StateFlag_DirectiveWasFalse;
 		return false;
 	case gbFileError_Permission:
 		if (err_on_not_found) {
-			error(ce->proc, "Failed to `#%.*s` file: %s; file permissions problem", LIT(builtin_name), c_str);
+			error(ce->proc, "Failed to `#%.*s` file: %.*s; file permissions problem", LIT(builtin_name), LIT(path));
 		}
 		call->state_flags |= StateFlag_DirectiveWasFalse;
 		return false;
 	case gbFileError_None:
 		// Okay
 		break;
-	}
-
-	if (cache == nullptr) {
-		isize file_size = cast(isize)gb_file_size(&f);
-		if (file_size > 0) {
-			u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1);
-			gb_file_read_at(&f, ptr, file_size, 0);
-			ptr[file_size] = '\0';
-			data.text = ptr;
-			data.len = file_size;
-		}
-	}
+	};
 
 	return true;
 }
@@ -1263,7 +1285,7 @@ gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand
 	operand->mode = Addressing_Constant;
 
 	LoadFileCache *cache = nullptr;
-	if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) {
+	if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache, LoadFileTier_Contents)) {
 		operand->value = exact_value_string(cache->data);
 		return LoadDirective_Success;
 	}
@@ -1345,6 +1367,8 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c
 			map_set(&c->info->load_directory_map, call, new_cache);
 		} else {
 			cache->file_error = file_error;
+
+			map_set(&c->info->load_directory_map, call, cache);
 		}
 	});
 
@@ -1389,7 +1413,7 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c
 
 		for (FileInfo fi : list) {
 			LoadFileCache *cache = nullptr;
-			if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache)) {
+			if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents)) {
 				array_add(&file_caches, cache);
 			} else {
 				result = LoadDirective_Error;
@@ -1488,6 +1512,30 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
 
 		operand->type = t_source_code_location;
 		operand->mode = Addressing_Value;
+	} else if (name == "exists") {
+		if (ce->args.count != 1) {
+			error(ce->close, "'#exists' expects 1 argument, got %td", ce->args.count);
+			return false;
+		}
+
+		Operand o = {};
+		check_expr(c, &o, ce->args[0]);
+		if (o.mode != Addressing_Constant || !is_type_string(o.type)) {
+			error(ce->args[0], "'#exists' expected a constant string argument");
+			return false;
+		}
+
+		operand->type  = t_untyped_bool;
+		operand->mode  = Addressing_Constant;
+
+		String original_string = o.value.value_string;
+		LoadFileCache *cache = nullptr;
+		if (cache_load_file_directive(c, call, original_string, /* err_on_not_found=*/ false, &cache, LoadFileTier_Exists)) {
+			operand->value = exact_value_bool(cache->exists);
+		} else {
+			operand->value = exact_value_bool(false);
+		}
+
 	} else if (name == "load") {
 		return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success;
 	} else if (name == "load_directory") {
@@ -1540,7 +1588,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
 		String hash_kind = o_hash.value.value_string;
 
 		LoadFileCache *cache = nullptr;
-		if (cache_load_file_directive(c, call, original_string, true, &cache)) {
+		if (cache_load_file_directive(c, call, original_string, true, &cache, LoadFileTier_Contents)) {
 			MUTEX_GUARD(&c->info->load_file_mutex);
 			// TODO(bill): make these procedures fast :P
 			u64 hash_value = 0;

+ 2 - 0
src/check_expr.cpp

@@ -7420,6 +7420,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
 		String name = bd->name.string;
 		if (
 		    name == "location" || 
+		    name == "exists" ||
 		    name == "assert" || 
 		    name == "panic" || 
 		    name == "defined" || 
@@ -8341,6 +8342,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
 		    name == "assert" ||
 		    name == "defined" ||
 		    name == "config" ||
+			name == "exists" ||
 		    name == "load" ||
 		    name == "load_hash" ||
 		    name == "load_directory" ||

+ 9 - 0
src/checker.hpp

@@ -336,7 +336,16 @@ struct ObjcMsgData {
 	ObjcMsgKind kind;
 	Type *proc_type;
 };
+
+enum LoadFileTier {
+	LoadFileTier_Invalid,
+	LoadFileTier_Exists,
+	LoadFileTier_Contents,
+};
+
 struct LoadFileCache {
+	LoadFileTier   tier;
+	bool           exists;
 	String         path;
 	gbFileError    file_error;
 	String         data;

+ 18 - 4
vendor/cgltf/cgltf.odin

@@ -1,9 +1,23 @@
 package cgltf
 
-when ODIN_OS == .Windows      { foreign import lib "lib/cgltf.lib" } 
-else when ODIN_OS == .Linux   { foreign import lib "lib/cgltf.a"        }
-else when ODIN_OS == .Darwin  { foreign import lib "lib/darwin/cgltf.a" }
-else                          { foreign import lib "system:cgltf"          }
+@(private)
+LIB :: (
+	     "lib/cgltf.lib"      when ODIN_OS == .Windows
+	else "lib/cgltf.a"        when ODIN_OS == .Linux
+	else "lib/darwin/cgltf.a" when ODIN_OS == .Darwin
+	else ""
+)
+
+when LIB != "" {
+	when !#exists(LIB) {
+		// Windows library is shipped with the compiler, so a Windows specific message should not be needed.
+		#panic("Could not find the compiled cgltf library, it can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/cgltf/src\"`")
+	}
+
+	foreign import lib { LIB }
+} else {
+	foreign import lib "system:cgltf"
+}
 
 import "core:c"
 

+ 8 - 4
vendor/miniaudio/common.odin

@@ -8,12 +8,16 @@ when MINIAUDIO_SHARED {
 	#panic("Shared linking for miniaudio is not supported yet")
 }
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
+@(private)
+LIB :: "lib/miniaudio.lib" when ODIN_OS == .Windows else "lib/miniaudio.a"
+
+when !#exists(LIB) {
+	// Windows library is shipped with the compiler, so a Windows specific message should not be needed.
+	#panic("Could not find the compiled miniaudio library, it can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/miniaudio/src\"`")
 }
 
+foreign import lib { LIB }
+
 BINDINGS_VERSION_MAJOR    :: 0
 BINDINGS_VERSION_MINOR    :: 11
 BINDINGS_VERSION_REVISION :: 21 

+ 1 - 5
vendor/miniaudio/data_conversion.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /************************************************************************************************************************************************************
 *************************************************************************************************************************************************************

+ 1 - 5
vendor/miniaudio/decoding.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /************************************************************************************************************************************************************
 

+ 1 - 5
vendor/miniaudio/device_io_procs.odin

@@ -1,10 +1,6 @@
 package miniaudio
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 import "core:c"
 

+ 1 - 5
vendor/miniaudio/effects.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /*
 Delay

+ 1 - 5
vendor/miniaudio/encoding.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /************************************************************************************************************************************************************
 

+ 1 - 5
vendor/miniaudio/engine.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /************************************************************************************************************************************************************
 

+ 1 - 5
vendor/miniaudio/filtering.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /**************************************************************************************************************************************************************
 

+ 1 - 5
vendor/miniaudio/generation.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 waveform_type :: enum c.int {
 	sine,

+ 1 - 5
vendor/miniaudio/job_queue.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /*
 Slot Allocator

+ 1 - 5
vendor/miniaudio/logging.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c/libc"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 MAX_LOG_CALLBACKS :: 4
 

+ 1 - 5
vendor/miniaudio/node_graph.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /************************************************************************************************************************************************************
 

+ 1 - 5
vendor/miniaudio/resource_manager.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /************************************************************************************************************************************************************
 

+ 1 - 5
vendor/miniaudio/synchronization.odin

@@ -1,10 +1,6 @@
 package miniaudio
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 @(default_calling_convention="c", link_prefix="ma_")
 foreign lib {

+ 1 - 5
vendor/miniaudio/utilities.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 @(default_calling_convention="c", link_prefix="ma_")
 foreign lib {

+ 1 - 5
vendor/miniaudio/vfs.odin

@@ -2,11 +2,7 @@ package miniaudio
 
 import "core:c"
 
-when ODIN_OS == .Windows {
-	foreign import lib "lib/miniaudio.lib"
-} else {
-	foreign import lib "lib/miniaudio.a"
-}
+foreign import lib { LIB }
 
 /************************************************************************************************************************************************************
 

+ 19 - 6
vendor/stb/image/stb_image.odin

@@ -2,13 +2,26 @@ package stb_image
 
 import c "core:c/libc"
 
-#assert(size_of(c.int) == size_of(b32))
-
-     when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib"      }
-else when ODIN_OS == .Linux   { foreign import stbi "../lib/stb_image.a"        }
-else when ODIN_OS == .Darwin  { foreign import stbi "../lib/darwin/stb_image.a" }
-else                          { foreign import stbi "system:stb_image"          }
+@(private)
+LIB :: (
+	     "../lib/stb_image.lib"      when ODIN_OS == .Windows
+	else "../lib/stb_image.a"        when ODIN_OS == .Linux
+	else "../lib/darwin/stb_image.a" when ODIN_OS == .Darwin
+	else ""
+)
+
+when LIB != "" {
+	when !#exists(LIB) {
+		// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
+		#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
+	}
+
+	foreign import stbi { LIB }
+} else {
+	foreign import stbi "system:stb_image"
+}
 
+#assert(size_of(c.int) == size_of(b32))
 #assert(size_of(b32) == size_of(c.int))
 
 //

+ 18 - 5
vendor/stb/image/stb_image_resize.odin

@@ -2,11 +2,24 @@ package stb_image
 
 import c "core:c/libc"
 
-     when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib"      }
-else when ODIN_OS == .Linux   { foreign import lib "../lib/stb_image_resize.a"        }
-else when ODIN_OS == .Darwin  { foreign import lib "../lib/darwin/stb_image_resize.a" }
-else                          { foreign import lib "system:stb_image_resize"         }
-
+@(private)
+RESIZE_LIB :: (
+	     "../lib/stb_image_resize.lib"      when ODIN_OS == .Windows
+	else "../lib/stb_image_resize.a"        when ODIN_OS == .Linux
+	else "../lib/darwin/stb_image_resize.a" when ODIN_OS == .Darwin
+	else ""
+)
+
+when RESIZE_LIB != "" {
+	when !#exists(RESIZE_LIB) {
+		// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
+		#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
+	}
+
+	foreign import lib { RESIZE_LIB }
+} else {
+	foreign import lib "system:stb_image_resize"
+}
 
 //////////////////////////////////////////////////////////////////////////////
 //

+ 17 - 4
vendor/stb/image/stb_image_write.odin

@@ -2,11 +2,24 @@ package stb_image
 
 import c "core:c/libc"
 
-     when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib"      }
-else when ODIN_OS == .Linux   { foreign import stbiw "../lib/stb_image_write.a"        }
-else when ODIN_OS == .Darwin  { foreign import stbiw "../lib/darwin/stb_image_write.a" }
-else                          { foreign import stbiw "system:stb_image_write"           }
+@(private)
+WRITE_LIB :: (
+	     "../lib/stb_image_write.lib"      when ODIN_OS == .Windows
+	else "../lib/stb_image_write.a"        when ODIN_OS == .Linux
+	else "../lib/darwin/stb_image_write.a" when ODIN_OS == .Darwin
+	else ""
+)
 
+when WRITE_LIB != "" {
+	when !#exists(WRITE_LIB) {
+		// The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed.
+		#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
+	}
+
+	foreign import stbiw { WRITE_LIB }
+} else {
+	foreign import stbiw "system:stb_image_write"
+}
 
 write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int)
 

+ 17 - 4
vendor/stb/rect_pack/stb_rect_pack.odin

@@ -4,10 +4,23 @@ import "core:c"
 
 #assert(size_of(b32) == size_of(c.int))
 
-     when ODIN_OS == .Windows { foreign import lib "../lib/stb_rect_pack.lib"      }
-else when ODIN_OS == .Linux   { foreign import lib "../lib/stb_rect_pack.a"        }
-else when ODIN_OS == .Darwin  { foreign import lib "../lib/darwin/stb_rect_pack.a" }
-else                          { foreign import lib "system:stb_rect_pack"          }
+@(private)
+LIB :: (
+	     "../lib/stb_rect_pack.lib"      when ODIN_OS == .Windows
+	else "../lib/stb_rect_pack.a"        when ODIN_OS == .Linux
+	else "../lib/darwin/stb_rect_pack.a" when ODIN_OS == .Darwin
+	else ""
+)
+
+when LIB != "" {
+	when !#exists(LIB) {
+		#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
+	}
+
+	foreign import lib { LIB }
+} else {
+	foreign import lib "system:stb_rect_pack"
+}
 
 Coord :: distinct c.int
 _MAXVAL :: max(Coord)

+ 1 - 1
vendor/stb/src/Makefile

@@ -14,7 +14,7 @@ unix:
 	$(AR) rcs ../lib/stb_image_resize.a stb_image_resize.o
 	$(AR) rcs ../lib/stb_truetype.a     stb_truetype.o
 	$(AR) rcs ../lib/stb_rect_pack.a    stb_rect_pack.o
-	#$(AR) rcs ../lib/stb_vorbis_pack.a  stb_vorbis_pack.o
+	$(AR) rcs ../lib/stb_vorbis.a       stb_vorbis.o
 	#$(CC) -fPIC -shared -Wl,-soname=stb_image.so         -o ../lib/stb_image.so        stb_image.o
 	#$(CC) -fPIC -shared -Wl,-soname=stb_image_write.so   -o ../lib/stb_image_write.so  stb_image_write.o
 	#$(CC) -fPIC -shared -Wl,-soname=stb_image_resize.so  -o ../lib/stb_image_resize.so stb_image_resize.o

+ 17 - 5
vendor/stb/truetype/stb_truetype.odin

@@ -3,11 +3,23 @@ package stb_truetype
 import c "core:c"
 import stbrp "vendor:stb/rect_pack"
 
-     when ODIN_OS == .Windows { foreign import stbtt "../lib/stb_truetype.lib"      }
-else when ODIN_OS == .Linux   { foreign import stbtt "../lib/stb_truetype.a"        }
-else when ODIN_OS == .Darwin  { foreign import stbtt "../lib/darwin/stb_truetype.a" }
-else                          { foreign import stbtt "system:stb_truetype"          }
-
+@(private)
+LIB :: (
+	     "../lib/stb_truetype.lib"      when ODIN_OS == .Windows
+	else "../lib/stb_truetype.a"        when ODIN_OS == .Linux
+	else "../lib/darwin/stb_truetype.a" when ODIN_OS == .Darwin
+	else ""
+)
+
+when LIB != "" {
+	when !#exists(LIB) {
+		#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
+	}
+
+	foreign import stbtt { LIB }
+} else {
+	foreign import stbtt "system:stb_truetype"
+}
 
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////

+ 17 - 7
vendor/stb/vorbis/stb_vorbis.odin

@@ -2,13 +2,23 @@ package stb_vorbis
 
 import c "core:c/libc"
 
-
-     when ODIN_OS == .Windows { foreign import lib "../lib/stb_vorbis.lib"      }
-else when ODIN_OS == .Linux   { foreign import lib "../lib/stb_vorbis.a"        }
-else when ODIN_OS == .Darwin  { foreign import lib "../lib/darwin/stb_vorbis.a" }
-else                          { foreign import lib "system:stb_vorbis"          }
-
-
+@(private)
+LIB :: (
+	     "../lib/stb_vorbis.lib"      when ODIN_OS == .Windows
+	else "../lib/stb_vorbis.a"        when ODIN_OS == .Linux
+	else "../lib/darwin/stb_vorbis.a" when ODIN_OS == .Darwin
+	else ""
+)
+
+when LIB != "" {
+	when !#exists(LIB) {
+		#panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`")
+	}
+
+	foreign import lib { LIB }
+} else {
+	foreign import lib "system:stb_vorbis"
+}
 
 ///////////   THREAD SAFETY