From 613a6c473fb61893f29132638cc8051ab0f4d019 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:21 +0300 Subject: [PATCH] pref: fix undefined reference to tcc_backtrace when linking (fixes #23198) --- vlib/v/pref/default.v | 9 +++ vlib/v/pref/pref_test.v | 17 ++++++ .../v/tests/shared_library_system_link_test.v | 56 +++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 vlib/v/tests/shared_library_system_link_test.v diff --git a/vlib/v/pref/default.v b/vlib/v/pref/default.v index c01748c1c..a1b378089 100644 --- a/vlib/v/pref/default.v +++ b/vlib/v/pref/default.v @@ -96,6 +96,14 @@ pub fn (mut p Preferences) defines_map_unique_keys() string { return skeys.join(',') } +fn (mut p Preferences) disable_tcc_shared_backtraces() { + if p.is_shared && p.ccompiler_type == .tinyc && 'no_backtrace' !in p.compile_defines_all { + // TCC shared libraries should not depend on TCC's backtrace runtime symbols. + p.parse_define('no_backtrace') + } +} + +// fill_with_defaults initializes unset preferences and derives build options from them. pub fn (mut p Preferences) fill_with_defaults() { p.setup_os_and_arch_when_not_explicitly_set() p.expand_lookup_paths() @@ -171,6 +179,7 @@ pub fn (mut p Preferences) fill_with_defaults() { } p.find_cc_if_cross_compiling() p.ccompiler_type = cc_from_string(p.ccompiler) + p.disable_tcc_shared_backtraces() p.is_test = p.path.ends_with('_test.v') || p.path.ends_with('_test.vv') || p.path.all_before_last('.v').all_before_last('.').ends_with('_test') p.is_vsh = p.path.ends_with('.vsh') || p.raw_vsh_tmp_prefix != '' diff --git a/vlib/v/pref/pref_test.v b/vlib/v/pref/pref_test.v index 7fc86ae7d..6515374d4 100644 --- a/vlib/v/pref/pref_test.v +++ b/vlib/v/pref/pref_test.v @@ -194,3 +194,20 @@ fn test_output_flag_accepts_directory_path() { } assert os.is_file(expected_output) } + +fn test_tcc_shared_builds_disable_backtraces() { + mut shared_prefs := &pref.Preferences{ + path: 'libfoo.v' + is_shared: true + ccompiler: 'tinyc' + } + shared_prefs.fill_with_defaults() + assert 'no_backtrace' in shared_prefs.compile_defines_all + + mut regular_prefs := &pref.Preferences{ + path: 'main.v' + ccompiler: 'tinyc' + } + regular_prefs.fill_with_defaults() + assert 'no_backtrace' !in regular_prefs.compile_defines_all +} diff --git a/vlib/v/tests/shared_library_system_link_test.v b/vlib/v/tests/shared_library_system_link_test.v new file mode 100644 index 000000000..fb555e158 --- /dev/null +++ b/vlib/v/tests/shared_library_system_link_test.v @@ -0,0 +1,56 @@ +import os +import rand + +const vexe = @VEXE + +fn test_shared_library_links_with_system_cc() { + if os.user_os() != 'linux' { + return + } + workdir := os.join_path(os.vtmp_dir(), 'v_shared_link_${rand.ulid()}') + os.mkdir_all(workdir) or { panic(err) } + defer { + os.rmdir_all(workdir) or {} + } + lib_src := os.join_path(workdir, 'libfoo.v') + lib_out := os.join_path(workdir, 'libfoo') + lib_so := '${lib_out}.so' + host_src := os.join_path(workdir, 'host.c') + host_bin := os.join_path(workdir, 'host') + os.write_file(lib_src, [ + 'module libfoo', + '', + 'pub fn square(x int) int {', + '\treturn x * x', + '}', + ].join('\n')) or { panic(err) } + os.write_file(host_src, [ + '#include ', + '', + 'int libfoo__square(int);', + '', + 'int main(void) {', + '\tprintf("%d\\n", libfoo__square(2));', + '\treturn 0;', + '}', + ].join('\n')) or { panic(err) } + run_cmd('${os.quoted_path(vexe)} -shared -o ${os.quoted_path(lib_out)} ${os.quoted_path(lib_src)}') or { + panic(err) + } + assert os.exists(lib_so) + run_cmd('cc ${os.quoted_path(host_src)} -L${os.quoted_path(workdir)} -lfoo -o ${os.quoted_path(host_bin)}') or { + panic(err) + } + res := run_cmd('LD_LIBRARY_PATH=${os.quoted_path(workdir)} ${os.quoted_path(host_bin)}') or { + panic(err) + } + assert res.output.trim_space() == '4' +} + +fn run_cmd(cmd string) !os.Result { + res := os.execute(cmd) + if res.exit_code != 0 { + return error('command failed:\n${cmd}\n${res.output}') + } + return res +} -- 2.39.5