From 102d080a31f89b5497933ff1622c40df4bcaa6ec Mon Sep 17 00:00:00 2001 From: vassvik Date: Sat, 28 Aug 2021 13:27:41 +0200 Subject: Fix core:c/libc Windows compilation errors by linking to the right libraries. Fix some name typos and missing types in Windows. Add explicit cast on MB_CUR_MAX --- core/c/libc/complex.odin | 6 +++++- core/c/libc/ctype.odin | 6 +++++- core/c/libc/errno.odin | 6 +++++- core/c/libc/math.odin | 6 +++++- core/c/libc/setjmp.odin | 6 +++++- core/c/libc/signal.odin | 6 +++++- core/c/libc/stdio.odin | 6 +++++- core/c/libc/stdlib.odin | 8 ++++++-- core/c/libc/string.odin | 6 +++++- core/c/libc/threads.odin | 10 +++++++--- core/c/libc/time.odin | 6 +++++- core/c/libc/uchar.odin | 6 +++++- core/c/libc/wchar.odin | 6 +++++- core/c/libc/wctype.odin | 6 +++++- 14 files changed, 73 insertions(+), 17 deletions(-) diff --git a/core/c/libc/complex.odin b/core/c/libc/complex.odin index c11e51586..4e199ac69 100644 --- a/core/c/libc/complex.odin +++ b/core/c/libc/complex.odin @@ -2,7 +2,11 @@ package libc // 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") foreign libc { diff --git a/core/c/libc/ctype.odin b/core/c/libc/ctype.odin index 2f9a023a6..0aefc00c3 100644 --- a/core/c/libc/ctype.odin +++ b/core/c/libc/ctype.odin @@ -1,6 +1,10 @@ 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 diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin index 78f6763eb..6d5a6ff0c 100644 --- a/core/c/libc/errno.odin +++ b/core/c/libc/errno.odin @@ -2,7 +2,11 @@ package libc // 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: // EDOM, diff --git a/core/c/libc/math.odin b/core/c/libc/math.odin index b3c285950..ae9e3c709 100644 --- a/core/c/libc/math.odin +++ b/core/c/libc/math.odin @@ -4,7 +4,11 @@ package libc 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, // but we cannot use the same names as exported by libc so use @(link_name) diff --git a/core/c/libc/setjmp.odin b/core/c/libc/setjmp.odin index 57a31301c..e1915c01d 100644 --- a/core/c/libc/setjmp.odin +++ b/core/c/libc/setjmp.odin @@ -2,7 +2,11 @@ package libc // 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" +} @(default_calling_convention="c") foreign libc { diff --git a/core/c/libc/signal.odin b/core/c/libc/signal.odin index 04a2d373f..22bcaec0b 100644 --- a/core/c/libc/signal.odin +++ b/core/c/libc/signal.odin @@ -2,7 +2,11 @@ package libc // 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; diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index 40e32ea07..0f7cb44a7 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -1,6 +1,10 @@ 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 diff --git a/core/c/libc/stdlib.odin b/core/c/libc/stdlib.odin index ce9dc9c4e..ba4602e84 100644 --- a/core/c/libc/stdlib.odin +++ b/core/c/libc/stdlib.odin @@ -2,7 +2,11 @@ package libc // 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" { RAND_MAX :: 0x7fff; @@ -14,7 +18,7 @@ when ODIN_OS == "windows" { } MB_CUR_MAX :: #force_inline proc() -> size_t { - return ___mb_cur_max_func(); + return size_t(___mb_cur_max_func()); } } diff --git a/core/c/libc/string.odin b/core/c/libc/string.odin index 9665a8491..d39b4ecb2 100644 --- a/core/c/libc/string.odin +++ b/core/c/libc/string.odin @@ -3,7 +3,11 @@ package libc // 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 { // 7.24.2 Copying functions diff --git a/core/c/libc/threads.odin b/core/c/libc/threads.odin index 93d4f4efe..cf21bc614 100644 --- a/core/c/libc/threads.odin +++ b/core/c/libc/threads.odin @@ -6,7 +6,10 @@ thrd_start_t :: proc "c" (rawptr) -> int; tss_dtor_t :: proc "c" (rawptr); when ODIN_OS == "windows" { - foreign import libc "system:c" + foreign import libc { + "system:libucrt.lib", + "system:msvcprt.lib" + } thrd_success :: 0; // _Thrd_success thrd_nomem :: 1; // _Thrd_nomem @@ -24,6 +27,7 @@ when ODIN_OS == "windows" { thrd_t :: struct { _: rawptr, _: uint, } // _Thrd_t tss_t :: distinct int; // _Tss_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 // because they held off implementing and C11 support for so @@ -52,9 +56,9 @@ when ODIN_OS == "windows" { @(link_name="_Mtx_unlock") mtx_unlock :: proc(mtx: ^mtx_t) -> int ---; // 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_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_exit") thrd_exit :: proc(res: int) -> ! ---; @(link_name="_Thrd_join") thrd_join :: proc(thr: thrd_t, res: ^int) -> int ---; diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin index 42dd739e2..93574ae38 100644 --- a/core/c/libc/time.odin +++ b/core/c/libc/time.odin @@ -2,7 +2,11 @@ package libc // 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 approach the 2038 problem. Windows has defaulted to this since VC8 (2005). diff --git a/core/c/libc/uchar.odin b/core/c/libc/uchar.odin index 60b71d786..e9adbe13d 100644 --- a/core/c/libc/uchar.odin +++ b/core/c/libc/uchar.odin @@ -2,7 +2,11 @@ package libc // 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") foreign libc { diff --git a/core/c/libc/wchar.odin b/core/c/libc/wchar.odin index d66fa91b7..9851c8053 100644 --- a/core/c/libc/wchar.odin +++ b/core/c/libc/wchar.odin @@ -2,7 +2,11 @@ package libc // 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") foreign libc { diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin index fed258acd..8b887d309 100644 --- a/core/c/libc/wctype.odin +++ b/core/c/libc/wctype.odin @@ -2,7 +2,11 @@ package libc // 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" { wctrans_t :: distinct wchar_t; -- cgit v1.2.3 From 165118c64197bf962e78a9ea354bebe1141b6d7c Mon Sep 17 00:00:00 2001 From: vassvik Date: Sat, 28 Aug 2021 13:32:13 +0200 Subject: Fix runtime crash for setjmp in Windows related to an hidden second argument not normally accessible needing to be set to 0. --- core/c/libc/setjmp.odin | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/core/c/libc/setjmp.odin b/core/c/libc/setjmp.odin index e1915c01d..9eb12853c 100644 --- a/core/c/libc/setjmp.odin +++ b/core/c/libc/setjmp.odin @@ -8,16 +8,35 @@ when ODIN_OS == "windows" { 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. + // + // TODO(mv): Some description of the extra argument, and maybe a link describing + // it in more detail? + @(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") 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 longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---; } -- cgit v1.2.3 From 8ca4286624581dcb39d22a041670bdccca50d194 Mon Sep 17 00:00:00 2001 From: vassvik Date: Sat, 28 Aug 2021 13:32:32 +0200 Subject: Add core:c/libc tests --- core/c/libc/tests/general.odin | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 core/c/libc/tests/general.odin diff --git a/core/c/libc/tests/general.odin b/core/c/libc/tests/general.odin new file mode 100644 index 000000000..1c311a8f3 --- /dev/null +++ b/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(); +} \ No newline at end of file -- cgit v1.2.3 From f9bea5b791514393b3450a7af1dc8192cd34d493 Mon Sep 17 00:00:00 2001 From: vassvik Date: Sat, 28 Aug 2021 13:41:14 +0200 Subject: Updated comment for Windows version of setjmp. --- core/c/libc/setjmp.odin | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/c/libc/setjmp.odin b/core/c/libc/setjmp.odin index 9eb12853c..c5b07b893 100644 --- a/core/c/libc/setjmp.odin +++ b/core/c/libc/setjmp.odin @@ -17,8 +17,19 @@ when ODIN_OS == "windows" { // necessarily export a symbol named setjmp but rather _setjmp in the case // of musl, glibc, BSD libc, and msvcrt. // - // TODO(mv): Some description of the extra argument, and maybe a link describing - // it in more detail? + /// 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 ---; } -- cgit v1.2.3