builtin: improve musl/Alpine support (define weak backtrace/backtrace_symbols/backtrace_symbols_fd symbols) (#14250)
parent
4da2908d63
commit
0e5c1cee48
|
@ -0,0 +1,20 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
// These are just dummy implementations to appease linking on musl/alpine
|
||||||
|
|
||||||
|
[export: 'backtrace_symbols']
|
||||||
|
[weak]
|
||||||
|
fn vbacktrace_symbols(const_buffer &voidptr, size int) &&char {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
[export: 'backtrace']
|
||||||
|
[weak]
|
||||||
|
fn vbacktrace(buffer &voidptr, size int) int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
[export: 'backtrace_symbols_fd']
|
||||||
|
[weak]
|
||||||
|
fn vbacktrace_symbols_fd(const_buffer &voidptr, size int, fd int) {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
// <execinfo.h>
|
||||||
|
fn C.backtrace(a &voidptr, size int) int
|
||||||
|
fn C.backtrace_symbols(a &voidptr, size int) &&char
|
||||||
|
fn C.backtrace_symbols_fd(a &voidptr, size int, fd int)
|
|
@ -45,10 +45,13 @@ $if dynamic_boehm ? {
|
||||||
#flag -DBUS_PAGE_FAULT=T_PAGEFLT
|
#flag -DBUS_PAGE_FAULT=T_PAGEFLT
|
||||||
#flag -DGC_PTHREADS=1
|
#flag -DGC_PTHREADS=1
|
||||||
$if !tinyc {
|
$if !tinyc {
|
||||||
|
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||||
} $else {
|
}
|
||||||
|
$if tinyc {
|
||||||
#flag -I/usr/local/include
|
#flag -I/usr/local/include
|
||||||
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
|
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
|
||||||
|
#flag -lgc
|
||||||
}
|
}
|
||||||
#flag -lpthread
|
#flag -lpthread
|
||||||
} $else $if openbsd {
|
} $else $if openbsd {
|
||||||
|
|
|
@ -39,13 +39,6 @@ fn C.isdigit(c int) bool
|
||||||
// stdio.h
|
// stdio.h
|
||||||
fn C.popen(c &char, t &char) voidptr
|
fn C.popen(c &char, t &char) voidptr
|
||||||
|
|
||||||
// <execinfo.h>
|
|
||||||
fn C.backtrace(a &voidptr, size int) int
|
|
||||||
|
|
||||||
fn C.backtrace_symbols(a &voidptr, size int) &&char
|
|
||||||
|
|
||||||
fn C.backtrace_symbols_fd(a &voidptr, size int, fd int)
|
|
||||||
|
|
||||||
// <libproc.h>
|
// <libproc.h>
|
||||||
pub fn proc_pidpath(int, voidptr, int) int
|
pub fn proc_pidpath(int, voidptr, int) int
|
||||||
|
|
||||||
|
|
|
@ -564,9 +564,12 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
|
||||||
'test' {
|
'test' {
|
||||||
return if c.pref.is_test { .eval } else { .skip }
|
return if c.pref.is_test { .eval } else { .skip }
|
||||||
}
|
}
|
||||||
|
'musl' {
|
||||||
|
return .unknown
|
||||||
|
}
|
||||||
'glibc' {
|
'glibc' {
|
||||||
return .unknown
|
return .unknown
|
||||||
} // TODO
|
}
|
||||||
'threads' {
|
'threads' {
|
||||||
return if c.table.gostmts > 0 { .eval } else { .skip }
|
return if c.table.gostmts > 0 { .eval } else { .skip }
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,6 +366,10 @@ const c_common_macros = '
|
||||||
#undef VWEAK
|
#undef VWEAK
|
||||||
#define VWEAK
|
#define VWEAK
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
#undef VWEAK
|
||||||
|
#define VWEAK
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(VNORETURN)
|
#if !defined(VNORETURN)
|
||||||
|
@ -460,11 +464,6 @@ typedef int (*qsort_callback_func)(const void*, const void*);
|
||||||
#if defined __has_include
|
#if defined __has_include
|
||||||
#if __has_include (<execinfo.h>)
|
#if __has_include (<execinfo.h>)
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#else
|
|
||||||
// Most probably musl OR __ANDROID__ ...
|
|
||||||
int backtrace (void **__array, int __size) { return 0; }
|
|
||||||
char **backtrace_symbols (void *const *__array, int __size){ return 0; }
|
|
||||||
void backtrace_symbols_fd (void *const *__array, int __size, int __fd){}
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -416,8 +416,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||||
}
|
}
|
||||||
for attr in node.attrs {
|
for attr in node.attrs {
|
||||||
if attr.name == 'export' {
|
if attr.name == 'export' {
|
||||||
|
weak := if node.attrs.any(it.name == 'weak') { 'VWEAK ' } else { '' }
|
||||||
g.writeln('// export alias: $attr.arg -> $name')
|
g.writeln('// export alias: $attr.arg -> $name')
|
||||||
export_alias := '$type_name $fn_attrs${attr.arg}($arg_str)'
|
export_alias := '$weak$type_name $fn_attrs${attr.arg}($arg_str)'
|
||||||
g.definitions.writeln('VV_EXPORTED_SYMBOL $export_alias; // exported fn $node.name')
|
g.definitions.writeln('VV_EXPORTED_SYMBOL $export_alias; // exported fn $node.name')
|
||||||
g.writeln('$export_alias {')
|
g.writeln('$export_alias {')
|
||||||
g.write('\treturn ${name}(')
|
g.write('\treturn ${name}(')
|
||||||
|
@ -2143,6 +2144,10 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
||||||
g.write('__NOINLINE ')
|
g.write('__NOINLINE ')
|
||||||
}
|
}
|
||||||
'weak' {
|
'weak' {
|
||||||
|
if attrs.any(it.name == 'export') {
|
||||||
|
// only the exported wrapper should be weak; otherwise x86_64-w64-mingw32-gcc complains
|
||||||
|
continue
|
||||||
|
}
|
||||||
// a `[weak]` tag tells the C compiler, that the next declaration will be weak, i.e. when linking,
|
// a `[weak]` tag tells the C compiler, that the next declaration will be weak, i.e. when linking,
|
||||||
// if there is another declaration of a symbol with the same name (a 'strong' one), it should be
|
// if there is another declaration of a symbol with the same name (a 'strong' one), it should be
|
||||||
// used instead, *without linker errors about duplicate symbols*.
|
// used instead, *without linker errors about duplicate symbols*.
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
VV_LOCAL_SYMBOL int main__my_other_fn(void);
|
||||||
|
VV_EXPORTED_SYMBOL VWEAK int wxyz(void); // exported fn main.my_other_fn
|
||||||
|
VWEAK int wxyz(void) {
|
||||||
|
VV_LOCAL_SYMBOL int main__my_other_fn(void) {
|
||||||
|
|
||||||
|
VV_LOCAL_SYMBOL int main__my_fn(void);
|
||||||
|
VV_EXPORTED_SYMBOL int abcd(void); // exported fn main.my_fn
|
||||||
|
int abcd(void) {
|
||||||
|
VV_LOCAL_SYMBOL int main__my_fn(void) {
|
||||||
|
|
||||||
|
println(int_str(main__my_fn()));
|
||||||
|
println(int_str(main__my_other_fn()));
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
42
|
||||||
|
11
|
|
@ -0,0 +1,20 @@
|
||||||
|
// This file tests the ability to export functions to C with a fully custom name.
|
||||||
|
|
||||||
|
// It also tests, that the exported functions will be exported as weak symbols,
|
||||||
|
// if the user tagged them as such.
|
||||||
|
|
||||||
|
[export: abcd]
|
||||||
|
fn my_fn() int {
|
||||||
|
return 42
|
||||||
|
}
|
||||||
|
|
||||||
|
[export: wxyz]
|
||||||
|
[weak]
|
||||||
|
fn my_other_fn() int {
|
||||||
|
return 11
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println(my_fn())
|
||||||
|
println(my_other_fn())
|
||||||
|
}
|
|
@ -99,6 +99,8 @@ pub mut:
|
||||||
// verbosity VerboseLevel
|
// verbosity VerboseLevel
|
||||||
is_verbose bool
|
is_verbose bool
|
||||||
// nofmt bool // disable vfmt
|
// nofmt bool // disable vfmt
|
||||||
|
is_glibc bool // if GLIBC will be linked
|
||||||
|
is_musl bool // if MUSL will be linked
|
||||||
is_test bool // `v test string_test.v`
|
is_test bool // `v test string_test.v`
|
||||||
is_script bool // single file mode (`v program.v`), main function can be skipped
|
is_script bool // single file mode (`v program.v`), main function can be skipped
|
||||||
is_vsh bool // v script (`file.vsh`) file, the `os` module should be made global
|
is_vsh bool // v script (`file.vsh`) file, the `os` module should be made global
|
||||||
|
@ -107,17 +109,25 @@ pub mut:
|
||||||
is_shared bool // an ordinary shared library, -shared, no matter if it is live or not
|
is_shared bool // an ordinary shared library, -shared, no matter if it is live or not
|
||||||
is_o bool // building an .o file
|
is_o bool // building an .o file
|
||||||
is_prof bool // benchmark every function
|
is_prof bool // benchmark every function
|
||||||
|
is_prod bool // use "-O2"
|
||||||
|
is_repl bool
|
||||||
|
is_run bool
|
||||||
|
is_debug bool // turned on by -g or -cg, it tells v to pass -g to the C backend compiler.
|
||||||
|
is_vlines bool // turned on by -g (it slows down .tmp.c generation slightly).
|
||||||
|
is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run
|
||||||
|
is_fmt bool
|
||||||
|
is_vet bool
|
||||||
|
is_vweb bool // skip _ var warning in templates
|
||||||
|
is_ios_simulator bool
|
||||||
|
is_apk bool // build as Android .apk format
|
||||||
|
is_help bool // -h, -help or --help was passed
|
||||||
|
is_cstrict bool // turn on more C warnings; slightly slower
|
||||||
test_runner string // can be 'simple' (fastest, but much less detailed), 'tap', 'normal'
|
test_runner string // can be 'simple' (fastest, but much less detailed), 'tap', 'normal'
|
||||||
profile_file string // the profile results will be stored inside profile_file
|
profile_file string // the profile results will be stored inside profile_file
|
||||||
profile_no_inline bool // when true, [inline] functions would not be profiled
|
profile_no_inline bool // when true, [inline] functions would not be profiled
|
||||||
profile_fns []string // when set, profiling will be off by default, but inside these functions (and what they call) it will be on.
|
profile_fns []string // when set, profiling will be off by default, but inside these functions (and what they call) it will be on.
|
||||||
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
|
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
|
||||||
is_prod bool // use "-O2"
|
|
||||||
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
|
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
|
||||||
is_repl bool
|
|
||||||
is_run bool
|
|
||||||
is_debug bool // turned on by -g or -cg, it tells v to pass -g to the C backend compiler.
|
|
||||||
is_vlines bool // turned on by -g (it slows down .tmp.c generation slightly).
|
|
||||||
// Note: passing -cg instead of -g will set is_vlines to false and is_debug to true, thus making v generate cleaner C files,
|
// Note: passing -cg instead of -g will set is_vlines to false and is_debug to true, thus making v generate cleaner C files,
|
||||||
// which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks).
|
// which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks).
|
||||||
sanitize bool // use Clang's new "-fsanitize" option
|
sanitize bool // use Clang's new "-fsanitize" option
|
||||||
|
@ -131,7 +141,6 @@ pub mut:
|
||||||
dump_c_flags string // `-dump-c-flags file.txt` - let V store all C flags, passed to the backend C compiler in `file.txt`, one C flag/value per line.
|
dump_c_flags string // `-dump-c-flags file.txt` - let V store all C flags, passed to the backend C compiler in `file.txt`, one C flag/value per line.
|
||||||
use_cache bool // when set, use cached modules to speed up subsequent compilations, at the cost of slower initial ones (while the modules are cached)
|
use_cache bool // when set, use cached modules to speed up subsequent compilations, at the cost of slower initial ones (while the modules are cached)
|
||||||
retry_compilation bool = true // retry the compilation with another C compiler, if tcc fails.
|
retry_compilation bool = true // retry the compilation with another C compiler, if tcc fails.
|
||||||
is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run
|
|
||||||
// TODO Convert this into a []string
|
// TODO Convert this into a []string
|
||||||
cflags string // Additional options which will be passed to the C compiler.
|
cflags string // Additional options which will be passed to the C compiler.
|
||||||
// For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size.
|
// For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size.
|
||||||
|
@ -148,8 +157,6 @@ pub mut:
|
||||||
// generating_vh bool
|
// generating_vh bool
|
||||||
no_builtin bool // Skip adding the `builtin` module implicitly. The generated C code may not compile.
|
no_builtin bool // Skip adding the `builtin` module implicitly. The generated C code may not compile.
|
||||||
enable_globals bool // allow __global for low level code
|
enable_globals bool // allow __global for low level code
|
||||||
is_fmt bool
|
|
||||||
is_vet bool
|
|
||||||
is_bare bool // set by -freestanding
|
is_bare bool // set by -freestanding
|
||||||
bare_builtin_dir string // Set by -bare-builtin-dir xyz/ . The xyz/ module should contain implementations of malloc, memset, etc, that are used by the rest of V's `builtin` module. That option is only useful with -freestanding (i.e. when is_bare is true).
|
bare_builtin_dir string // Set by -bare-builtin-dir xyz/ . The xyz/ module should contain implementations of malloc, memset, etc, that are used by the rest of V's `builtin` module. That option is only useful with -freestanding (i.e. when is_bare is true).
|
||||||
no_preludes bool // Prevents V from generating preludes in resulting .c files
|
no_preludes bool // Prevents V from generating preludes in resulting .c files
|
||||||
|
@ -162,11 +169,14 @@ pub mut:
|
||||||
out_name_c string // full os.real_path to the generated .tmp.c file; set by builder.
|
out_name_c string // full os.real_path to the generated .tmp.c file; set by builder.
|
||||||
out_name string
|
out_name string
|
||||||
path string // Path to file/folder to compile
|
path string // Path to file/folder to compile
|
||||||
// -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }`
|
//
|
||||||
run_only []string // VTEST_ONLY_FN and -run-only accept comma separated glob patterns.
|
run_only []string // VTEST_ONLY_FN and -run-only accept comma separated glob patterns.
|
||||||
// Only test_ functions that match these patterns will be run. -run-only is valid only for _test.v files.
|
// Only test_ functions that match these patterns will be run. -run-only is valid only for _test.v files.
|
||||||
|
//
|
||||||
|
// -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }`
|
||||||
compile_defines []string // just ['vfmt']
|
compile_defines []string // just ['vfmt']
|
||||||
compile_defines_all []string // contains both: ['vfmt','another']
|
compile_defines_all []string // contains both: ['vfmt','another']
|
||||||
|
//
|
||||||
run_args []string // `v run x.v 1 2 3` => `1 2 3`
|
run_args []string // `v run x.v 1 2 3` => `1 2 3`
|
||||||
printfn_list []string // a list of generated function names, whose source should be shown, for debugging
|
printfn_list []string // a list of generated function names, whose source should be shown, for debugging
|
||||||
print_v_files bool // when true, just print the list of all parsed .v files then stop.
|
print_v_files bool // when true, just print the list of all parsed .v files then stop.
|
||||||
|
@ -178,22 +188,19 @@ pub mut:
|
||||||
reuse_tmpc bool // do not use random names for .tmp.c and .tmp.c.rsp files, and do not remove them
|
reuse_tmpc bool // do not use random names for .tmp.c and .tmp.c.rsp files, and do not remove them
|
||||||
no_rsp bool // when true, pass C backend options directly on the CLI (do not use `.rsp` files for them, some older C compilers do not support them)
|
no_rsp bool // when true, pass C backend options directly on the CLI (do not use `.rsp` files for them, some older C compilers do not support them)
|
||||||
no_std bool // when true, do not pass -std=gnu99(linux)/-std=c99 to the C backend
|
no_std bool // when true, do not pass -std=gnu99(linux)/-std=c99 to the C backend
|
||||||
use_color ColorOutput // whether the warnings/errors should use ANSI color escapes.
|
//
|
||||||
no_parallel bool
|
no_parallel bool // do not use threads when compiling; slower, but more portable and sometimes less buggy
|
||||||
is_vweb bool // skip _ var warning in templates
|
|
||||||
only_check_syntax bool // when true, just parse the files, then stop, before running checker
|
only_check_syntax bool // when true, just parse the files, then stop, before running checker
|
||||||
check_only bool // same as only_check_syntax, but also runs the checker
|
check_only bool // same as only_check_syntax, but also runs the checker
|
||||||
experimental bool // enable experimental features
|
experimental bool // enable experimental features
|
||||||
skip_unused bool // skip generating C code for functions, that are not used
|
skip_unused bool // skip generating C code for functions, that are not used
|
||||||
show_timings bool // show how much time each compiler stage took
|
show_timings bool // show how much time each compiler stage took
|
||||||
is_ios_simulator bool
|
//
|
||||||
is_apk bool // build as Android .apk format
|
use_color ColorOutput // whether the warnings/errors should use ANSI color escapes.
|
||||||
cleanup_files []string // list of temporary *.tmp.c and *.tmp.c.rsp files. Cleaned up on successfull builds.
|
cleanup_files []string // list of temporary *.tmp.c and *.tmp.c.rsp files. Cleaned up on successfull builds.
|
||||||
build_options []string // list of options, that should be passed down to `build-module`, if needed for -usecache
|
build_options []string // list of options, that should be passed down to `build-module`, if needed for -usecache
|
||||||
cache_manager vcache.CacheManager
|
cache_manager vcache.CacheManager
|
||||||
is_help bool // -h, -help or --help was passed
|
|
||||||
gc_mode GarbageCollectionMode = .no_gc // .no_gc, .boehm, .boehm_leak, ...
|
gc_mode GarbageCollectionMode = .no_gc // .no_gc, .boehm, .boehm_leak, ...
|
||||||
is_cstrict bool // turn on more C warnings; slightly slower
|
|
||||||
assert_failure_mode AssertFailureMode // whether to call abort() or print_backtrace() after an assertion failure
|
assert_failure_mode AssertFailureMode // whether to call abort() or print_backtrace() after an assertion failure
|
||||||
message_limit int = 100 // the maximum amount of warnings/errors/notices that will be accumulated
|
message_limit int = 100 // the maximum amount of warnings/errors/notices that will be accumulated
|
||||||
nofloat bool // for low level code, like kernels: replaces f32 with u32 and f64 with u64
|
nofloat bool // for low level code, like kernels: replaces f32 with u32 and f64 with u64
|
||||||
|
@ -206,8 +213,25 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
|
||||||
return parse_args_and_show_errors(known_external_commands, args, false)
|
return parse_args_and_show_errors(known_external_commands, args, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[if linux]
|
||||||
|
fn detect_musl(mut res Preferences) {
|
||||||
|
res.is_glibc = true
|
||||||
|
res.is_musl = false
|
||||||
|
if os.exists('/etc/alpine-release') {
|
||||||
|
res.is_musl = true
|
||||||
|
res.is_glibc = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
my_libs := os.walk_ext('/proc/self/map_files/', '').map(os.real_path(it))
|
||||||
|
if my_libs.any(it.contains('musl')) {
|
||||||
|
res.is_musl = true
|
||||||
|
res.is_glibc = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_args_and_show_errors(known_external_commands []string, args []string, show_output bool) (&Preferences, string) {
|
pub fn parse_args_and_show_errors(known_external_commands []string, args []string, show_output bool) (&Preferences, string) {
|
||||||
mut res := &Preferences{}
|
mut res := &Preferences{}
|
||||||
|
detect_musl(mut res)
|
||||||
$if x64 {
|
$if x64 {
|
||||||
res.m64 = true // follow V model by default
|
res.m64 = true // follow V model by default
|
||||||
}
|
}
|
||||||
|
@ -412,6 +436,16 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
||||||
'-no-retry-compilation' {
|
'-no-retry-compilation' {
|
||||||
res.retry_compilation = false
|
res.retry_compilation = false
|
||||||
}
|
}
|
||||||
|
'-musl' {
|
||||||
|
res.is_musl = true
|
||||||
|
res.is_glibc = false
|
||||||
|
res.build_options << arg
|
||||||
|
}
|
||||||
|
'-glibc' {
|
||||||
|
res.is_musl = false
|
||||||
|
res.is_glibc = true
|
||||||
|
res.build_options << arg
|
||||||
|
}
|
||||||
'-no-builtin' {
|
'-no-builtin' {
|
||||||
res.no_builtin = true
|
res.no_builtin = true
|
||||||
res.build_options << arg
|
res.build_options << arg
|
||||||
|
@ -579,6 +613,10 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
||||||
'-cc' {
|
'-cc' {
|
||||||
res.ccompiler = cmdline.option(current_args, '-cc', 'cc')
|
res.ccompiler = cmdline.option(current_args, '-cc', 'cc')
|
||||||
res.build_options << '$arg "$res.ccompiler"'
|
res.build_options << '$arg "$res.ccompiler"'
|
||||||
|
if res.ccompiler == 'musl-gcc' {
|
||||||
|
res.is_musl = true
|
||||||
|
res.is_glibc = false
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
'-checker-match-exhaustive-cutoff-limit' {
|
'-checker-match-exhaustive-cutoff-limit' {
|
||||||
|
|
Loading…
Reference in New Issue