Parcourir la source

Library names - Only link with used foreign libraries

Ginger Bill il y a 8 ans
Parent
commit
e3e16f5d05
14 fichiers modifiés avec 341 ajouts et 251 suppressions
  1. 1 14
      code/demo.odin
  2. 4 4
      core/_preload.odin
  3. 14 14
      core/math.odin
  4. 3 3
      core/mem.odin
  5. 25 24
      core/opengl.odin
  6. 1 2
      core/os_windows.odin
  7. 85 84
      core/sys/windows.odin
  8. 23 0
      src/check_decl.c
  9. 3 0
      src/check_expr.c
  10. 73 58
      src/checker.c
  11. 15 0
      src/entity.c
  12. 23 1
      src/ir.c
  13. 5 4
      src/main.c
  14. 66 43
      src/parser.c

+ 1 - 14
code/demo.odin

@@ -9,21 +9,8 @@
 #import "sync.odin";
 #import "utf8.odin";
 
-
 main :: proc() {
-	b : [1000]byte;
-
-	using fmt;
-
-	println();
-	println("Pointer of Address 0");
-	println(^b[0]);
-	println();
-	println("Pointer of Address 50");
-	println(^b[50]);
-	println();
-	println("Difference between 50 and 0");
-	println(^b[50] - ^b[0]);
+	fmt.println("GOOGOLPLEX");
 }
 
 /*

+ 4 - 4
core/_preload.odin

@@ -109,11 +109,11 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
 
 
 
-assume :: proc(cond: bool) #foreign "llvm.assume"
+assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume";
 
-__debug_trap       :: proc()        #foreign "llvm.debugtrap"
-__trap             :: proc()        #foreign "llvm.trap"
-read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
+__debug_trap       :: proc()        #foreign __llvm_core "llvm.debugtrap";
+__trap             :: proc()        #foreign __llvm_core "llvm.trap";
+read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
 
 
 Allocator_Mode :: enum u8 {

+ 14 - 14
core/math.odin

@@ -24,14 +24,14 @@ Mat2 :: [2]Vec2;
 Mat3 :: [3]Vec3;
 Mat4 :: [4]Vec4;
 
-sqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32"
-sqrt :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64"
+sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
+sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
 
-sin :: proc(x: f32) -> f32 #foreign "llvm.sin.f32"
-sin :: proc(x: f64) -> f64 #foreign "llvm.sin.f64"
+sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
+sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
 
-cos :: proc(x: f32) -> f32 #foreign "llvm.cos.f32"
-cos :: proc(x: f64) -> f64 #foreign "llvm.cos.f64"
+cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
+cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
 
 tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
 tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
@@ -42,16 +42,16 @@ lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
 sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; }
 sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; }
 
-bit_reverse :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
-bit_reverse :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
-bit_reverse :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
+bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16";
+bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32";
+bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64";
 
-byte_swap :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
-byte_swap :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
-byte_swap :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
+byte_swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16";
+byte_swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
+byte_swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
 
-fmuladd :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
-fmuladd :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
+fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32";
+fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
 
 
 copy_sign :: proc(x, y: f32) -> f32 {

+ 3 - 3
core/mem.odin

@@ -2,7 +2,7 @@
 #import "os.odin";
 
 set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
-	llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
+	llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
 	llvm_memset_64bit(data, cast(byte)value, len, 1, false);
 	return data;
 }
@@ -13,14 +13,14 @@ zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
 
 copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
 	// NOTE(bill): This _must_ implemented like C's memmove
-	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
+	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
 	llvm_memmove_64bit(dst, src, len, 1, false);
 	return dst;
 }
 
 copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
 	// NOTE(bill): This _must_ implemented like C's memcpy
-	llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
+	llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
 	llvm_memcpy_64bit(dst, src, len, 1, false);
 	return dst;
 }

+ 25 - 24
core/opengl.odin

@@ -1,36 +1,37 @@
-#foreign_system_library "opengl32" when ODIN_OS == "windows";
+#foreign_system_library "opengl32.lib" when ODIN_OS == "windows";
 #import win32 "sys/windows.odin" when ODIN_OS == "windows";
 #include "opengl_constants.odin";
 
-Clear         :: proc(mask: u32)                                #foreign "glClear"
-ClearColor    :: proc(r, g, b, a: f32)                          #foreign "glClearColor"
-Begin         :: proc(mode: i32)                                #foreign "glBegin"
-End           :: proc()                                         #foreign "glEnd"
-Finish        :: proc()                                         #foreign "glFinish"
-BlendFunc     :: proc(sfactor, dfactor: i32)                    #foreign "glBlendFunc"
-Enable        :: proc(cap: i32)                                 #foreign "glEnable"
-Disable       :: proc(cap: i32)                                 #foreign "glDisable"
-GenTextures   :: proc(count: i32, result: ^u32)                 #foreign "glGenTextures"
-DeleteTextures:: proc(count: i32, result: ^u32)                 #foreign "glDeleteTextures"
-TexParameteri :: proc(target, pname, param: i32)                #foreign "glTexParameteri"
-TexParameterf :: proc(target: i32, pname: i32, param: f32)      #foreign "glTexParameterf"
-BindTexture   :: proc(target: i32, texture: u32)                #foreign "glBindTexture"
-LoadIdentity  :: proc()                                         #foreign "glLoadIdentity"
-Viewport      :: proc(x, y, width, height: i32)                 #foreign "glViewport"
-Ortho         :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho"
-Color3f       :: proc(r, g, b: f32)                             #foreign "glColor3f"
-Vertex3f      :: proc(x, y, z: f32)                             #foreign "glVertex3f"
+Clear         :: proc(mask: u32)                                #foreign opengl32 "glClear";
+ClearColor    :: proc(r, g, b, a: f32)                          #foreign opengl32 "glClearColor";
+Begin         :: proc(mode: i32)                                #foreign opengl32 "glBegin";
+End           :: proc()                                         #foreign opengl32 "glEnd";
+Finish        :: proc()                                         #foreign opengl32 "glFinish";
+BlendFunc     :: proc(sfactor, dfactor: i32)                    #foreign opengl32 "glBlendFunc";
+Enable        :: proc(cap: i32)                                 #foreign opengl32 "glEnable";
+Disable       :: proc(cap: i32)                                 #foreign opengl32 "glDisable";
+GenTextures   :: proc(count: i32, result: ^u32)                 #foreign opengl32 "glGenTextures";
+DeleteTextures:: proc(count: i32, result: ^u32)                 #foreign opengl32 "glDeleteTextures";
+TexParameteri :: proc(target, pname, param: i32)                #foreign opengl32 "glTexParameteri";
+TexParameterf :: proc(target: i32, pname: i32, param: f32)      #foreign opengl32 "glTexParameterf";
+BindTexture   :: proc(target: i32, texture: u32)                #foreign opengl32 "glBindTexture";
+LoadIdentity  :: proc()                                         #foreign opengl32 "glLoadIdentity";
+Viewport      :: proc(x, y, width, height: i32)                 #foreign opengl32 "glViewport";
+Ortho         :: proc(left, right, bottom, top, near, far: f64) #foreign opengl32 "glOrtho";
+Color3f       :: proc(r, g, b: f32)                             #foreign opengl32 "glColor3f";
+Vertex3f      :: proc(x, y, z: f32)                             #foreign opengl32 "glVertex3f";
 TexImage2D    :: proc(target, level, internal_format,
                       width, height, border,
-                      format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
+                      format, _type: i32, pixels: rawptr) #foreign opengl32 "glTexImage2D";
 
-GetError    :: proc() -> i32            #foreign "glGetError"
-GetString   :: proc(name: i32) -> ^byte #foreign "glGetString"
-GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv"
+GetError    :: proc() -> i32            #foreign opengl32 "glGetError";
+GetString   :: proc(name: i32) -> ^byte #foreign opengl32 "glGetString";
+GetIntegerv :: proc(name: i32, v: ^i32) #foreign opengl32 "glGetIntegerv";
 
 
+string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; }
 
-_libgl := win32.LoadLibraryA((cast(string)"opengl32.dll\x00").data);
+_libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00"));
 
 GetProcAddress :: proc(name: string) -> proc() #cc_c {
 	assert(name[name.count-1] == 0);

+ 1 - 2
core/os_windows.odin

@@ -265,8 +265,7 @@ exit :: proc(code: int) {
 
 
 current_thread_id :: proc() -> int {
-	GetCurrentThreadId :: proc() -> u32 #foreign
-	return cast(int)GetCurrentThreadId();
+	return cast(int)win32.GetCurrentThreadId();
 }
 
 

+ 85 - 84
core/sys/windows.odin

@@ -1,5 +1,8 @@
-#foreign_system_library "user32" when ODIN_OS == "windows";
-#foreign_system_library "gdi32"  when ODIN_OS == "windows";
+#foreign_system_library "kernel32.lib";
+#foreign_system_library "user32.lib";
+#foreign_system_library "gdi32.lib";
+#foreign_system_library "winmm.lib";
+#foreign_system_library "opengl32.lib";
 
 HANDLE    :: rawptr;
 HWND      :: HANDLE;
@@ -124,43 +127,43 @@ GET_FILEEX_INFO_LEVELS :: i32;
 GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0;
 GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
 
-GetLastError     :: proc() -> i32                            #foreign
-ExitProcess      :: proc(exit_code: u32)                     #foreign
-GetDesktopWindow :: proc() -> HWND                           #foreign
-GetCursorPos     :: proc(p: ^POINT) -> i32                   #foreign
-ScreenToClient   :: proc(h: HWND, p: ^POINT) -> i32          #foreign
-GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE      #foreign
-GetStockObject   :: proc(fn_object: i32) -> HGDIOBJ          #foreign
-PostQuitMessage  :: proc(exit_code: i32)                     #foreign
-SetWindowTextA   :: proc(hwnd: HWND, c_string: ^u8) -> BOOL  #foreign
+GetLastError     :: proc() -> i32                            #foreign kernel32;
+ExitProcess      :: proc(exit_code: u32)                     #foreign kernel32;
+GetDesktopWindow :: proc() -> HWND                           #foreign user32;
+GetCursorPos     :: proc(p: ^POINT) -> i32                   #foreign user32;
+ScreenToClient   :: proc(h: HWND, p: ^POINT) -> i32          #foreign user32;
+GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE      #foreign kernel32;
+GetStockObject   :: proc(fn_object: i32) -> HGDIOBJ          #foreign gdi32;
+PostQuitMessage  :: proc(exit_code: i32)                     #foreign user32;
+SetWindowTextA   :: proc(hwnd: HWND, c_string: ^u8) -> BOOL  #foreign user32;
 
-QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign
-QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign
+QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32;
+QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign kernel32;
 
-Sleep :: proc(ms: i32) -> i32 #foreign
+Sleep :: proc(ms: i32) -> i32 #foreign kernel32;
 
-OutputDebugStringA :: proc(c_str: ^u8) #foreign
+OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32;
 
 
-RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign
+RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign user32;
 CreateWindowExA  :: proc(ex_style: u32,
                          class_name, title: ^u8,
                          style: u32,
                          x, y, w, h: i32,
                          parent: HWND, menu: HMENU, instance: HINSTANCE,
-                         param: rawptr) -> HWND #foreign
+                         param: rawptr) -> HWND #foreign user32;
 
-ShowWindow       :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign
-TranslateMessage :: proc(msg: ^MSG) -> BOOL                 #foreign
-DispatchMessageA :: proc(msg: ^MSG) -> LRESULT              #foreign
-UpdateWindow     :: proc(hwnd: HWND) -> BOOL                #foreign
+ShowWindow       :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign user32;
+TranslateMessage :: proc(msg: ^MSG) -> BOOL                 #foreign user32;
+DispatchMessageA :: proc(msg: ^MSG) -> LRESULT              #foreign user32;
+UpdateWindow     :: proc(hwnd: HWND) -> BOOL                #foreign user32;
 PeekMessageA     :: proc(msg: ^MSG, hwnd: HWND,
-                         msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign
+                         msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign user32;
 
-DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign
+DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign user32;
 
-AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign
-GetActiveWindow  :: proc() -> HWND #foreign
+AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
+GetActiveWindow  :: proc() -> HWND #foreign user32;
 
 
 GetQueryPerformanceFrequency :: proc() -> i64 {
@@ -169,34 +172,34 @@ GetQueryPerformanceFrequency :: proc() -> i64 {
 	return r;
 }
 
-GetCommandLineA    :: proc() -> ^u8 #foreign
-GetSystemMetrics   :: proc(index: i32) -> i32 #foreign
-GetCurrentThreadId :: proc() -> u32 #foreign
+GetCommandLineA    :: proc() -> ^u8 #foreign kernel32;
+GetSystemMetrics   :: proc(index: i32) -> i32 #foreign kernel32;
+GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
 
-timeGetTime             :: proc() -> u32 #foreign
-GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign
-FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign
-FileTimeToSystemTime    :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign
-SystemTimeToFileTime    :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign
+timeGetTime             :: proc() -> u32 #foreign winmm;
+GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign kernel32;
+FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign kernel32;
+FileTimeToSystemTime    :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign kernel32;
+SystemTimeToFileTime    :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign kernel32;
 
 // File Stuff
 
-CloseHandle  :: proc(h: HANDLE) -> i32 #foreign
-GetStdHandle :: proc(h: i32) -> HANDLE #foreign
+CloseHandle  :: proc(h: HANDLE) -> i32 #foreign kernel32;
+GetStdHandle :: proc(h: i32) -> HANDLE #foreign kernel32;
 CreateFileA  :: proc(filename: ^u8, desired_access, share_mode: u32,
                      security: rawptr,
-                     creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign
-ReadFile  :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign
-WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign
+                     creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign kernel32;
+ReadFile  :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
+WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
 
-GetFileSizeEx              :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign
-GetFileAttributesExA       :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign
-GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign
+GetFileSizeEx              :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign kernel32;
+GetFileAttributesExA       :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign kernel32;
+GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign kernel32;
 
-GetFileType    :: proc(file_handle: HANDLE) -> u32 #foreign
-SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign
+GetFileType    :: proc(file_handle: HANDLE) -> u32 #foreign kernel32;
+SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
 
-SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign
+SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign kernel32;
 
 HANDLE_FLAG_INHERIT :: 1;
 HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
@@ -250,10 +253,10 @@ INVALID_SET_FILE_POINTER :: ~cast(u32)0;
 
 
 
-HeapAlloc      :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr                 #foreign
-HeapReAlloc    :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign
-HeapFree       :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL               #foreign
-GetProcessHeap :: proc () -> HANDLE #foreign
+HeapAlloc      :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr                 #foreign kernel32;
+HeapReAlloc    :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
+HeapFree       :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL               #foreign kernel32;
+GetProcessHeap :: proc () -> HANDLE #foreign kernel32;
 
 
 HEAP_ZERO_MEMORY :: 0x00000008;
@@ -268,27 +271,27 @@ SECURITY_ATTRIBUTES :: struct #ordered {
 
 INFINITE :: 0xffffffff;
 
-CreateSemaphoreA    :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign
-ReleaseSemaphore    :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign
-WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign
+CreateSemaphoreA    :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign kernel32;
+ReleaseSemaphore    :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign kernel32;
+WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign kernel32;
 
 
-InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign
-InterlockedExchange        :: proc(dst: ^i32, desired: i32) -> i32 #foreign
-InterlockedExchangeAdd     :: proc(dst: ^i32, desired: i32) -> i32 #foreign
-InterlockedAnd             :: proc(dst: ^i32, desired: i32) -> i32 #foreign
-InterlockedOr              :: proc(dst: ^i32, desired: i32) -> i32 #foreign
+InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32;
+InterlockedExchange        :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
+InterlockedExchangeAdd     :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
+InterlockedAnd             :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
+InterlockedOr              :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32;
 
-InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign
-InterlockedExchange64        :: proc(dst: ^i64, desired: i64) -> i64 #foreign
-InterlockedExchangeAdd64     :: proc(dst: ^i64, desired: i64) -> i64 #foreign
-InterlockedAnd64             :: proc(dst: ^i64, desired: i64) -> i64 #foreign
-InterlockedOr64              :: proc(dst: ^i64, desired: i64) -> i64 #foreign
+InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign kernel32;
+InterlockedExchange64        :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
+InterlockedExchangeAdd64     :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
+InterlockedAnd64             :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
+InterlockedOr64              :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32;
 
-_mm_pause        :: proc() #foreign
-ReadWriteBarrier :: proc() #foreign
-WriteBarrier     :: proc() #foreign
-ReadBarrier      :: proc() #foreign
+_mm_pause        :: proc() #foreign kernel32;
+ReadWriteBarrier :: proc() #foreign kernel32;
+WriteBarrier     :: proc() #foreign kernel32;
+ReadBarrier      :: proc() #foreign kernel32;
 
 
 // GDI
@@ -321,17 +324,15 @@ StretchDIBits :: proc (hdc: HDC,
                        x_src, y_src, width_src, header_src: i32,
                        bits: rawptr, bits_info: ^BITMAPINFO,
                        usage: u32,
-                       rop: u32) -> i32 #foreign
+                       rop: u32) -> i32 #foreign gdi32;
 
 
 
-LoadLibraryA   :: proc (c_str: ^u8) -> HMODULE #foreign
-FreeLibrary    :: proc (h: HMODULE) #foreign
-GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign
-
-GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign
-
+LoadLibraryA   :: proc (c_str: ^u8) -> HMODULE #foreign kernel32;
+FreeLibrary    :: proc (h: HMODULE) #foreign kernel32;
+GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign kernel32;
 
+GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign user32;
 
 // Windows OpenGL
 PFD_TYPE_RGBA             :: 0;
@@ -358,7 +359,7 @@ PFD_STEREO_DONTCARE       :: 0x80000000;
 
 HGLRC :: HANDLE;
 PROC  :: type proc() #cc_c;
-wglCreateContextAttribsARBType :: proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
+wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
 
 
 PIXELFORMATDESCRIPTOR :: struct #ordered {
@@ -392,11 +393,11 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
 	damage_mask: u32,
 }
 
-GetDC             :: proc(h: HANDLE) -> HDC #foreign
-SetPixelFormat    :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign
-ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign
-SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign
-ReleaseDC         :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign
+GetDC             :: proc(h: HANDLE) -> HDC #foreign user32;
+SetPixelFormat    :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign user32;
+ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
+SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign user32;
+ReleaseDC         :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
 
 WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091;
 WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092;
@@ -404,15 +405,15 @@ WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126;
 WGL_CONTEXT_CORE_PROFILE_BIT_ARB          :: 0x0001;
 WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002;
 
-wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign
-wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign
-wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign
-wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL #foreign
+wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign opengl32;
+wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32;
+wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32;
+wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32;
 
 
 
-GetKeyState      :: proc(v_key: i32) -> i16 #foreign
-GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
+GetKeyState      :: proc(v_key: i32) -> i16 #foreign user32;
+GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign user32;
 
 is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(cast(i32)key) < 0; }
 

+ 23 - 0
src/check_decl.c

@@ -319,6 +319,29 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
 			name = pd->foreign_name;
 		}
 
+		AstNode *foreign_library = d->proc_lit->ProcLit.foreign_library;
+		if (foreign_library == NULL) {
+			error(e->token, "#foreign procedures must declare which library they are from");
+		} else if (foreign_library->kind != AstNode_Ident) {
+			error_node(foreign_library, "#foreign library names must be an identifier");
+		} else {
+			String name = foreign_library->Ident.string;
+			Entity *found = scope_lookup_entity(c->context.scope, name);
+			if (found == NULL) {
+				if (str_eq(name, str_lit("_"))) {
+					error_node(foreign_library, "`_` cannot be used as a value type");
+				} else {
+					error_node(foreign_library, "Undeclared name: %.*s", LIT(name));
+				}
+			} else if (found->kind != Entity_LibraryName) {
+				error_node(foreign_library, "`_` cannot be used as a library name");
+			} else {
+				// TODO(bill): Extra stuff to do with library names?
+				e->Procedure.foreign_library = found;
+				add_entity_use(c, foreign_library, found);
+			}
+		}
+
 		e->Procedure.is_foreign = true;
 		e->Procedure.foreign_name = name;
 

+ 3 - 0
src/check_expr.c

@@ -985,6 +985,9 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type
 	case Entity_ImportName:
 		error_node(n, "Use of import `%.*s` not in selector", LIT(e->ImportName.name));
 		return;
+	case Entity_LibraryName:
+		error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(e->LibraryName.name));
+		return;
 
 	case Entity_Nil:
 		o->mode = Addressing_Value;

+ 73 - 58
src/checker.c

@@ -266,7 +266,6 @@ typedef struct CheckerInfo {
 	MapIsize             type_info_map;   // Key: Type *
 	isize                type_info_count;
 	Entity *             implicit_values[ImplicitValue_Count];
-	Array(String)        foreign_libraries; // For the linker
 } CheckerInfo;
 
 typedef struct Checker {
@@ -476,7 +475,9 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit
 						continue;
 					}
 
-					if (e->kind == Entity_ImportName && gone_thru_file) {
+					if ((e->kind == Entity_ImportName ||
+					     e->kind == Entity_LibraryName)
+					     && gone_thru_file) {
 						continue;
 					}
 
@@ -515,13 +516,14 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
 	Entity *prev = NULL;
 	if (found) {
 		prev = *found;
-		if (prev->kind != Entity_Procedure &&
+		if (prev->kind != Entity_Procedure ||
 		    entity->kind != Entity_Procedure) {
 			return prev;
 		}
 	}
 
-	if (prev != NULL && entity->kind == Entity_Procedure) {
+	if (prev != NULL &&
+	    entity->kind == Entity_Procedure) {
 		if (s->is_global) {
 			return prev;
 		}
@@ -605,6 +607,9 @@ void init_universal_scope(BuildContext *bc) {
 	add_global_constant(a, str_lit("false"), t_untyped_bool,    make_exact_value_bool(false));
 
 	add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
+	add_global_entity(make_entity_library_name(a,  universal_scope,
+	                                           make_token_ident(str_lit("__llvm_core")), t_invalid,
+	                                           str_lit(""), str_lit("__llvm_core")));
 
 	// TODO(bill): Set through flags in the compiler
 	add_global_string_constant(a, str_lit("ODIN_OS"),      bc->ODIN_OS);
@@ -643,7 +648,6 @@ void init_checker_info(CheckerInfo *i) {
 	map_entity_init(&i->foreign_procs, a);
 	map_isize_init(&i->type_info_map,  a);
 	map_ast_file_init(&i->files,       a);
-	array_init(&i->foreign_libraries,  a);
 	i->type_info_count = 0;
 
 }
@@ -658,7 +662,6 @@ void destroy_checker_info(CheckerInfo *i) {
 	map_entity_destroy(&i->foreign_procs);
 	map_isize_destroy(&i->type_info_map);
 	map_ast_file_destroy(&i->files);
-	array_free(&i->foreign_libraries);
 }
 
 
@@ -843,17 +846,6 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn
 	map_decl_info_set(&c->info.entities, hash_pointer(e), d);
 }
 
-// NOTE(bill): Returns true if it's added
-bool try_add_foreign_library_path(Checker *c, String import_file) {
-	for_array(i, c->info.foreign_libraries) {
-		String import = c->info.foreign_libraries.e[i];
-		if (str_eq(import, import_file)) {
-			return false;
-		}
-	}
-	array_add(&c->info.foreign_libraries, import_file);
-	return true;
-}
 
 
 void add_type_info_type(Checker *c, Type *t) {
@@ -1047,6 +1039,9 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) {
 			if ((e->Procedure.tags & ProcTag_export) != 0) {
 				add_dependency_to_map(&map, info, e);
 			}
+			if (e->Procedure.is_foreign) {
+				add_dependency_to_map(&map, info, e->Procedure.foreign_library);
+			}
 		}
 	}
 
@@ -1555,6 +1550,43 @@ void check_all_global_entities(Checker *c) {
 }
 
 
+String path_to_entity_name(String name, String fullpath) {
+	if (name.len != 0) {
+		return name;
+	}
+	// NOTE(bill): use file name (without extension) as the identifier
+	// If it is a valid identifier
+	String filename = fullpath;
+	isize slash = 0;
+	isize dot = 0;
+	for (isize i = filename.len-1; i >= 0; i--) {
+		u8 c = filename.text[i];
+		if (c == '/' || c == '\\') {
+			break;
+		}
+		slash = i;
+	}
+
+	filename.text += slash;
+	filename.len -= slash;
+
+	dot = filename.len;
+	while (dot --> 0) {
+		u8 c = filename.text[dot];
+		if (c == '.') {
+			break;
+		}
+	}
+
+	filename.len = dot;
+
+	if (is_string_an_identifier(filename)) {
+		return filename;
+	} else {
+		return str_lit("_");
+	}
+}
+
 void check_import_entities(Checker *c, MapScope *file_scopes) {
 	for_array(i, c->delayed_imports) {
 		Scope *parent_scope = c->delayed_imports.e[i].parent;
@@ -1615,49 +1647,23 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
 				if (e->scope == parent_scope) {
 					continue;
 				}
-				// NOTE(bill): Do not add other imported entities
-				bool ok = add_entity(c, parent_scope, NULL, e);
-				if (ok && id->is_import) { // `#import`ed entities don't get exported
-					map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
-				}
-			}
-		} else {
-			String import_name = id->import_name.string;
-			if (import_name.len == 0) {
-				// NOTE(bill): use file name (without extension) as the identifier
-				// If it is a valid identifier
-				String filename = id->fullpath;
-				isize slash = 0;
-				isize dot = 0;
-				for (isize i = filename.len-1; i >= 0; i--) {
-					u8 c = filename.text[i];
-					if (c == '/' || c == '\\') {
-						break;
-					}
-					slash = i;
-				}
-
-				filename.text += slash;
-				filename.len -= slash;
-
-				dot = filename.len;
-				while (dot --> 0) {
-					u8 c = filename.text[dot];
-					if (c == '.') {
-						break;
+				switch (e->kind) {
+				case Entity_ImportName:
+				case Entity_LibraryName:
+					break;
+				default: {
+					bool ok = add_entity(c, parent_scope, NULL, e);
+					if (ok && id->is_import) { // `#import`ed entities don't get exported
+						map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
 					}
-				}
-
-				filename.len = dot;
-
-				if (is_string_an_identifier(filename)) {
-					import_name = filename;
-				} else {
-					error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(filename));
+				} break;
 				}
 			}
-
-			if (import_name.len > 0) {
+		} else {
+			String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
+			if (str_eq(import_name, str_lit("_"))) {
+				error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(id->import_name.string));
+			} else {
 				GB_ASSERT(id->import_name.pos.line != 0);
 				id->import_name.string = import_name;
 				Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
@@ -1690,7 +1696,16 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
 			file_str = import_file;
 		}
 
-		try_add_foreign_library_path(c, file_str);
+		String library_name = path_to_entity_name(fl->library_name.string, file_str);
+		if (str_eq(library_name, str_lit("_"))) {
+			error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
+		} else {
+			GB_ASSERT(fl->library_name.pos.line != 0);
+			fl->library_name.string = library_name;
+			Entity *e = make_entity_library_name(c->allocator, parent_scope, fl->library_name, t_invalid,
+			                                     file_str, library_name);
+			add_entity(c, parent_scope, NULL, e);
+		}
 	}
 }
 

+ 15 - 0
src/entity.c

@@ -12,6 +12,7 @@ typedef enum ImplicitValueId ImplicitValueId;
 	ENTITY_KIND(Procedure) \
 	ENTITY_KIND(Builtin) \
 	ENTITY_KIND(ImportName) \
+	ENTITY_KIND(LibraryName) \
 	ENTITY_KIND(Nil) \
 	ENTITY_KIND(ImplicitValue) \
 	ENTITY_KIND(Count)
@@ -72,6 +73,7 @@ struct Entity {
 		struct {
 			bool         is_foreign;
 			String       foreign_name;
+			Entity *     foreign_library;
 			String       link_name;
 			u64          tags;
 			OverloadKind overload_kind;
@@ -85,6 +87,11 @@ struct Entity {
 			Scope *scope;
 			bool   used;
 		} ImportName;
+		struct {
+			String path;
+			String name;
+			bool   used;
+		} LibraryName;
 		i32 Nil;
 		struct {
 			// TODO(bill): Should this be a user-level construct rather than compiler-level?
@@ -178,6 +185,14 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
 	return entity;
 }
 
+Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type,
+                                 String path, String name) {
+	Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type);
+	entity->LibraryName.path = path;
+	entity->LibraryName.name = name;
+	return entity;
+}
+
 Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
 	Token token = make_token_ident(name);
 	Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);

+ 23 - 1
src/ir.c

@@ -43,13 +43,15 @@ typedef struct irModule {
 
 	Array(irProcedure *) procs;             // NOTE(bill): All procedures with bodies
 	irValueArray         procs_to_generate; // NOTE(bill): Procedures to generate
+
+	Array(String) foreign_library_paths; // Only the ones that were used
 } irModule;
 
 // NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory)
 typedef struct irDomNode {
 	irBlock *        idom; // Parent (Immediate Dominator)
 	Array(irBlock *) children;
-	i32               pre, post; // Ordering in tree
+	i32              pre, post; // Ordering in tree
 } irDomNode;
 
 
@@ -5037,6 +5039,7 @@ void ir_init_module(irModule *m, Checker *c, BuildContext *build_context) {
 	map_string_init(&m->type_names, heap_allocator());
 	array_init(&m->procs,    heap_allocator());
 	array_init(&m->procs_to_generate, heap_allocator());
+	array_init(&m->foreign_library_paths, heap_allocator());
 
 	// Default states
 	m->stmt_state_flags = 0;
@@ -5100,7 +5103,9 @@ void ir_destroy_module(irModule *m) {
 	map_ir_value_destroy(&m->members);
 	map_string_destroy(&m->type_names);
 	map_ir_debug_info_destroy(&m->debug_info);
+	array_free(&m->procs);
 	array_free(&m->procs_to_generate);
+	array_free(&m->foreign_library_paths);
 	gb_arena_free(&m->arena);
 }
 
@@ -5199,6 +5204,22 @@ irValue *ir_type_info_member_offset(irProcedure *proc, irValue *data, isize coun
 	return offset;
 }
 
+void ir_add_foreign_library_path(irModule *m, Entity *e) {
+	GB_ASSERT(e != NULL);
+	String library_path = e->LibraryName.path;
+	if (library_path.len == 0) {
+		return;
+	}
+
+	for_array(path_index, m->foreign_library_paths) {
+		String path = m->foreign_library_paths.e[path_index];
+		if (str_eq(path, library_path)) {
+			return;
+		}
+	}
+	array_add(&m->foreign_library_paths, library_path);
+}
+
 void ir_gen_tree(irGen *s) {
 	irModule *m = &s->module;
 	CheckerInfo *info = m->info;
@@ -5318,6 +5339,7 @@ void ir_gen_tree(irGen *s) {
 			AstNode *body = pd->body;
 			if (e->Procedure.is_foreign) {
 				name = e->token.string; // NOTE(bill): Don't use the mangled name
+				ir_add_foreign_library_path(m, e->Procedure.foreign_library);
 			}
 			if (pd->foreign_name.len > 0) {
 				name = pd->foreign_name;

+ 5 - 4
src/main.c

@@ -235,13 +235,14 @@ int main(int argc, char **argv) {
 
 	timings_start_section(&timings, str_lit("msvc-link"));
 
-	gbString lib_str = gb_string_make(heap_allocator(), "\"Kernel32.lib\"");
+	gbString lib_str = gb_string_make(heap_allocator(), "");
 	// defer (gb_string_free(lib_str));
 	char lib_str_buf[1024] = {0};
-	for_array(i, checker.info.foreign_libraries) {
-		String lib = checker.info.foreign_libraries.e[i];
+	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.lib\"", LIT(lib));
+		                        " \"%.*s\"", LIT(lib));
 		lib_str = gb_string_appendc(lib_str, lib_str_buf);
 	}
 

+ 66 - 43
src/parser.c

@@ -124,11 +124,12 @@ AstNodeArray make_ast_node_array(AstFile *f) {
 		AstNode *expr; \
 	}) \
 	AST_NODE_KIND(ProcLit, "procedure literal", struct { \
-		AstNode *type;         \
-		AstNode *body;         \
-		u64      tags;         \
-		String   foreign_name; \
-		String   link_name;    \
+		AstNode *type;            \
+		AstNode *body;            \
+		u64      tags;            \
+		AstNode *foreign_library; \
+		String   foreign_name;    \
+		String   link_name;       \
 	}) \
 	AST_NODE_KIND(CompoundLit, "compound literal", struct { \
 		AstNode *type; \
@@ -302,6 +303,7 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 	}) \
 	AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
 		Token token, filepath; \
+		Token library_name;     \
 		String base_dir;       \
 		AstNode *cond;         \
 		bool is_system;        \
@@ -774,11 +776,12 @@ AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) {
 }
 
 
-AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String foreign_name, String link_name) {
+AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, AstNode *foreign_library, String foreign_name, String link_name) {
 	AstNode *result = make_node(f, AstNode_ProcLit);
 	result->ProcLit.type = type;
 	result->ProcLit.body = body;
 	result->ProcLit.tags = tags;
+	result->ProcLit.foreign_library = foreign_library;
 	result->ProcLit.foreign_name = foreign_name;
 	result->ProcLit.link_name = link_name;
 	return result;
@@ -1112,14 +1115,6 @@ AstNode *make_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArra
 	return result;
 }
 
-AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, AstNode *cond, bool is_system) {
-	AstNode *result = make_node(f, AstNode_ForeignLibrary);
-	result->ForeignLibrary.token = token;
-	result->ForeignLibrary.filepath = filepath;
-	result->ForeignLibrary.cond = cond;
-	result->ForeignLibrary.is_system = is_system;
-	return result;
-}
 
 AstNode *make_value_decl(AstFile *f, bool is_var, AstNodeArray names, AstNode *type, AstNodeArray values) {
 	AstNode *result = make_node(f, AstNode_ValueDecl);
@@ -1141,6 +1136,16 @@ AstNode *make_import_decl(AstFile *f, Token token, bool is_import, Token relpath
 	return result;
 }
 
+AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, Token library_name, AstNode *cond, bool is_system) {
+	AstNode *result = make_node(f, AstNode_ForeignLibrary);
+	result->ForeignLibrary.token = token;
+	result->ForeignLibrary.filepath = filepath;
+	result->ForeignLibrary.library_name = library_name;
+	result->ForeignLibrary.cond = cond;
+	result->ForeignLibrary.is_system = is_system;
+	return result;
+}
+
 
 bool next_token(AstFile *f) {
 	Token prev = f->curr_token;
@@ -1316,7 +1321,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
 	case AstNode_EnumType:
 		return true;
 	case AstNode_ProcLit:
-		return true;
+		return s->ProcLit.body != NULL;
 
 	case AstNode_ValueDecl:
 		if (!s->ValueDecl.is_var) {
@@ -1366,7 +1371,7 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 
 
 AstNode *    parse_expr(AstFile *f, bool lhs);
-AstNode *    parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_);
+AstNode *    parse_proc_type(AstFile *f, AstNode **foreign_library, String *foreign_name, String *link_name);
 AstNodeArray parse_stmt_list(AstFile *f);
 AstNode *    parse_stmt(AstFile *f);
 AstNode *    parse_body(AstFile *f);
@@ -1508,7 +1513,7 @@ bool is_foreign_name_valid(String name) {
 	return true;
 }
 
-void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) {
+void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) {
 	// TODO(bill): Add this to procedure literals too
 	GB_ASSERT(tags         != NULL);
 	GB_ASSERT(link_name    != NULL);
@@ -1528,6 +1533,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
 
 		if (str_eq(tag_name, str_lit("foreign"))) {
 			check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name);
+			*foreign_library_token = parse_identifier(f);
 			if (f->curr_token.kind == Token_String) {
 				*foreign_name = f->curr_token.string;
 				// TODO(bill): Check if valid string
@@ -1785,9 +1791,10 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 	// Parse Procedure Type or Literal
 	case Token_proc: {
 		Token token = f->curr_token;
+		AstNode *foreign_library = NULL;
 		String foreign_name = {0};
 		String link_name = {0};
-		AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
+		AstNode *type = parse_proc_type(f, &foreign_library, &foreign_name, &link_name);
 		u64 tags = type->ProcType.tags;
 
 		if (f->curr_token.kind == Token_OpenBrace) {
@@ -1800,11 +1807,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 			body = parse_body(f);
 			f->curr_proc = curr_proc;
 
-			return make_proc_lit(f, type, body, tags, foreign_name, link_name);
+			return make_proc_lit(f, type, body, tags, foreign_library, foreign_name, link_name);
 		}
 
 		if ((tags & ProcTag_foreign) != 0) {
-			return make_proc_lit(f, type, NULL, tags, foreign_name, link_name);
+			return make_proc_lit(f, type, NULL, tags, foreign_library, foreign_name, link_name);
 		}
 		if (tags != 0) {
 			syntax_error(token, "A procedure type cannot have tags");
@@ -2312,7 +2319,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
 
 
 
-AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_) {
+AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) {
 	AstNodeArray params = {0};
 	AstNodeArray results = {0};
 
@@ -2322,12 +2329,14 @@ AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_)
 	u64 tags = 0;
 	String foreign_name = {0};
 	String link_name = {0};
+	AstNode *foreign_library = NULL;
 	ProcCallingConvention cc = ProcCC_Odin;
 
-	parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
+	parse_proc_tags(f, &tags, &foreign_library, &foreign_name, &link_name, &cc);
 
-	if (foreign_name_) *foreign_name_ = foreign_name;
-	if (link_name_)    *link_name_    = link_name;
+	if (foreign_library_) *foreign_library_ = foreign_library;
+	if (foreign_name_)    *foreign_name_    = foreign_name;
+	if (link_name_)       *link_name_       = link_name;
 
 	return make_proc_type(f, proc_token, params, results, tags, cc);
 }
@@ -2644,7 +2653,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 
 	case Token_proc: {
 		Token token = f->curr_token;
-		AstNode *pt = parse_proc_type(f, NULL, NULL);
+		AstNode *pt = parse_proc_type(f, NULL, NULL, NULL);
 		if (pt->ProcType.tags != 0) {
 			syntax_error(token, "A procedure type cannot have tags");
 		}
@@ -3327,6 +3336,21 @@ AstNode *parse_stmt(AstFile *f) {
 			return s;
 		} else if (str_eq(tag, str_lit("foreign_system_library"))) {
 			AstNode *cond = NULL;
+			Token lib_name = {0};
+
+			switch (f->curr_token.kind) {
+			case Token_Ident:
+				lib_name = f->curr_token;
+				next_token(f);
+				break;
+			default:
+				lib_name.pos = f->curr_token.pos;
+				break;
+			}
+
+			if (str_eq(lib_name.string, str_lit("_"))) {
+				syntax_error(lib_name, "Illegal #foreign_library name: `_`");
+			}
 			Token file_path = expect_token(f, Token_String);
 
 			if (allow_token(f, Token_when)) {
@@ -3334,7 +3358,7 @@ AstNode *parse_stmt(AstFile *f) {
 			}
 
 			if (f->curr_proc == NULL) {
-				s = make_foreign_library(f, hash_token, file_path, cond, true);
+				s = make_foreign_library(f, hash_token, file_path, lib_name, cond, true);
 			} else {
 				syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope");
 				s = make_bad_decl(f, token, file_path);
@@ -3343,6 +3367,21 @@ AstNode *parse_stmt(AstFile *f) {
 			return s;
 		} else if (str_eq(tag, str_lit("foreign_library"))) {
 			AstNode *cond = NULL;
+			Token lib_name = {0};
+
+			switch (f->curr_token.kind) {
+			case Token_Ident:
+				lib_name = f->curr_token;
+				next_token(f);
+				break;
+			default:
+				lib_name.pos = f->curr_token.pos;
+				break;
+			}
+
+			if (str_eq(lib_name.string, str_lit("_"))) {
+				syntax_error(lib_name, "Illegal #foreign_library name: `_`");
+			}
 			Token file_path = expect_token(f, Token_String);
 
 			if (allow_token(f, Token_when)) {
@@ -3350,7 +3389,7 @@ AstNode *parse_stmt(AstFile *f) {
 			}
 
 			if (f->curr_proc == NULL) {
-				s = make_foreign_library(f, hash_token, file_path, cond, false);
+				s = make_foreign_library(f, hash_token, file_path, lib_name, cond, false);
 			} else {
 				syntax_error(token, "You cannot use #foreign_library within a procedure. This must be done at the file scope");
 				s = make_bad_decl(f, token, file_path);
@@ -3513,22 +3552,6 @@ bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos)
 	return true;
 }
 
-
-// // NOTE(bill): Returns true if it's added
-// bool try_add_foreign_library_path(Parser *p, String import_file) {
-// 	gb_mutex_lock(&p->mutex);
-
-// 	for_array(i, p->foreign_libraries) {
-// 		String import = p->foreign_libraries.e[i];
-// 		if (str_eq(import, import_file)) {
-// 			return false;
-// 		}
-// 	}
-// 	array_add(&p->foreign_libraries, import_file);
-// 	gb_mutex_unlock(&p->mutex);
-// 	return true;
-// }
-
 gb_global Rune illegal_import_runes[] = {
 	'"', '\'', '`', ' ', '\t', '\r', '\n', '\v', '\f',
 	'\\', // NOTE(bill): Disallow windows style filepaths