Skip to content

Commit

Permalink
cgen: use the real C line number instead of #line 1000000 ... in th…
Browse files Browse the repository at this point in the history
…e C footer with `-g` (#21388)
  • Loading branch information
spytheman committed Apr 30, 2024
1 parent 08b6cc7 commit 00dd0bf
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 8 deletions.
5 changes: 4 additions & 1 deletion vlib/v/builder/cbuilder/cbuilder.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
53 changes: 47 additions & 6 deletions vlib/v/gen/c/cmain.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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){')
Expand Down

0 comments on commit 00dd0bf

Please sign in to comment.