Skip to content

Commit d82757a

Browse files
committed
checker,cgen: add support for a #postinclude directive
1 parent a4101f4 commit d82757a

File tree

4 files changed

+51
-32
lines changed

4 files changed

+51
-32
lines changed

doc/docs.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7949,26 +7949,36 @@ seamlessly across all platforms.
79497949
However, since the Windows header libraries use extremely generic names such as `Rectangle`,
79507950
this will cause a conflict if you wish to use C code that also has a name defined as `Rectangle`.
79517951
7952-
For very specific cases like this, we have `#preinclude`.
7952+
For very specific cases like this, V has `#preinclude` and `#postinclude` directives.
79537953
7954-
This will allow things to be configured before V adds in its built in libraries.
7954+
These directives allow things to be configured *before* V adds in its built in libraries,
7955+
and *after* all of the V code generation has completed (and thus all of the prototypes,
7956+
declarations and definitions are already present).
79557957
79567958
Example usage:
79577959
```v ignore
79587960
// This will include before built in libraries are used.
79597961
#preinclude "pre_include.h"
7962+
79607963
// This will include after built in libraries are used.
79617964
#include "include.h"
7965+
7966+
// This will include after all of the V code generation is complete,
7967+
// including the one for the main function of the project
7968+
#postinclude "post_include.h"
79627969
```
79637970
79647971
An example of what might be included in `pre_include.h`
79657972
can be [found here](https://github.com/irishgreencitrus/raylib.v/blob/main/include/pre.h)
79667973
7967-
This is an advanced feature, and will not be necessary
7968-
outside of very specific cases with C interop,
7969-
meaning it could cause more issues than it solves.
7974+
The `#postinclude` directive on the other hand is useful for allowing the integration
7975+
of frameworks like SDL3 or Sokol, that insist on having callbacks in your code, instead
7976+
of behaving like ordinary libraries, and allowing you to decide when to call them.
7977+
7978+
NOTE: these are advanced features, and will not be necessary outside of very specific cases
7979+
with C interop. Other than those, using them could cause more issues than it solves.
79707980
7971-
Consider it last resort!
7981+
Consider using them as a last resort!
79727982
79737983
## Other V Features
79747984

vlib/v/checker/checker.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2612,7 +2612,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
26122612
return
26132613
}
26142614
match node.kind {
2615-
'include', 'insert', 'preinclude' {
2615+
'include', 'insert', 'preinclude', 'postinclude' {
26162616
original_flag := node.main
26172617
mut flag := node.main
26182618
if flag.contains('@VROOT') {
@@ -2655,7 +2655,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
26552655
node.main = d
26562656
}
26572657
flag_no_comment := flag.all_before('//').trim_space()
2658-
if node.kind == 'include' || node.kind == 'preinclude' {
2658+
if node.kind in ['include', 'preinclude', 'postinclude'] {
26592659
if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"'))
26602660
|| (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) {
26612661
c.error('including C files should use either `"header_file.h"` or `<header_file.h>` quoting',

vlib/v/gen/c/cgen.v

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ mut:
4848
// line_nr int
4949
cheaders strings.Builder
5050
preincludes strings.Builder // allows includes to go before `definitions`
51+
postincludes strings.Builder // allows includes to go after all the rest of the code generation
5152
includes strings.Builder // all C #includes required by V modules
5253
typedefs strings.Builder
5354
enum_typedefs strings.Builder // enum types
@@ -300,6 +301,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
300301
cheaders: strings.new_builder(15000)
301302
includes: strings.new_builder(100)
302303
preincludes: strings.new_builder(100)
304+
postincludes: strings.new_builder(100)
303305
typedefs: strings.new_builder(100)
304306
enum_typedefs: strings.new_builder(100)
305307
type_definitions: strings.new_builder(100)
@@ -387,6 +389,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
387389
global_g.out.write(g.out) or { panic(err) }
388390
global_g.cheaders.write(g.cheaders) or { panic(err) }
389391
global_g.preincludes.write(g.preincludes) or { panic(err) }
392+
global_g.postincludes.write(g.postincludes) or { panic(err) }
390393
global_g.includes.write(g.includes) or { panic(err) }
391394
global_g.typedefs.write(g.typedefs) or { panic(err) }
392395
global_g.type_definitions.write(g.type_definitions) or { panic(err) }
@@ -567,7 +570,6 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
567570
}
568571
b.write_string2('\n// V comptime_definitions:\n', g.comptime_definitions.str())
569572
b.write_string2('\n// V typedefs:\n', g.typedefs.str())
570-
b.write_string2('\n // V preincludes:\n', g.preincludes.str())
571573
b.write_string2('\n// V cheaders:', g.cheaders.str())
572574
if g.pcs_declarations.len > 0 {
573575
b.write_string2('\n// V profile counters:\n', g.pcs_declarations.str())
@@ -741,6 +743,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
741743
extern_out_str := g.extern_out.str()
742744
b.write_string(out_str)
743745
b.writeln('// THE END.')
746+
b.write_string2('\n // V postincludes:\n', g.postincludes.str())
744747
util.timing_measure('cgen common')
745748
$if trace_all_generic_fn_keys ? {
746749
gkeys := g.table.fn_generic_types.keys()
@@ -5436,6 +5439,21 @@ fn (mut g Gen) gen_option_error(target_type ast.Type, expr ast.Expr) {
54365439
g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }')
54375440
}
54385441

5442+
fn (mut g Gen) hash_stmt_guarded_include(node ast.HashStmt) string {
5443+
mut missing_message := 'Header file ${node.main}, needed for module `${node.mod}` was not found.'
5444+
if node.msg != '' {
5445+
missing_message += ' ${node.msg}.'
5446+
} else {
5447+
missing_message += ' Please install the corresponding development headers.'
5448+
}
5449+
mut guarded_include := get_guarded_include_text(node.main, missing_message)
5450+
if node.main == '<errno.h>' {
5451+
// fails with musl-gcc and msvc; but an unguarded include works:
5452+
guarded_include = '#include ${node.main}'
5453+
}
5454+
return guarded_include
5455+
}
5456+
54395457
fn (mut g Gen) hash_stmt(node ast.HashStmt) {
54405458
line_nr := node.pos.line_nr + 1
54415459
mut ct_condition := ''
@@ -5451,17 +5469,7 @@ fn (mut g Gen) hash_stmt(node ast.HashStmt) {
54515469
}
54525470
// #include etc
54535471
if node.kind == 'include' {
5454-
mut missing_message := 'Header file ${node.main}, needed for module `${node.mod}` was not found.'
5455-
if node.msg != '' {
5456-
missing_message += ' ${node.msg}.'
5457-
} else {
5458-
missing_message += ' Please install the corresponding development headers.'
5459-
}
5460-
mut guarded_include := get_guarded_include_text(node.main, missing_message)
5461-
if node.main == '<errno.h>' {
5462-
// fails with musl-gcc and msvc; but an unguarded include works:
5463-
guarded_include = '#include ${node.main}'
5464-
}
5472+
guarded_include := g.hash_stmt_guarded_include(node)
54655473
if node.main.contains('.m') {
54665474
g.definitions.writeln('')
54675475
if ct_condition != '' {
@@ -5486,17 +5494,7 @@ fn (mut g Gen) hash_stmt(node ast.HashStmt) {
54865494
}
54875495
}
54885496
} else if node.kind == 'preinclude' {
5489-
mut missing_message := 'Header file ${node.main}, needed for module `${node.mod}` was not found.'
5490-
if node.msg != '' {
5491-
missing_message += ' ${node.msg}.'
5492-
} else {
5493-
missing_message += ' Please install the corresponding development headers.'
5494-
}
5495-
mut guarded_include := get_guarded_include_text(node.main, missing_message)
5496-
if node.main == '<errno.h>' {
5497-
// fails with musl-gcc and msvc; but an unguarded include works:
5498-
guarded_include = '#include ${node.main}'
5499-
}
5497+
guarded_include := g.hash_stmt_guarded_include(node)
55005498
if node.main.contains('.m') {
55015499
// Might need to support '#preinclude' for .m files as well but for the moment
55025500
// this does the same as '#include' for them
@@ -5522,6 +5520,17 @@ fn (mut g Gen) hash_stmt(node ast.HashStmt) {
55225520
g.preincludes.writeln('#endif // \$if ${ct_condition}')
55235521
}
55245522
}
5523+
} else if node.kind == 'postinclude' {
5524+
guarded_include := g.hash_stmt_guarded_include(node)
5525+
g.postincludes.writeln('')
5526+
if ct_condition != '' {
5527+
g.postincludes.writeln('#if ${ct_condition}')
5528+
}
5529+
g.postincludes.writeln('// added by module `${node.mod}`, file: ${os.file_name(node.source_file)}:${line_nr}:')
5530+
g.postincludes.writeln(guarded_include)
5531+
if ct_condition != '' {
5532+
g.postincludes.writeln('#endif // \$if ${ct_condition}')
5533+
}
55255534
} else if node.kind == 'insert' {
55265535
if ct_condition != '' {
55275536
g.includes.writeln('#if ${ct_condition}')

vlib/v/gen/native/stmt.c.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
7575
}
7676

7777
match node.kind {
78-
'include', 'preinclude', 'define', 'insert' {
78+
'include', 'preinclude', 'postinclude', 'define', 'insert' {
7979
g.v_error('#${node.kind} is not supported with the native backend',
8080
node.pos)
8181
}

0 commit comments

Comments
 (0)