diff --git a/cmd/v/help/build-c.txt b/cmd/v/help/build-c.txt index 8973a6dc8b..01b1360ab0 100644 --- a/cmd/v/help/build-c.txt +++ b/cmd/v/help/build-c.txt @@ -31,42 +31,51 @@ see also `v help build`. -bare-builtin-dir Use with `-freestanding`. This specifies the directory to the implementation of some basic builtin functions. The list is as follows: - memcpy(dest &byte, src &byte, n int) &byte - Moves n bytes from dest to src, and returns dest - [export: 'malloc'] - __malloc(n int) &byte - Allocates n bytes of memory and returns the pointer to the first byte - strlen(s &byte) int - Returns the amount of bytes until the first `0`, starting at s - realloc(old_area &byte, new_size int) &byte - Allocates a new area of size new_size, copies old_area - to the new area, and returns a pointer to the new area. - memset(s &byte, c int, n int) &byte - Sets n bytes starting at s to c (c is casted to a char) - and returns s. - memmove(dest &byte, src &byte, n int) &byte - Like memcpy, but guaranteed to work if dest and src overlap. - [export: 'calloc'] - __calloc(nmemb int, size int) &byte - Like malloc, but sets all the bytes to `0` first. - getchar() int - Read one character from stdin and return it. - memcmp(a &byte, b &byte, n int) int - Compare two buffers of length n. If a and b are equal, return 0. - Otherwise, return the difference between the first different letter. - [export: 'free'] - __free(ptr &byte) - Free the block of memory ptr allocated by malloc. - vsprintf(str &char, format &char, ap va_list) int - See `man vsprintf`. - vsnprintf(str &char, size int, format &char, ap va_list) int - See `man vsnprintf`. bare_print(buf &byte, len u64) Print len charecters from the buffer pointed to by buf to stdout. bare_eprint(buf &byte, len u64) Print len charecters from the buffer pointed to by buf to stderr. + bare_panic(msg string) + Print "V panic: " + msg, along with an optional backtrace and/or the V commit hash, and then exit. + [export: 'malloc'] + __malloc(n size_t) &C.void + Allocates n bytes of memory and returns the pointer to the first byte + [export: 'free'] + __free(ptr &C.void) + Free the block of memory ptr allocated by malloc. + realloc(old_area &C.void, new_size size_t) &C.void + Allocates a new area of size new_size, copies old_area + to the new area, and returns a pointer to the new area. + [export: 'calloc'] + __calloc(nmemb size_t, size size_t) &C.void + Like malloc, but sets all the bytes to `0` first. + memcpy(dest &C.void, src &C.void, n size_t) &C.void + Moves n bytes from dest to src, and returns dest + memmove(dest &C.void, src &C.void, n size_t) &C.void + Like memcpy, but guaranteed to work if dest and src overlap. + memcmp(a &C.void, b &C.void, n size_t) int + Compare two buffers of length n. If a and b are equal, return 0. + Otherwise, return the difference between the first different letter. + strlen(s &C.void) size_t + Returns the amount of bytes until the first `0`, starting at s + memset(s &C.void, c int, n size_t) &C.void + Sets n bytes starting at s to c (c is casted to a char) + and returns s. + getchar() int + Read one character from stdin and return it. + Print "V Panic" + msg, along with an optional backtrace, and then exit. + vsprintf(str &char, format &char, ap va_list) int + See `man vsprintf`. + vsnprintf(str &char, size size_t, format &char, ap va_list) int + See `man vsnprintf`. + bare_backtrace() string + Return a backtrace that can be printed. If backtraces are not + supported, return a message stating that backtraces do not work. + [export: 'exit'] + __exit(code int) + Exit with code code. code is allowed to be ignored. - The module decleration should be `builtin`. The default linux + The module decleration should be `builtin`. The default Linux implementation can be found in `vlib/builtin/linux_bare`. -os , -target-os diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 6a0c3506f5..d88c229be8 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -22,7 +22,9 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { // module is less likely to change than function, etc... // During edits, the line number will change most frequently, // so it is last - $if !freestanding { + $if freestanding { + bare_panic(s) + } $else { eprintln('================ V panic ================') eprintln(' module: $mod') eprintln(' function: ${fn_name}()') @@ -30,31 +32,26 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { eprintln(' file: $file:$line_no') eprintln(' v hash: $vcommithash()') eprintln('=========================================') - } $else { - eprint('V panic: ') - eprintln(s) - } - $if exit_after_panic_message ? { - C.exit(1) - } $else { - $if no_backtrace ? { + $if exit_after_panic_message ? { C.exit(1) } $else { - $if tinyc { + $if no_backtrace ? { + C.exit(1) + } $else { + $if tinyc { + $if panics_break_into_debugger ? { + break_if_debugger_attached() + } $else { + C.tcc_backtrace(c'Backtrace') + } + C.exit(1) + } + print_backtrace_skipping_top_frames(1) $if panics_break_into_debugger ? { break_if_debugger_attached() - } $else { - C.tcc_backtrace(c'Backtrace') } C.exit(1) } - $if !freestanding { - print_backtrace_skipping_top_frames(1) - } - $if panics_break_into_debugger ? { - break_if_debugger_attached() - } - C.exit(1) } } } @@ -66,30 +63,32 @@ pub fn panic_optional_not_set(s string) { // panic prints a nice error message, then exits the process with exit code of 1. // It also shows a backtrace on most platforms. pub fn panic(s string) { - eprint('V panic: ') - eprintln(s) - eprintln('v hash: $vcommithash()') - $if exit_after_panic_message ? { - C.exit(1) + $if freestanding { + bare_panic(s) } $else { - $if no_backtrace ? { + eprint('V panic: ') + eprintln(s) + eprintln('v hash: $vcommithash()') + $if exit_after_panic_message ? { C.exit(1) } $else { - $if tinyc { + $if no_backtrace ? { + C.exit(1) + } $else { + $if tinyc { + $if panics_break_into_debugger ? { + break_if_debugger_attached() + } $else { + C.tcc_backtrace(c'Backtrace') + } + C.exit(1) + } + print_backtrace_skipping_top_frames(1) $if panics_break_into_debugger ? { break_if_debugger_attached() - } $else { - C.tcc_backtrace(c'Backtrace') } C.exit(1) } - $if !freestanding { - print_backtrace_skipping_top_frames(1) - } - $if panics_break_into_debugger ? { - break_if_debugger_attached() - } - C.exit(1) } } } diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index a5768a40fa..2559002380 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -32,7 +32,9 @@ pub fn print_backtrace() { // 1 frame for print_backtrace itself // ... print the rest of the backtrace frames ... // => top 2 frames should be skipped, since they will not be informative to the developer - $if !freestanding { + $if freestanding { + println(bare_backtrace()) + } $else { print_backtrace_skipping_top_frames(2) } } diff --git a/vlib/builtin/linux_bare/libc_impl.v b/vlib/builtin/linux_bare/libc_impl.v index dfe8de0e52..516f984402 100644 --- a/vlib/builtin/linux_bare/libc_impl.v +++ b/vlib/builtin/linux_bare/libc_impl.v @@ -1,72 +1,76 @@ module builtin [unsafe] -pub fn memcpy(dest &byte, src &byte, n int) &byte { +pub fn memcpy(dest &C.void, src &C.void, n size_t) &C.void { + dest_ := unsafe { &byte(dest) } + src_ := unsafe { &byte(src) } unsafe { - for i in 0 .. n { - dest[i] = src[i] + for i in 0 .. int(n) { + dest_[i] = src_[i] } - return dest } + return dest } [export: 'malloc'] [unsafe] -fn __malloc(n int) &byte { - return unsafe { malloc(n) } +fn __malloc(n size_t) &C.void { + return unsafe { malloc(int(n)) } } [unsafe] -fn strlen(s &byte) int { +fn strlen(_s &C.void) size_t { + s := unsafe { &byte(_s) } mut i := 0 for ; unsafe { s[i] } != 0; i++ {} - return i + return size_t(i) } [unsafe] -fn realloc(old_area &byte, new_size int) &byte { +fn realloc(old_area &C.void, new_size size_t) &C.void { if old_area == 0 { - return unsafe { malloc(new_size) } + return unsafe { malloc(int(new_size)) } } - if new_size == 0 { + if new_size == size_t(0) { unsafe { free(old_area) } return 0 } old_size := unsafe { *(&u64(old_area - sizeof(u64))) } - if new_size <= old_size { + if u64(new_size) <= old_size { return old_area } else { - new_area := unsafe { malloc(new_size) } - unsafe { memmove(new_area, old_area, int(old_size)) } + new_area := unsafe { malloc(int(new_size)) } + unsafe { memmove(new_area, old_area, size_t(old_size)) } unsafe { free(old_area) } return new_area } } [unsafe] -fn memset(_s &byte, _c int, n int) &byte { - c := char(_c) - mut s := unsafe { &char(_s) } +fn memset(s &C.void, c int, n size_t) &C.void { + mut s_ := unsafe { &char(s) } for i in 0 .. int(n) { unsafe { - s[i] = c + s_[i] = char(c) } } return s } [unsafe] -fn memmove(dest &byte, src &byte, n int) &byte { - mut temp_buf := unsafe { malloc(n) } +fn memmove(dest &C.void, src &C.void, n size_t) &C.void { + dest_ := unsafe { &byte(dest) } + src_ := unsafe { &byte(src) } + mut temp_buf := unsafe { malloc(int(n)) } for i in 0 .. int(n) { unsafe { - temp_buf[i] = src[i] + temp_buf[i] = src_[i] } } for i in 0 .. int(n) { unsafe { - dest[i] = temp_buf[i] + dest_[i] = temp_buf[i] } } unsafe { free(temp_buf) } @@ -75,23 +79,25 @@ fn memmove(dest &byte, src &byte, n int) &byte { [export: 'calloc'] [unsafe] -fn __calloc(nmemb int, size int) &byte { - new_area := unsafe { malloc(nmemb * size) } +fn __calloc(nmemb size_t, size size_t) &C.void { + new_area := unsafe { malloc(int(nmemb) * int(size)) } unsafe { memset(new_area, 0, nmemb * size) } return new_area } fn getchar() int { x := byte(0) - sys_read(C.stdin, &x, 1) + sys_read(0, &x, 1) return int(x) } -fn memcmp(a &byte, b &byte, n int) int { +fn memcmp(a &C.void, b &C.void, n size_t) int { + a_ := unsafe { &byte(a) } + b_ := unsafe { &byte(b) } for i in 0 .. int(n) { - if unsafe { a[i] != b[i] } { + if unsafe { a_[i] != b_[i] } { unsafe { - return a[i] - b[i] + return a_[i] - b_[i] } } } @@ -100,7 +106,7 @@ fn memcmp(a &byte, b &byte, n int) int { [export: 'free'] [unsafe] -fn __free(ptr &byte) { +fn __free(ptr &C.void) { err := mm_free(ptr) if err != .enoerror { eprintln('free error:') @@ -112,7 +118,7 @@ fn vsprintf(str &char, format &char, ap &byte) int { panic('vsprintf(): string interpolation is not supported in `-freestanding`') } -fn vsnprintf(str &char, size int, format &char, ap &byte) int { +fn vsnprintf(str &char, size size_t, format &char, ap &byte) int { panic('vsnprintf(): string interpolation is not supported in `-freestanding`') } @@ -128,3 +134,17 @@ fn bare_print(buf &byte, len u64) { fn bare_eprint(buf &byte, len u64) { sys_write(2, buf, len) } + +fn bare_panic(msg string) { + println('V panic' + msg) + exit(1) +} + +fn bare_backtrace() string { + return 'backtraces are not available with `-freestanding`' +} + +[export: 'exit'] +fn __exit(code int) { + sys_exit(code) +} diff --git a/vlib/v/gen/c/cheaders.v b/vlib/v/gen/c/cheaders.v index 5f0581bc15..3518e44762 100644 --- a/vlib/v/gen/c/cheaders.v +++ b/vlib/v/gen/c/cheaders.v @@ -735,50 +735,17 @@ typedef void (*MapFreeFn)(voidptr); c_common_macros + ' -#ifndef exit -#define exit(rc) sys_exit(rc) -void sys_exit (int); -#endif - -#define stdin 0 -#define stdout 1 -#define stderr 2 - #define _VFREESTANDING typedef long unsigned int size_t; // Memory allocation related headers -// void *malloc(int size); -byte *calloc(int nitems, int size); -byte *realloc(byte *ptr, int size); -byte *memcpy(byte *dest, byte *src, int n); -byte *memset(byte *s, int c, int n); -byte *memmove(byte *dest, byte *src, int n); - -// Backtrace headers -int backtrace(void **buffer, int size); -char **backtrace_symbols(void *const *buffer, int size); -void backtrace_symbols_fd(void *const *buffer, int size, int fd); - -// I/O related headers -typedef void FILE; -FILE *popen(const char *command, const char *type); -int pclose(FILE *stream); -int fgetc(FILE *stream); -char *fgets(char *s, int size, FILE *stream); -int getc(FILE *stream); -int getchar(void); -int ungetc(int c, FILE *stream); - - -// char manipulation headers -int toupper(int c); -int tolower(int c); -// int toupper_l(int c, locale_t locale); -// int tolower_l(int c, locale_t locale); - -int isatty(int fd); +void *malloc(size_t size); +void *calloc(size_t nitems, size_t size); +void *realloc(void *ptr, size_t size); +void *memcpy(void *dest, void *src, size_t n); +void *memset(void *s, int c, size_t n); +void *memmove(void *dest, void *src, size_t n); // varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky typedef __builtin_va_list va_list; @@ -804,6 +771,5 @@ static voidptr memfreedup(voidptr ptr, voidptr src, int sz) { return memdup(src, sz); } -' + - c_wyhash +' + c_wyhash )