cgen: add support for -g again
parent
6a8a589adb
commit
ca7a64a451
|
@ -36,6 +36,7 @@ pub fn (mut b Builder) gen_c(v_files []string) string {
|
|||
|
||||
pub fn (mut b Builder) build_c(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 := b.gen_c(v_files)
|
||||
mut f := os.create(out_file) or {
|
||||
|
|
|
@ -59,6 +59,8 @@ mut:
|
|||
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
||||
is_sql bool // Inside `sql db{}` statement, generating sql instead of C (e.g. `and` instead of `&&` etc)
|
||||
is_shared bool // for initialization of hidden mutex in `[rw]shared` literals
|
||||
is_vlines_enabled bool // is it safe to generate #line directives when -g is passed
|
||||
vlines_path string // set to the proper path for generating #line directives
|
||||
optionals []string // to avoid duplicates TODO perf, use map
|
||||
shareds []int // types with hidden mutex for which decl has been emitted
|
||||
inside_ternary int // ?: comma separated statements on a single line
|
||||
|
@ -147,6 +149,9 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
mut autofree_used := false
|
||||
for file in files {
|
||||
g.file = file
|
||||
if g.pref.is_vlines {
|
||||
g.vlines_path = util.vlines_escape_path(file.path, g.pref.ccompiler)
|
||||
}
|
||||
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
|
||||
// building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
|
||||
is_test := g.file.path.ends_with('.vv') || g.file.path.ends_with('_test.v')
|
||||
|
@ -174,6 +179,8 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
}
|
||||
g.write_variadic_types()
|
||||
// g.write_str_definitions()
|
||||
// v files are finished, what remains is pure C code
|
||||
g.gen_vlines_reset()
|
||||
if g.pref.build_mode != .build_module {
|
||||
// no init in builtin.o
|
||||
g.write_init_function()
|
||||
|
@ -235,7 +242,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
return b.str()
|
||||
}
|
||||
|
||||
pub fn (g Gen) hashes() string {
|
||||
pub fn (g &Gen) hashes() string {
|
||||
mut res := c_commit_hash_default.replace('@@@', util.vhash())
|
||||
res += c_current_commit_hash_default.replace('@@@', util.githash(g.pref.building_v))
|
||||
return res
|
||||
|
@ -563,9 +570,6 @@ pub fn (mut g Gen) write_variadic_types() {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (g Gen) save() {
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) write(s string) {
|
||||
$if trace_gen ? {
|
||||
eprintln('gen file: ${g.file.path:-30} | last_fn_c_name: ${g.last_fn_c_name:-45} | write: $s')
|
||||
|
@ -648,6 +652,15 @@ fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
|||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
fn (mut g Gen) write_v_source_line_info(pos token.Position) {
|
||||
if g.inside_ternary == 0 && g.pref.is_vlines && g.is_vlines_enabled {
|
||||
nline := pos.line_nr + 1
|
||||
lineinfo := '\n#line $nline "$g.vlines_path"'
|
||||
g.writeln(lineinfo)
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
g.stmt_path_pos << g.out.len
|
||||
defer {
|
||||
|
@ -664,9 +677,11 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
// g.writeln('//// stmt start')
|
||||
match node {
|
||||
ast.AssertStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_assert_stmt(node)
|
||||
}
|
||||
ast.AssignStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.gen_assign_stmt(node)
|
||||
}
|
||||
ast.Block {
|
||||
|
@ -679,11 +694,13 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.writeln('}')
|
||||
}
|
||||
ast.BranchStmt {
|
||||
g.write_v_source_line_info(node.tok.position())
|
||||
// continue or break
|
||||
g.write(node.tok.kind.str())
|
||||
g.writeln(';')
|
||||
}
|
||||
ast.ConstDecl {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
// if g.pref.build_mode != .build_module {
|
||||
g.const_decl(node)
|
||||
// }
|
||||
|
@ -692,6 +709,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.comp_for(node)
|
||||
}
|
||||
ast.CompIf {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.comp_if(node)
|
||||
}
|
||||
ast.DeferStmt {
|
||||
|
@ -723,6 +741,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.enum_typedefs.writeln('} $enum_name;\n')
|
||||
}
|
||||
ast.ExprStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.expr(node.expr)
|
||||
if g.inside_ternary == 0 && !node.is_expr && !(node.expr is ast.IfExpr) {
|
||||
g.writeln(';')
|
||||
|
@ -779,6 +798,8 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
}
|
||||
}
|
||||
ast.ForCStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.is_vlines_enabled = false
|
||||
g.write('for (')
|
||||
if !node.has_init {
|
||||
g.write('; ')
|
||||
|
@ -799,13 +820,17 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.stmt(node.inc)
|
||||
}
|
||||
g.writeln(') {')
|
||||
g.is_vlines_enabled = true
|
||||
g.stmts(node.stmts)
|
||||
g.writeln('}')
|
||||
}
|
||||
ast.ForInStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.for_in(node)
|
||||
}
|
||||
ast.ForStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
g.is_vlines_enabled = false
|
||||
g.write('while (')
|
||||
if node.is_inf {
|
||||
g.write('1')
|
||||
|
@ -813,6 +838,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||
g.expr(node.cond)
|
||||
}
|
||||
g.writeln(') {')
|
||||
g.is_vlines_enabled = true
|
||||
g.stmts(node.stmts)
|
||||
g.writeln('}')
|
||||
}
|
||||
|
@ -2784,7 +2810,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
|||
}
|
||||
|
||||
[inline]
|
||||
fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
||||
fn (g &Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
||||
match expr {
|
||||
ast.CallExpr { return g.table.get_type_symbol(expr.return_type).kind == .multi_return }
|
||||
else { return false }
|
||||
|
@ -2792,6 +2818,7 @@ fn (g Gen) expr_is_multi_return_call(expr ast.Expr) bool {
|
|||
}
|
||||
|
||||
fn (mut g Gen) return_statement(node ast.Return) {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
if node.exprs.len > 0 {
|
||||
// skip `retun $vweb.html()`
|
||||
if node.exprs[0] is ast.ComptimeCall {
|
||||
|
@ -3525,7 +3552,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
|
|||
}
|
||||
|
||||
// sort structs by dependant fields
|
||||
fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
|
||||
fn (g &Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
|
||||
mut dep_graph := depgraph.new_dep_graph()
|
||||
// types name list
|
||||
mut type_names := []string{}
|
||||
|
@ -4168,7 +4195,7 @@ fn (mut g Gen) type_default(typ table.Type) string {
|
|||
*/
|
||||
}
|
||||
|
||||
fn (g Gen) get_all_test_function_names() []string {
|
||||
fn (g &Gen) get_all_test_function_names() []string {
|
||||
mut tfuncs := []string{}
|
||||
mut tsuite_begin := ''
|
||||
mut tsuite_end := ''
|
||||
|
@ -4215,7 +4242,7 @@ fn (g Gen) get_all_test_function_names() []string {
|
|||
return all_tfuncs_c
|
||||
}
|
||||
|
||||
fn (g Gen) is_importing_os() bool {
|
||||
fn (g &Gen) is_importing_os() bool {
|
||||
return 'os' in g.table.imports
|
||||
}
|
||||
|
||||
|
@ -4385,7 +4412,7 @@ fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
|
|||
g.auto_str_funcs.writeln('}')
|
||||
}
|
||||
|
||||
fn (g Gen) type_to_fmt(typ table.Type) string {
|
||||
fn (g &Gen) type_to_fmt(typ table.Type) string {
|
||||
sym := g.table.get_type_symbol(typ)
|
||||
if sym.kind in [.struct_, .array, .array_fixed, .map] {
|
||||
return '%.*s\\000'
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
module gen
|
||||
|
||||
import v.util
|
||||
|
||||
pub fn (mut g Gen) gen_c_main() {
|
||||
if !g.has_main {
|
||||
return
|
||||
|
@ -17,6 +19,23 @@ pub fn (mut g Gen) gen_c_main() {
|
|||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_vlines_reset() {
|
||||
if g.pref.is_vlines {
|
||||
// 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('')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_c_main_header() {
|
||||
if g.pref.os == .windows {
|
||||
if g.is_gui_app() {
|
||||
|
@ -37,13 +56,11 @@ fn (mut g Gen) gen_c_main_header() {
|
|||
g.writeln('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);')
|
||||
}
|
||||
g.writeln('\t_vinit();')
|
||||
|
||||
if g.pref.is_prof {
|
||||
g.writeln('')
|
||||
g.writeln('\tatexit(vprint_profile_stats);')
|
||||
g.writeln('')
|
||||
}
|
||||
|
||||
if g.is_importing_os() {
|
||||
if g.autofree {
|
||||
g.writeln('free(_const_os__args.data); // empty, inited in _vinit()')
|
||||
|
@ -63,7 +80,6 @@ pub fn (mut g Gen) gen_c_main_footer() {
|
|||
if g.autofree {
|
||||
g.writeln('\t_vcleanup();')
|
||||
}
|
||||
|
||||
g.writeln('\treturn 0;')
|
||||
g.writeln('}')
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
|||
}
|
||||
// g.cur_fn = it
|
||||
fn_start_pos := g.out.len
|
||||
g.write_v_source_line_info(it.pos)
|
||||
msvc_attrs := g.write_fn_attrs(it.attrs)
|
||||
// Live
|
||||
is_livefn := it.attrs.contains('live')
|
||||
|
|
|
@ -70,7 +70,7 @@ pub mut:
|
|||
is_debug bool // false by default, turned on by -g or -cg, it tells v to pass -g to the C backend compiler.
|
||||
is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly).
|
||||
show_cc bool // -showcc, print cc command
|
||||
// NB: passing -cg instead of -g will set is_vlines to false and is_g to true, thus making v generate cleaner C files,
|
||||
// NB: 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).
|
||||
use_cache bool // turns on v usage of the module cache to speed up compilation.
|
||||
is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run
|
||||
|
@ -101,6 +101,7 @@ pub mut:
|
|||
output_cross_c bool
|
||||
prealloc bool
|
||||
vroot string
|
||||
out_name_c string // full os.real_path to the generated .tmp.c file; set by builder.
|
||||
out_name string
|
||||
display_name string
|
||||
bundle_id string
|
||||
|
@ -144,8 +145,13 @@ pub fn parse_args(args []string) (&Preferences, string) {
|
|||
'-silent' {
|
||||
res.output_mode = .silent
|
||||
}
|
||||
'-g' {
|
||||
res.is_debug = true
|
||||
res.is_vlines = true
|
||||
}
|
||||
'-cg' {
|
||||
res.is_debug = true
|
||||
res.is_vlines = false
|
||||
}
|
||||
'-repl' {
|
||||
res.is_repl = true
|
||||
|
|
|
@ -141,3 +141,14 @@ pub fn verror(kind, s string) {
|
|||
eprintln('$final_kind: $s')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
pub fn vlines_escape_path(path string, ccompiler string) string {
|
||||
is_cc_tcc := ccompiler.contains('tcc')
|
||||
if is_cc_tcc {
|
||||
// tcc currently has a bug, causing all #line files,
|
||||
// to be prefixed with the *same folder as the .tmp.c file*
|
||||
// this ../../ escaping, is a temporary workaround for that
|
||||
return '../../../../../..' + cescaped_path(os.real_path(path))
|
||||
}
|
||||
return cescaped_path(os.real_path(path))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue