From 00dd0bf9383c601b3b96a57191f6b76335f44538 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 30 Apr 2024 17:03:53 +0300 Subject: [PATCH] cgen: use the real C line number instead of `#line 1000000 ...` in the C footer with `-g` (#21388) --- vlib/v/builder/cbuilder/cbuilder.v | 5 ++- vlib/v/gen/c/cgen.v | 2 +- vlib/v/gen/c/cmain.v | 53 ++++++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/vlib/v/builder/cbuilder/cbuilder.v b/vlib/v/builder/cbuilder/cbuilder.v index 585dbff853..cc5f2b1cca 100644 --- a/vlib/v/builder/cbuilder/cbuilder.v +++ b/vlib/v/builder/cbuilder/cbuilder.v @@ -56,7 +56,10 @@ pub fn build_c(mut b builder.Builder, v_files []string, out_file string) { b.out_name_c = out_file b.pref.out_name_c = os.real_path(out_file) b.info('build_c(${out_file})') - output2 := gen_c(mut b, v_files) + mut output2 := gen_c(mut b, v_files) + if b.pref.is_vlines { + output2 = c.fix_reset_dbg_line(output2, out_file) + } os.write_file(out_file, output2) or { panic(err) } if b.pref.is_stats { b.stats_lines = output2.count('\n') + 1 diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index d27dd8e0a8..63886b5add 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -523,7 +523,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) (str g.finish() - mut b := strings.new_builder(640000) + mut b := strings.new_builder(g.out.len + 200_000) b.write_string(g.hashes()) if g.use_segfault_handler || g.pref.is_prof { b.writeln('\n#define V_USE_SIGNAL_H') diff --git a/vlib/v/gen/c/cmain.v b/vlib/v/gen/c/cmain.v index 321315e5eb..86689af900 100644 --- a/vlib/v/gen/c/cmain.v +++ b/vlib/v/gen/c/cmain.v @@ -2,6 +2,9 @@ module c import v.util import v.ast +import strings + +pub const reset_dbg_line = '#line 999999999' pub fn (mut g Gen) gen_c_main() { if !g.has_main { @@ -38,18 +41,56 @@ fn (mut g Gen) gen_vlines_reset() { // At this point, the v files are transpiled. // The rest is auto generated code, which will not have // different .v source file/line numbers. - // - // TODO: calculate the proper line here, based on - // the actual C lines in all the buffers - lines_so_far := 1000000 g.vlines_path = util.vlines_escape_path(g.pref.out_name_c, g.pref.ccompiler) g.writeln('') - g.writeln('\n// Reset the file/line numbers') - g.writeln('\n#line ${lines_so_far} "${g.vlines_path}"') + g.writeln('// Reset the C file/line numbers') + g.writeln('${c.reset_dbg_line} "${g.vlines_path}"') g.writeln('') } } +pub fn fix_reset_dbg_line(src string, out_file string) string { + util.timing_start(@FN) + defer { + util.timing_measure(@FN) + } + // Note: using src.index() + a line counting loop + src.replace() here is slower, + // since it has to iterate over pretty much the entire src string several times. + // The loop below, does it just once, combining counting the lines, and finding the reset line: + mut dbg_reset_line_idx := 0 + mut lines := 1 + for idx, ob in src { + if ob == `\n` { + lines++ + if unsafe { vmemcmp(src.str + idx + 1, c.reset_dbg_line.str, c.reset_dbg_line.len) } == 0 { + dbg_reset_line_idx = idx + 1 + break + } + } + } + // find the position of the "..\..\..\src.tmp.c": + mut first_quote_idx := 0 + for idx := dbg_reset_line_idx; idx < src.len; idx++ { + if unsafe { src.str[idx] } == `"` { + first_quote_idx = idx + break + } + } + // replace the reset line with the fixed line counter, keeping everything + // before and after it unchanged: + mut sb := strings.new_builder(src.len) + unsafe { + sb.write_ptr(src.str, dbg_reset_line_idx) + sb.write_string('#line ') + sb.write_decimal(lines) + sb.write_ptr(src.str + first_quote_idx - 1, src.len - first_quote_idx) + } + $if trace_reset_dbg_line ? { + eprintln('> reset_dbg_line: ${out_file}:${lines} | first_quote_idx: ${first_quote_idx} | src.len: ${src.len} | sb.len: ${sb.len} | sb.cap: ${sb.cap}') + } + return sb.str() +} + fn (mut g Gen) gen_c_main_function_only_header() { if g.pref.cmain != '' { g.writeln('int ${g.pref.cmain}(int ___argc, char** ___argv){')