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 -DGC_PTHREADS=1
|
||||
$if !tinyc {
|
||||
#flag -I@VEXEROOT/thirdparty/libgc/include
|
||||
#flag @VEXEROOT/thirdparty/libgc/gc.o
|
||||
} $else {
|
||||
}
|
||||
$if tinyc {
|
||||
#flag -I/usr/local/include
|
||||
#flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
|
||||
#flag -lgc
|
||||
}
|
||||
#flag -lpthread
|
||||
} $else $if openbsd {
|
||||
|
|
|
@ -39,13 +39,6 @@ fn C.isdigit(c int) bool
|
|||
// stdio.h
|
||||
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>
|
||||
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' {
|
||||
return if c.pref.is_test { .eval } else { .skip }
|
||||
}
|
||||
'musl' {
|
||||
return .unknown
|
||||
}
|
||||
'glibc' {
|
||||
return .unknown
|
||||
} // TODO
|
||||
}
|
||||
'threads' {
|
||||
return if c.table.gostmts > 0 { .eval } else { .skip }
|
||||
}
|
||||
|
|
|
@ -366,6 +366,10 @@ const c_common_macros = '
|
|||
#undef VWEAK
|
||||
#define VWEAK
|
||||
#endif
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#undef VWEAK
|
||||
#define VWEAK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(VNORETURN)
|
||||
|
@ -460,11 +464,6 @@ typedef int (*qsort_callback_func)(const void*, const void*);
|
|||
#if defined __has_include
|
||||
#if __has_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
|
||||
|
|
|
@ -416,8 +416,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
|||
}
|
||||
for attr in node.attrs {
|
||||
if attr.name == 'export' {
|
||||
weak := if node.attrs.any(it.name == 'weak') { 'VWEAK ' } else { '' }
|
||||
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.writeln('$export_alias {')
|
||||
g.write('\treturn ${name}(')
|
||||
|
@ -2143,6 +2144,10 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
|
|||
g.write('__NOINLINE ')
|
||||
}
|
||||
'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,
|
||||
// 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*.
|
||||
|
|
|
@ -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
|
||||
is_verbose bool
|
||||
// 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_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
|
||||
|
@ -107,17 +109,25 @@ pub mut:
|
|||
is_shared bool // an ordinary shared library, -shared, no matter if it is live or not
|
||||
is_o bool // building an .o file
|
||||
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'
|
||||
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_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
|
||||
is_prod bool // use "-O2"
|
||||
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,
|
||||
// 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
|
||||
|
@ -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.
|
||||
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.
|
||||
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
|
||||
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.
|
||||
|
@ -148,8 +157,6 @@ pub mut:
|
|||
// generating_vh bool
|
||||
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
|
||||
is_fmt bool
|
||||
is_vet bool
|
||||
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).
|
||||
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 string
|
||||
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.
|
||||
// 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_all []string // contains both: ['vfmt','another']
|
||||
//
|
||||
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
|
||||
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
|
||||
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
|
||||
use_color ColorOutput // whether the warnings/errors should use ANSI color escapes.
|
||||
no_parallel bool
|
||||
is_vweb bool // skip _ var warning in templates
|
||||
//
|
||||
no_parallel bool // do not use threads when compiling; slower, but more portable and sometimes less buggy
|
||||
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
|
||||
experimental bool // enable experimental features
|
||||
skip_unused bool // skip generating C code for functions, that are not used
|
||||
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.
|
||||
build_options []string // list of options, that should be passed down to `build-module`, if needed for -usecache
|
||||
cache_manager vcache.CacheManager
|
||||
is_help bool // -h, -help or --help was passed
|
||||
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
|
||||
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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
[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) {
|
||||
mut res := &Preferences{}
|
||||
detect_musl(mut res)
|
||||
$if x64 {
|
||||
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' {
|
||||
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' {
|
||||
res.no_builtin = true
|
||||
res.build_options << arg
|
||||
|
@ -579,6 +613,10 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
|||
'-cc' {
|
||||
res.ccompiler = cmdline.option(current_args, '-cc', 'cc')
|
||||
res.build_options << '$arg "$res.ccompiler"'
|
||||
if res.ccompiler == 'musl-gcc' {
|
||||
res.is_musl = true
|
||||
res.is_glibc = false
|
||||
}
|
||||
i++
|
||||
}
|
||||
'-checker-match-exhaustive-cutoff-limit' {
|
||||
|
|
Loading…
Reference in New Issue