Browse Source

Merge pull request #1107 from odin-lang/mv/libc-errors

Fix libc errors in Windows and add some tests.
gingerBill 4 years ago
parent
commit
713cd728ba

+ 5 - 1
core/c/libc/complex.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.3 Complex arithmetic
 // 7.3 Complex arithmetic
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 @(default_calling_convention="c")
 @(default_calling_convention="c")
 foreign libc {
 foreign libc {

+ 5 - 1
core/c/libc/ctype.odin

@@ -1,6 +1,10 @@
 package libc
 package libc
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 // 7.4 Character handling
 // 7.4 Character handling
 
 

+ 5 - 1
core/c/libc/errno.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.5 Errors
 // 7.5 Errors
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 // C11 standard only requires the definition of:
 // C11 standard only requires the definition of:
 //	EDOM,
 //	EDOM,

+ 5 - 1
core/c/libc/math.odin

@@ -4,7 +4,11 @@ package libc
 
 
 import "core:intrinsics"
 import "core:intrinsics"
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 // To support C's tgmath behavior we use Odin's explicit procedure overloading,
 // To support C's tgmath behavior we use Odin's explicit procedure overloading,
 // but we cannot use the same names as exported by libc so use @(link_name)
 // but we cannot use the same names as exported by libc so use @(link_name)

+ 43 - 9
core/c/libc/setjmp.odin

@@ -2,18 +2,52 @@ package libc
 
 
 // 7.13 Nonlocal jumps
 // 7.13 Nonlocal jumps
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
+
+when ODIN_OS == "windows" {
+	@(default_calling_convention="c")
+	foreign libc {
+		// 7.13.1 Save calling environment
+		//
+		// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
+		// necessarily export a symbol named setjmp but rather _setjmp in the case
+		// of musl, glibc, BSD libc, and msvcrt.
+		//
+		/// NOTE(dweiler): UCRT has two implementations of longjmp. One that performs
+		// stack unwinding and one that doesn't. The choice of which to use depends on a
+		// flag which is set inside the jmp_buf structure given to setjmp. The default
+		// behavior is to unwind the stack. Within Odin, we cannot use the stack
+		// unwinding version as the unwinding information isn't present. To opt-in to
+		// the regular non-unwinding version we need a way to set this flag. Since the
+		// location of the flag within the struct is not defined or part of the ABI and
+		// can change between versions of UCRT, we must rely on setjmp to set it. It
+		// turns out that setjmp receives this flag in the RDX register on Win64, this
+		// just so happens to coincide with the second argument of a function in the
+		// Win64 ABI. By giving our setjmp a second argument with the value of zero,
+		// the RDX register will contain zero and correctly set the flag to disable
+		// stack unwinding.
+		@(link_name="_setjmp")
+		setjmp  :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int ---;
+	}
+} else {
+	@(default_calling_convention="c")
+	foreign libc {
+		// 7.13.1 Save calling environment
+		//
+		// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
+		// necessarily export a symbol named setjmp but rather _setjmp in the case
+		// of musl, glibc, BSD libc, and msvcrt.
+		@(link_name="_setjmp")
+		setjmp  :: proc(env: ^jmp_buf) -> int ---;
+	}
+}
 
 
 @(default_calling_convention="c")
 @(default_calling_convention="c")
 foreign libc {
 foreign libc {
-	// 7.13.1 Save calling environment
-	//
-	// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
-	// necessarily export a symbol named setjmp but rather _setjmp in the case
-	// of musl, glibc, BSD libc, and msvcrt.
-	@(link_name="_setjmp")
-	setjmp  :: proc(env: ^jmp_buf) -> int ---;
-
 	// 7.13.2 Restore calling environment
 	// 7.13.2 Restore calling environment
 	longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---;
 	longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---;
 }
 }

+ 5 - 1
core/c/libc/signal.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.14 Signal handling
 // 7.14 Signal handling
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 sig_atomic_t :: distinct atomic_int;
 sig_atomic_t :: distinct atomic_int;
 
 

+ 5 - 1
core/c/libc/stdio.odin

@@ -1,6 +1,10 @@
 package libc
 package libc
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 // 7.21 Input/output
 // 7.21 Input/output
 
 

+ 6 - 2
core/c/libc/stdlib.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.22 General utilities
 // 7.22 General utilities
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 when ODIN_OS == "windows" {
 when ODIN_OS == "windows" {
 	RAND_MAX :: 0x7fff;
 	RAND_MAX :: 0x7fff;
@@ -14,7 +18,7 @@ when ODIN_OS == "windows" {
 	}
 	}
 
 
 	MB_CUR_MAX :: #force_inline proc() -> size_t {
 	MB_CUR_MAX :: #force_inline proc() -> size_t {
-		return ___mb_cur_max_func();
+		return size_t(___mb_cur_max_func());
 	}
 	}
 }
 }
 
 

+ 5 - 1
core/c/libc/string.odin

