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) {
|
pub fn (mut b Builder) build_c(v_files []string, out_file string) {
|
||||||
b.out_name_c = out_file
|
b.out_name_c = out_file
|
||||||
|
b.pref.out_name_c = os.real_path(out_file)
|
||||||
b.info('build_c($out_file)')
|
b.info('build_c($out_file)')
|
||||||
output2 := b.gen_c(v_files)
|
output2 := b.gen_c(v_files)
|
||||||
mut f := os.create(out_file) or {
|
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_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_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_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
|
optionals []string // to avoid duplicates TODO perf, use map
|
||||||
shareds []int // types with hidden mutex for which decl has been emitted
|
shareds []int // types with hidden mutex for which decl has been emitted
|
||||||
inside_ternary int // ?: comma separated statements on a single line
|
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
|
mut autofree_used := false
|
||||||
for file in files {
|
for file in files {
|
||||||
g.file = file
|
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')
|
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
|
||||||
// building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
|
// 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')
|
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_variadic_types()
|
||||||
// g.write_str_definitions()
|
// 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 {
|
if g.pref.build_mode != .build_module {
|
||||||
// no init in builtin.o
|
// no init in builtin.o
|
||||||
g.write_init_function()
|
g.write_init_function()
|
||||||
|
@ -235,7 +242,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||||
return b.str()
|
return b.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (g Gen) hashes() string {
|
pub fn (g &Gen) hashes() string {
|
||||||
mut res := c_commit_hash_default.replace('@@@', util.vhash())
|
mut res := c_commit_hash_default.replace('@@@', util.vhash())
|
||||||
res += c_current_commit_hash_default.replace('@@@', util.githash(g.pref.building_v))
|
res += c_current_commit_hash_default.replace('@@@', util.githash(g.pref.building_v))
|
||||||
return res
|
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) {
|
pub fn (mut g Gen) write(s string) {
|
||||||
$if trace_gen ? {
|
$if trace_gen ? {
|
||||||
eprintln('gen file: ${g.file.path:-30} | last_fn_c_name: ${g.last_fn_c_name:-45} | write: $s')
|
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) {
|
fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
g.stmt_path_pos << g.out.len
|
g.stmt_path_pos << g.out.len
|
||||||
defer {
|
defer {
|
||||||
|
@ -664,9 +677,11 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
// g.writeln('//// stmt start')
|
// g.writeln('//// stmt start')
|
||||||
match node {
|
match node {
|
||||||
ast.AssertStmt {
|
ast.AssertStmt {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
g.gen_assert_stmt(node)
|
g.gen_assert_stmt(node)
|
||||||
}
|
}
|
||||||
ast.AssignStmt {
|
ast.AssignStmt {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
g.gen_assign_stmt(node)
|
g.gen_assign_stmt(node)
|
||||||
}
|
}
|
||||||
ast.Block {
|
ast.Block {
|
||||||
|
@ -679,11 +694,13 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
ast.BranchStmt {
|
ast.BranchStmt {
|
||||||
|
g.write_v_source_line_info(node.tok.position())
|
||||||
// continue or break
|
// continue or break
|
||||||
g.write(node.tok.kind.str())
|
g.write(node.tok.kind.str())
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
ast.ConstDecl {
|
ast.ConstDecl {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
// if g.pref.build_mode != .build_module {
|
// if g.pref.build_mode != .build_module {
|
||||||
g.const_decl(node)
|
g.const_decl(node)
|
||||||
// }
|
// }
|
||||||
|
@ -692,6 +709,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
g.comp_for(node)
|
g.comp_for(node)
|
||||||
}
|
}
|
||||||
ast.CompIf {
|
ast.CompIf {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
g.comp_if(node)
|
g.comp_if(node)
|
||||||
}
|
}
|
||||||
ast.DeferStmt {
|
ast.DeferStmt {
|
||||||
|
@ -723,6 +741,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
g.enum_typedefs.writeln('} $enum_name;\n')
|
g.enum_typedefs.writeln('} $enum_name;\n')
|
||||||
}
|
}
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
if g.inside_ternary == 0 && !node.is_expr && !(node.expr is ast.IfExpr) {
|
if g.inside_ternary == 0 && !node.is_expr && !(node.expr is ast.IfExpr) {
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
|
@ -779,6 +798,8 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.ForCStmt {
|
ast.ForCStmt {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
|
g.is_vlines_enabled = false
|
||||||
g.write('for (')
|
g.write('for (')
|
||||||
if !node.has_init {
|
if !node.has_init {
|
||||||
g.write('; ')
|
g.write('; ')
|
||||||
|
@ -799,13 +820,17 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
g.stmt(node.inc)
|
g.stmt(node.inc)
|
||||||
}
|
}
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
|
g.is_vlines_enabled = true
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
ast.ForInStmt {
|
ast.ForInStmt {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
g.for_in(node)
|
g.for_in(node)
|
||||||
}
|
}
|
||||||
ast.ForStmt {
|
ast.ForStmt {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
|
g.is_vlines_enabled = false
|
||||||
g.write('while (')
|
g.write('while (')
|
||||||
if node.is_inf {
|
if node.is_inf {
|
||||||
g.write('1')
|
g.write('1')
|
||||||
|
@ -813,6 +838,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
g.expr(node.cond)
|
g.expr(node.cond)
|
||||||
}
|
}
|
||||||
g.writeln(') {')
|
g.writeln(') {')
|
||||||
|
g.is_vlines_enabled = true
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
|
@ -2784,7 +2810,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[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 {
|
match expr {
|
||||||
ast.CallExpr { return g.table.get_type_symbol(expr.return_type).kind == .multi_return }
|
ast.CallExpr { return g.table.get_type_symbol(expr.return_type).kind == .multi_return }
|
||||||
else { return false }
|
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) {
|
fn (mut g Gen) return_statement(node ast.Return) {
|
||||||
|
g.write_v_source_line_info(node.pos)
|
||||||
if node.exprs.len > 0 {
|
if node.exprs.len > 0 {
|
||||||
// skip `retun $vweb.html()`
|
// skip `retun $vweb.html()`
|
||||||
if node.exprs[0] is ast.ComptimeCall {
|
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
|
// 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()
|
mut dep_graph := depgraph.new_dep_graph()
|
||||||
// types name list
|
// types name list
|
||||||
mut type_names := []string{}
|
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 tfuncs := []string{}
|
||||||
mut tsuite_begin := ''
|
mut tsuite_begin := ''
|
||||||
mut tsuite_end := ''
|
mut tsuite_end := ''
|
||||||
|
@ -4215,7 +4242,7 @@ fn (g Gen) get_all_test_function_names() []string {
|
||||||
return all_tfuncs_c
|
return all_tfuncs_c
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g Gen) is_importing_os() bool {
|
fn (g &Gen) is_importing_os() bool {
|
||||||
return 'os' in g.table.imports
|
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('}')
|
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)
|
sym := g.table.get_type_symbol(typ)
|
||||||
if sym.kind in [.struct_, .array, .array_fixed, .map] {
|
if sym.kind in [.struct_, .array, .array_fixed, .map] {
|
||||||
return '%.*s\\000'
|
return '%.*s\\000'
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module gen
|
module gen
|
||||||
|
|
||||||
|
import v.util
|
||||||
|
|
||||||
pub fn (mut g Gen) gen_c_main() {
|
pub fn (mut g Gen) gen_c_main() {
|
||||||
if !g.has_main {
|
if !g.has_main {
|
||||||
return
|
return
|
||||||
|
@ -7,16 +9,33 @@ pub fn (mut g Gen) gen_c_main() {
|
||||||
if g.pref.is_liveshared {
|
if g.pref.is_liveshared {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.out.writeln('')
|
g.out.writeln('')
|
||||||
main_fn_start_pos := g.out.len
|
main_fn_start_pos := g.out.len
|
||||||
g.gen_c_main_header()
|
g.gen_c_main_header()
|
||||||
g.writeln('\tmain__main();')
|
g.writeln('\tmain__main();')
|
||||||
g.gen_c_main_footer()
|
g.gen_c_main_footer()
|
||||||
if g.pref.printfn_list.len > 0 && 'main' in g.pref.printfn_list {
|
if g.pref.printfn_list.len > 0 && 'main' in g.pref.printfn_list {
|
||||||
println(g.out.after(main_fn_start_pos))
|
println(g.out.after(main_fn_start_pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
fn (mut g Gen) gen_c_main_header() {
|
||||||
if g.pref.os == .windows {
|
if g.pref.os == .windows {
|
||||||
if g.is_gui_app() {
|
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('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);')
|
||||||
}
|
}
|
||||||
g.writeln('\t_vinit();')
|
g.writeln('\t_vinit();')
|
||||||
|
|
||||||
if g.pref.is_prof {
|
if g.pref.is_prof {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
g.writeln('\tatexit(vprint_profile_stats);')
|
g.writeln('\tatexit(vprint_profile_stats);')
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.is_importing_os() {
|
if g.is_importing_os() {
|
||||||
if g.autofree {
|
if g.autofree {
|
||||||
g.writeln('free(_const_os__args.data); // empty, inited in _vinit()')
|
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 {
|
if g.autofree {
|
||||||
g.writeln('\t_vcleanup();')
|
g.writeln('\t_vcleanup();')
|
||||||
}
|
}
|
||||||
|
|
||||||
g.writeln('\treturn 0;')
|
g.writeln('\treturn 0;')
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||||
}
|
}
|
||||||
// g.cur_fn = it
|
// g.cur_fn = it
|
||||||
fn_start_pos := g.out.len
|
fn_start_pos := g.out.len
|
||||||
|
g.write_v_source_line_info(it.pos)
|
||||||
msvc_attrs := g.write_fn_attrs(it.attrs)
|
msvc_attrs := g.write_fn_attrs(it.attrs)
|
||||||
// Live
|
// Live
|
||||||
is_livefn := it.attrs.contains('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_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).
|
is_vlines bool // turned on by -g, false by default (it slows down .tmp.c generation slightly).
|
||||||
show_cc bool // -showcc, print cc command
|
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).
|
// 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.
|
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
|
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
|
output_cross_c bool
|
||||||
prealloc bool
|
prealloc bool
|
||||||
vroot string
|
vroot string
|
||||||
|
out_name_c string // full os.real_path to the generated .tmp.c file; set by builder.
|
||||||
out_name string
|
out_name string
|
||||||
display_name string
|
display_name string
|
||||||
bundle_id string
|
bundle_id string
|
||||||
|
@ -144,8 +145,13 @@ pub fn parse_args(args []string) (&Preferences, string) {
|
||||||
'-silent' {
|
'-silent' {
|
||||||
res.output_mode = .silent
|
res.output_mode = .silent
|
||||||
}
|
}
|
||||||
|
'-g' {
|
||||||
|
res.is_debug = true
|
||||||
|
res.is_vlines = true
|
||||||
|
}
|
||||||
'-cg' {
|
'-cg' {
|
||||||
res.is_debug = true
|
res.is_debug = true
|
||||||
|
res.is_vlines = false
|
||||||
}
|
}
|
||||||
'-repl' {
|
'-repl' {
|
||||||
res.is_repl = true
|
res.is_repl = true
|
||||||
|
|
|
@ -141,3 +141,14 @@ pub fn verror(kind, s string) {
|
||||||
eprintln('$final_kind: $s')
|
eprintln('$final_kind: $s')
|
||||||
exit(1)
|
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