From 6313ed6a79ad357808fb413128cc8d32b215c95c Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 23 Jul 2021 15:30:51 +0300 Subject: [PATCH] checker,cgen: fix `-os cross` support for `$if !solaris { #include }` --- vlib/v/ast/ast.v | 12 +++--- vlib/v/checker/checker.v | 10 ++++- vlib/v/gen/c/cgen.v | 41 +++++++++++++++++-- vlib/v/pref/pref.v | 2 +- .../project_with_c_code_ct_ifs/a_linux.h | 1 + .../project_with_c_code_ct_ifs/a_nonlinux.h | 1 + .../project_with_c_code_ct_ifs/ctimeifblock.v | 11 +++++ vlib/v/tests/project_with_c_code_ct_ifs/v.mod | 0 8 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 vlib/v/tests/project_with_c_code_ct_ifs/a_linux.h create mode 100644 vlib/v/tests/project_with_c_code_ct_ifs/a_nonlinux.h create mode 100644 vlib/v/tests/project_with_c_code_ct_ifs/ctimeifblock.v create mode 100644 vlib/v/tests/project_with_c_code_ct_ifs/v.mod diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 04a5f851cc..e7dabab438 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -874,17 +874,19 @@ pub mut: scope &Scope } -// #include etc +// #include, #define etc pub struct HashStmt { pub: mod string pos token.Position source_file string pub mut: - val string // example: 'include # please install openssl // comment' - kind string // : 'include' - main string // : '' - msg string // : 'please install openssl' + val string // example: 'include # please install openssl // comment' + kind string // : 'include' + main string // : '' + msg string // : 'please install openssl' + ct_conds []Expr // *all* comptime conditions, that must be true, for the hash to be processed + // ct_conds is filled by the checker, based on the current nesting of `$if cond1 {}` blocks } /* diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index cfc223c156..4811c4a030 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -77,7 +77,8 @@ pub mut: inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_ct_attr bool // true inside [if expr] skip_flags bool // should `#flag` and `#include` be skipped - fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc + fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc + ct_cond_stack []ast.Expr mut: files []ast.File expr_level int // to avoid infinite recursion segfaults due to compiler bugs @@ -4908,6 +4909,9 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { if c.skip_flags { return } + if c.ct_cond_stack.len > 0 { + node.ct_conds = c.ct_cond_stack.clone() + } if c.pref.backend.is_js() { if !c.file.path.ends_with('.js.v') { c.error('hash statements are only allowed in backend specific files such "x.js.v"', @@ -6551,6 +6555,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { // statements, in `-os cross` mode found_branch = false c.skip_flags = false + c.ct_cond_stack << branch.cond } if !c.skip_flags { c.stmts(branch.stmts) @@ -6573,6 +6578,9 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { c.comptime_fields_type.delete(comptime_field_name) } c.skip_flags = cur_skip_flags + if c.fn_level == 0 && c.pref.output_cross_c && c.ct_cond_stack.len > 0 { + c.ct_cond_stack.pop() + } } else { // smartcast sumtypes and interfaces when using `is` c.smartcast_if_conds(branch.cond, mut branch.scope) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 59bd660108..59a4cf6351 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1358,6 +1358,19 @@ fn (mut g Gen) stmt(node ast.Stmt) { g.writeln('goto $node.name;') } ast.HashStmt { + mut ct_condition := '' + if node.ct_conds.len > 0 { + ct_condition_start := g.out.len + for idx, ct_expr in node.ct_conds { + g.comp_if_cond(ct_expr, false) + if idx < node.ct_conds.len - 1 { + g.write(' && ') + } + } + ct_condition = g.out.cut_to(ct_condition_start).trim_space() + // dump(node) + // dump(ct_condition) + } // #include etc if node.kind == 'include' { mut missing_message := 'Header file $node.main, needed for module `$node.mod` was not found.' @@ -1372,17 +1385,39 @@ fn (mut g Gen) stmt(node ast.Stmt) { guarded_include = '#include $node.main' } if node.main.contains('.m') { + g.definitions.writeln('\n') + if ct_condition.len > 0 { + g.definitions.writeln('#if $ct_condition') + } // Objective C code import, include it after V types, so that e.g. `string` is // available there - g.definitions.writeln('// added by module `$node.mod`:') + g.definitions.writeln('// added by module `$node.mod`') g.definitions.writeln(guarded_include) + if ct_condition.len > 0 { + g.definitions.writeln('#endif // \$if $ct_condition') + } + g.definitions.writeln('\n') } else { - g.includes.writeln('// added by module `$node.mod`:') + g.includes.writeln('\n') + if ct_condition.len > 0 { + g.includes.writeln('#if $ct_condition') + } + g.includes.writeln('// added by module `$node.mod`') g.includes.writeln(guarded_include) + if ct_condition.len > 0 { + g.includes.writeln('#endif // \$if $ct_condition') + } + g.includes.writeln('\n') } } else if node.kind == 'define' { - g.includes.writeln('// defined by module `$node.mod` in file `$node.source_file`:') + if ct_condition.len > 0 { + g.includes.writeln('#if $ct_condition') + } + g.includes.writeln('// defined by module `$node.mod`') g.includes.writeln('#define $node.main') + if ct_condition.len > 0 { + g.includes.writeln('#endif // \$if $ct_condition') + } } } ast.Import {} diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 3e672f5437..07ad5ed296 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -154,7 +154,7 @@ pub mut: custom_prelude string // Contents of custom V prelude that will be prepended before code in resulting .c files lookup_path []string bare_builtin_dir string // Path to implementation of malloc, memset, etc. Only used if is_bare is true - output_cross_c bool // true, when the user passed `-os cross` + output_cross_c bool // true, when the user passed `-os cross` prealloc bool vroot string out_name_c string // full os.real_path to the generated .tmp.c file; set by builder. diff --git a/vlib/v/tests/project_with_c_code_ct_ifs/a_linux.h b/vlib/v/tests/project_with_c_code_ct_ifs/a_linux.h new file mode 100644 index 0000000000..801d989200 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_ct_ifs/a_linux.h @@ -0,0 +1 @@ +char *version = "linux"; diff --git a/vlib/v/tests/project_with_c_code_ct_ifs/a_nonlinux.h b/vlib/v/tests/project_with_c_code_ct_ifs/a_nonlinux.h new file mode 100644 index 0000000000..f190ca9c86 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_ct_ifs/a_nonlinux.h @@ -0,0 +1 @@ +char *version = "non-linux"; diff --git a/vlib/v/tests/project_with_c_code_ct_ifs/ctimeifblock.v b/vlib/v/tests/project_with_c_code_ct_ifs/ctimeifblock.v new file mode 100644 index 0000000000..e29362e80e --- /dev/null +++ b/vlib/v/tests/project_with_c_code_ct_ifs/ctimeifblock.v @@ -0,0 +1,11 @@ +$if linux { + #include "@VMODROOT/a_linux.h" +} + +$if !linux { + #include "@VMODROOT/a_nonlinux.h" +} + +fn main() { + C.printf(c'a: %s\n', C.version) +} diff --git a/vlib/v/tests/project_with_c_code_ct_ifs/v.mod b/vlib/v/tests/project_with_c_code_ct_ifs/v.mod new file mode 100644 index 0000000000..e69de29bb2