@@ -3,7 +3,11 @@ package libc
 
 
 // 7.24 String handling
 // 7.24 String handling
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 foreign libc {
 foreign libc {
 	// 7.24.2 Copying functions
 	// 7.24.2 Copying functions

+ 50 - 0
core/c/libc/tests/general.odin

@@ -0,0 +1,50 @@
+package libc_tests
+
+import "core:c/libc"
+
+test_stdio :: proc() {
+    c: libc.char = 'C';
+    libc.puts("Hello from puts");
+    libc.printf("Hello from printf in %c\n", c);
+}
+test_thread :: proc() {
+    thread_proc :: proc "c" (rawptr) -> libc.int {
+        libc.printf("Hello from thread");
+        return 42;
+    }
+    thread: libc.thrd_t;
+    libc.thrd_create(&thread, thread_proc, nil);
+    result: libc.int;
+    libc.thrd_join(thread, &result);
+    libc.printf(" %d\n", result);
+}
+
+jmp: libc.jmp_buf;
+test_sjlj :: proc() {
+    if libc.setjmp(&jmp) != 0 {
+        libc.printf("Hello from longjmp\n");
+        return;
+    }
+    libc.printf("Hello from setjmp\n");
+    libc.longjmp(&jmp, 1);
+}
+test_signal :: proc() {
+    handler :: proc "c" (sig: libc.int) {
+        libc.printf("Hello from signal handler\n");
+    }
+    libc.signal(libc.SIGABRT, handler);
+    libc.raise(libc.SIGABRT);
+}
+test_atexit :: proc() {
+    handler :: proc "c" () {
+        libc.printf("Hello from atexit\n");
+    }
+    libc.atexit(handler);
+}
+main :: proc() {
+    test_stdio();
+    test_thread();
+    test_sjlj();
+    test_signal();
+    test_atexit();
+}

+ 7 - 3
core/c/libc/threads.odin

@@ -6,7 +6,10 @@ thrd_start_t :: proc "c" (rawptr) -> int;
 tss_dtor_t   :: proc "c" (rawptr);
 tss_dtor_t   :: proc "c" (rawptr);
 
 
 when ODIN_OS == "windows" {
 when ODIN_OS == "windows" {
-	foreign import libc "system:c"
+	foreign import libc {
+		"system:libucrt.lib", 
+		"system:msvcprt.lib"
+	}
 
 
 	thrd_success        :: 0;                             // _Thrd_success
 	thrd_success        :: 0;                             // _Thrd_success
 	thrd_nomem          :: 1;                             // _Thrd_nomem
 	thrd_nomem          :: 1;                             // _Thrd_nomem
@@ -24,6 +27,7 @@ when ODIN_OS == "windows" {
 	thrd_t              :: struct { _: rawptr, _: uint, } // _Thrd_t
 	thrd_t              :: struct { _: rawptr, _: uint, } // _Thrd_t
 	tss_t               :: distinct int;                  // _Tss_imp_t
 	tss_t               :: distinct int;                  // _Tss_imp_t
 	cnd_t               :: distinct rawptr;               // _Cnd_imp_t
 	cnd_t               :: distinct rawptr;               // _Cnd_imp_t
+	mtx_t               :: distinct rawptr;               // _Mtx_imp_t
 
 
 	// MSVCRT does not expose the C11 symbol names as what they are in C11
 	// MSVCRT does not expose the C11 symbol names as what they are in C11
 	// because they held off implementing <threads.h> and C11 support for so
 	// because they held off implementing <threads.h> and C11 support for so
@@ -52,9 +56,9 @@ when ODIN_OS == "windows" {
 		@(link_name="_Mtx_unlock")    mtx_unlock    :: proc(mtx: ^mtx_t) -> int ---;
 		@(link_name="_Mtx_unlock")    mtx_unlock    :: proc(mtx: ^mtx_t) -> int ---;
 
 
 		// 7.26.5 Thread functions
 		// 7.26.5 Thread functions
-		@(link_name="_Thrd_create")   thrd_create   :: proc(thr: ^thr_t, func: thrd_start_t, arg: rawptr) -> int ---;
+		@(link_name="_Thrd_create")   thrd_create   :: proc(thr: ^thrd_t, func: thrd_start_t, arg: rawptr) -> int ---;
 		@(link_name="_Thrd_current")  thrd_current  :: proc() -> thrd_t ---;
 		@(link_name="_Thrd_current")  thrd_current  :: proc() -> thrd_t ---;
-		@(link_name="_Thrd_detach")   thrd_detach   :: proc(thr: thr_t) -> int ---;
+		@(link_name="_Thrd_detach")   thrd_detach   :: proc(thr: thrd_t) -> int ---;
 		@(link_name="_Thrd_equal")    thrd_equal    :: proc(lhs, rhs: thrd_t) -> int ---;
 		@(link_name="_Thrd_equal")    thrd_equal    :: proc(lhs, rhs: thrd_t) -> int ---;
 		@(link_name="_Thrd_exit")     thrd_exit     :: proc(res: int) -> ! ---;
 		@(link_name="_Thrd_exit")     thrd_exit     :: proc(res: int) -> ! ---;
 		@(link_name="_Thrd_join")     thrd_join     :: proc(thr: thrd_t, res: ^int) -> int ---;
 		@(link_name="_Thrd_join")     thrd_join     :: proc(thr: thrd_t, res: ^int) -> int ---;

+ 5 - 1
core/c/libc/time.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.27 Date and time
 // 7.27 Date and time
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 // We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
 // We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
 // we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
 // we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).

+ 5 - 1
core/c/libc/uchar.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.28 Unicode utilities
 // 7.28 Unicode utilities
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 @(default_calling_convention="c")
 @(default_calling_convention="c")
 foreign libc {
 foreign libc {

+ 5 - 1
core/c/libc/wchar.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.29 Extended multibyte and wide character utilities
 // 7.29 Extended multibyte and wide character utilities
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 @(default_calling_convention="c")
 @(default_calling_convention="c")
 foreign libc {
 foreign libc {

+ 5 - 1
core/c/libc/wctype.odin

@@ -2,7 +2,11 @@ package libc
 
 
 // 7.30 Wide character classification and mapping utilities
 // 7.30 Wide character classification and mapping utilities
 
 
-foreign import libc "system:c"
+when ODIN_OS == "windows" {
+	foreign import libc "system:libucrt.lib"
+} else {
+	foreign import libc "system:c"
+}
 
 
 when ODIN_OS == "windows" {
 when ODIN_OS == "windows" {
 	wctrans_t :: distinct wchar_t;
 	wctrans_t :: distinct wchar_t;