From cd31108260a3139a7e21bccd19c94601883394d4 Mon Sep 17 00:00:00 2001 From: irishgreencitrus <43090499+irishgreencitrus@users.noreply.github.com> Date: Thu, 18 Aug 2022 13:59:08 +0100 Subject: [PATCH] cgen: implement '#preinclude' (#15456) --- vlib/v/checker/checker.v | 4 +- vlib/v/gen/c/cgen.v | 45 +++++++++++++++++++ vlib/v/gen/c/testdata/preinclude_example.out | 1 + vlib/v/gen/c/testdata/preinclude_example.vv | 9 ++++ .../preinclude_example_changed_order.out | 1 + .../preinclude_example_changed_order.vv | 8 ++++ vlib/v/gen/c/testdata/preinclude_header.h | 4 ++ vlib/v/gen/c/testdata/preinclude_header2.h | 4 ++ 8 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 vlib/v/gen/c/testdata/preinclude_example.out create mode 100644 vlib/v/gen/c/testdata/preinclude_example.vv create mode 100644 vlib/v/gen/c/testdata/preinclude_example_changed_order.out create mode 100644 vlib/v/gen/c/testdata/preinclude_example_changed_order.vv create mode 100644 vlib/v/gen/c/testdata/preinclude_header.h create mode 100644 vlib/v/gen/c/testdata/preinclude_header2.h diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 80b9bd92e..33fa3d900 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1795,7 +1795,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { return } match node.kind { - 'include', 'insert' { + 'include', 'insert', 'preinclude' { original_flag := node.main mut flag := node.main if flag.contains('@VROOT') { @@ -1831,7 +1831,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { node.main = env } flag_no_comment := flag.all_before('//').trim_space() - if node.kind == 'include' { + if node.kind == 'include' || node.kind == 'preinclude' { if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"')) || (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) { c.error('including C files should use either `"header_file.h"` or `` quoting', diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 73fda94ef..0e6a12c65 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -52,6 +52,7 @@ struct Gen { mut: out strings.Builder cheaders strings.Builder + preincludes strings.Builder // allows includes to go before `definitions` includes strings.Builder // all C #includes required by V modules typedefs strings.Builder enum_typedefs strings.Builder // enum types @@ -244,6 +245,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { out: strings.new_builder(512000) cheaders: strings.new_builder(15000) includes: strings.new_builder(100) + preincludes: strings.new_builder(100) typedefs: strings.new_builder(100) enum_typedefs: strings.new_builder(100) type_definitions: strings.new_builder(100) @@ -301,6 +303,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { global_g.embedded_files << g.embedded_files global_g.out.write(g.out) or { panic(err) } global_g.cheaders.write(g.cheaders) or { panic(err) } + global_g.preincludes.write(g.preincludes) or { panic(err) } global_g.includes.write(g.includes) or { panic(err) } global_g.typedefs.write(g.typedefs) or { panic(err) } global_g.type_definitions.write(g.type_definitions) or { panic(err) } @@ -443,6 +446,8 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { b.write_string(g.comptime_definitions.str()) b.writeln('\n// V typedefs:') b.write_string(g.typedefs.str()) + b.writeln('\n // V preincludes:') + b.write_string(g.preincludes.str()) b.writeln('\n// V cheaders:') b.write_string(g.cheaders.str()) if g.pcs_declarations.len > 0 { @@ -668,6 +673,7 @@ pub fn (mut g Gen) init() { // tcc does not support has_include properly yet, turn it off completely #undef __has_include #endif' + g.preincludes.writeln(tcc_undef_has_include) g.cheaders.writeln(tcc_undef_has_include) g.includes.writeln(tcc_undef_has_include) if g.pref.os == .freebsd { @@ -1905,6 +1911,45 @@ fn (mut g Gen) stmt(node ast.Stmt) { } g.includes.writeln('\n') } + } else if node.kind == 'preinclude' { + mut missing_message := 'Header file $node.main, needed for module `$node.mod` was not found.' + if node.msg != '' { + missing_message += ' ${node.msg}.' + } else { + missing_message += ' Please install the corresponding development headers.' + } + mut guarded_include := get_guarded_include_text(node.main, missing_message) + if node.main == '' { + // fails with musl-gcc and msvc; but an unguarded include works: + guarded_include = '#include $node.main' + } + if node.main.contains('.m') { + // Might need to support '#preinclude' for .m files as well but for the moment + // this does the same as '#include' for them + 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`, file: ${os.file_name(node.source_file)}:$line_nr:') + g.definitions.writeln(guarded_include) + if ct_condition.len > 0 { + g.definitions.writeln('#endif // \$if $ct_condition') + } + g.definitions.writeln('\n') + } else { + g.preincludes.writeln('\n') + if ct_condition.len > 0 { + g.preincludes.writeln('#if $ct_condition') + } + g.preincludes.writeln('// added by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:') + g.preincludes.writeln(guarded_include) + if ct_condition.len > 0 { + g.preincludes.writeln('#endif // \$if $ct_condition') + } + g.preincludes.writeln('\n') + } } else if node.kind == 'insert' { if ct_condition.len > 0 { g.includes.writeln('#if $ct_condition') diff --git a/vlib/v/gen/c/testdata/preinclude_example.out b/vlib/v/gen/c/testdata/preinclude_example.out new file mode 100644 index 000000000..8d38505c1 --- /dev/null +++ b/vlib/v/gen/c/testdata/preinclude_example.out @@ -0,0 +1 @@ +456 diff --git a/vlib/v/gen/c/testdata/preinclude_example.vv b/vlib/v/gen/c/testdata/preinclude_example.vv new file mode 100644 index 000000000..9b5bf8ecb --- /dev/null +++ b/vlib/v/gen/c/testdata/preinclude_example.vv @@ -0,0 +1,9 @@ +#include "@VEXEROOT/vlib/v/gen/c/testdata/preinclude_header2.h" + +#preinclude "@VEXEROOT/vlib/v/gen/c/testdata/preinclude_header.h" + +fn main() { + a := int(C.MYNUMBER) + println(a) + assert a == 456 +} diff --git a/vlib/v/gen/c/testdata/preinclude_example_changed_order.out b/vlib/v/gen/c/testdata/preinclude_example_changed_order.out new file mode 100644 index 000000000..a6905f8ba --- /dev/null +++ b/vlib/v/gen/c/testdata/preinclude_example_changed_order.out @@ -0,0 +1 @@ +999 diff --git a/vlib/v/gen/c/testdata/preinclude_example_changed_order.vv b/vlib/v/gen/c/testdata/preinclude_example_changed_order.vv new file mode 100644 index 000000000..05f4887ec --- /dev/null +++ b/vlib/v/gen/c/testdata/preinclude_example_changed_order.vv @@ -0,0 +1,8 @@ +#include "@VEXEROOT/vlib/v/gen/c/testdata/preinclude_header.h" +#preinclude "@VEXEROOT/vlib/v/gen/c/testdata/preinclude_header2.h" + +fn main() { + a := int(C.MYNUMBER) + println(a) + assert a == 999 +} diff --git a/vlib/v/gen/c/testdata/preinclude_header.h b/vlib/v/gen/c/testdata/preinclude_header.h new file mode 100644 index 000000000..0b7cc163a --- /dev/null +++ b/vlib/v/gen/c/testdata/preinclude_header.h @@ -0,0 +1,4 @@ + +#ifndef MYNUMBER +#define MYNUMBER 456 +#endif diff --git a/vlib/v/gen/c/testdata/preinclude_header2.h b/vlib/v/gen/c/testdata/preinclude_header2.h new file mode 100644 index 000000000..1a2d68749 --- /dev/null +++ b/vlib/v/gen/c/testdata/preinclude_header2.h @@ -0,0 +1,4 @@ + +#ifndef MYNUMBER +#define MYNUMBER 999 +#endif -- 2.39.5