mirror of
https://github.com/vlang/v.git
synced 2025-09-11 16:36:20 -04:00
checker,cgen: add support for a #postinclude
directive
This commit is contained in:
parent
a4101f4ed8
commit
d82757abd9
22
doc/docs.md
22
doc/docs.md
@ -7949,26 +7949,36 @@ seamlessly across all platforms.
|
|||||||
However, since the Windows header libraries use extremely generic names such as `Rectangle`,
|
However, since the Windows header libraries use extremely generic names such as `Rectangle`,
|
||||||
this will cause a conflict if you wish to use C code that also has a name defined as `Rectangle`.
|
this will cause a conflict if you wish to use C code that also has a name defined as `Rectangle`.
|
||||||
|
|
||||||
For very specific cases like this, we have `#preinclude`.
|
For very specific cases like this, V has `#preinclude` and `#postinclude` directives.
|
||||||
|
|
||||||
This will allow things to be configured before V adds in its built in libraries.
|
These directives allow things to be configured *before* V adds in its built in libraries,
|
||||||
|
and *after* all of the V code generation has completed (and thus all of the prototypes,
|
||||||
|
declarations and definitions are already present).
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
```v ignore
|
```v ignore
|
||||||
// This will include before built in libraries are used.
|
// This will include before built in libraries are used.
|
||||||
#preinclude "pre_include.h"
|
#preinclude "pre_include.h"
|
||||||
|
|
||||||
// This will include after built in libraries are used.
|
// This will include after built in libraries are used.
|
||||||
#include "include.h"
|
#include "include.h"
|
||||||
|
|
||||||
|
// This will include after all of the V code generation is complete,
|
||||||
|
// including the one for the main function of the project
|
||||||
|
#postinclude "post_include.h"
|
||||||
```
|
```
|
||||||
|
|
||||||
An example of what might be included in `pre_include.h`
|
An example of what might be included in `pre_include.h`
|
||||||
can be [found here](https://github.com/irishgreencitrus/raylib.v/blob/main/include/pre.h)
|
can be [found here](https://github.com/irishgreencitrus/raylib.v/blob/main/include/pre.h)
|
||||||
|
|
||||||
This is an advanced feature, and will not be necessary
|
The `#postinclude` directive on the other hand is useful for allowing the integration
|
||||||
outside of very specific cases with C interop,
|
of frameworks like SDL3 or Sokol, that insist on having callbacks in your code, instead
|
||||||
meaning it could cause more issues than it solves.
|
of behaving like ordinary libraries, and allowing you to decide when to call them.
|
||||||
|
|
||||||
Consider it last resort!
|
NOTE: these are advanced features, and will not be necessary outside of very specific cases
|
||||||
|
with C interop. Other than those, using them could cause more issues than it solves.
|
||||||
|
|
||||||
|
Consider using them as a last resort!
|
||||||
|
|
||||||
## Other V Features
|
## Other V Features
|
||||||
|
|
||||||
|
@ -2612,7 +2612,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
match node.kind {
|
match node.kind {
|
||||||
'include', 'insert', 'preinclude' {
|
'include', 'insert', 'preinclude', 'postinclude' {
|
||||||
original_flag := node.main
|
original_flag := node.main
|
||||||
mut flag := node.main
|
mut flag := node.main
|
||||||
if flag.contains('@VROOT') {
|
if flag.contains('@VROOT') {
|
||||||
@ -2655,7 +2655,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
|
|||||||
node.main = d
|
node.main = d
|
||||||
}
|
}
|
||||||
flag_no_comment := flag.all_before('//').trim_space()
|
flag_no_comment := flag.all_before('//').trim_space()
|
||||||
if node.kind == 'include' || node.kind == 'preinclude' {
|
if node.kind in ['include', 'preinclude', 'postinclude'] {
|
||||||
if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"'))
|
if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"'))
|
||||||
|| (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 `<header_file.h>` quoting',
|
c.error('including C files should use either `"header_file.h"` or `<header_file.h>` quoting',
|
||||||
|
@ -48,6 +48,7 @@ mut:
|
|||||||
// line_nr int
|
// line_nr int
|
||||||
cheaders strings.Builder
|
cheaders strings.Builder
|
||||||
preincludes strings.Builder // allows includes to go before `definitions`
|
preincludes strings.Builder // allows includes to go before `definitions`
|
||||||
|
postincludes strings.Builder // allows includes to go after all the rest of the code generation
|
||||||
includes strings.Builder // all C #includes required by V modules
|
includes strings.Builder // all C #includes required by V modules
|
||||||
typedefs strings.Builder
|
typedefs strings.Builder
|
||||||
enum_typedefs strings.Builder // enum types
|
enum_typedefs strings.Builder // enum types
|
||||||
@ -300,6 +301,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
|
|||||||
cheaders: strings.new_builder(15000)
|
cheaders: strings.new_builder(15000)
|
||||||
includes: strings.new_builder(100)
|
includes: strings.new_builder(100)
|
||||||
preincludes: strings.new_builder(100)
|
preincludes: strings.new_builder(100)
|
||||||
|
postincludes: strings.new_builder(100)
|
||||||
typedefs: strings.new_builder(100)
|
typedefs: strings.new_builder(100)
|
||||||
enum_typedefs: strings.new_builder(100)
|
enum_typedefs: strings.new_builder(100)
|
||||||
type_definitions: strings.new_builder(100)
|
type_definitions: strings.new_builder(100)
|
||||||
@ -387,6 +389,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
|
|||||||
global_g.out.write(g.out) or { panic(err) }
|
global_g.out.write(g.out) or { panic(err) }
|
||||||
global_g.cheaders.write(g.cheaders) or { panic(err) }
|
global_g.cheaders.write(g.cheaders) or { panic(err) }
|
||||||
global_g.preincludes.write(g.preincludes) or { panic(err) }
|
global_g.preincludes.write(g.preincludes) or { panic(err) }
|
||||||
|
global_g.postincludes.write(g.postincludes) or { panic(err) }
|
||||||
global_g.includes.write(g.includes) or { panic(err) }
|
global_g.includes.write(g.includes) or { panic(err) }
|
||||||
global_g.typedefs.write(g.typedefs) or { panic(err) }
|
global_g.typedefs.write(g.typedefs) or { panic(err) }
|
||||||
global_g.type_definitions.write(g.type_definitions) or { panic(err) }
|
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
|
|||||||
}
|
}
|
||||||
b.write_string2('\n// V comptime_definitions:\n', g.comptime_definitions.str())
|
b.write_string2('\n// V comptime_definitions:\n', g.comptime_definitions.str())
|
||||||
b.write_string2('\n// V typedefs:\n', g.typedefs.str())
|
b.write_string2('\n// V typedefs:\n', g.typedefs.str())
|
||||||
b.write_string2('\n // V preincludes:\n', g.preincludes.str())
|
|
||||||
b.write_string2('\n// V cheaders:', g.cheaders.str())
|
b.write_string2('\n// V cheaders:', g.cheaders.str())
|
||||||
if g.pcs_declarations.len > 0 {
|
if g.pcs_declarations.len > 0 {
|
||||||
b.write_string2('\n// V profile counters:\n', g.pcs_declarations.str())
|
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
|
|||||||
extern_out_str := g.extern_out.str()
|
extern_out_str := g.extern_out.str()
|
||||||
b.write_string(out_str)
|
b.write_string(out_str)
|
||||||
b.writeln('// THE END.')
|
b.writeln('// THE END.')
|
||||||
|
b.write_string2('\n // V postincludes:\n', g.postincludes.str())
|
||||||
util.timing_measure('cgen common')
|
util.timing_measure('cgen common')
|
||||||
$if trace_all_generic_fn_keys ? {
|
$if trace_all_generic_fn_keys ? {
|
||||||
gkeys := g.table.fn_generic_types.keys()
|
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) {
|
|||||||
g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }')
|
g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) hash_stmt_guarded_include(node ast.HashStmt) string {
|
||||||
|
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 == '<errno.h>' {
|
||||||
|
// fails with musl-gcc and msvc; but an unguarded include works:
|
||||||
|
guarded_include = '#include ${node.main}'
|
||||||
|
}
|
||||||
|
return guarded_include
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) hash_stmt(node ast.HashStmt) {
|
fn (mut g Gen) hash_stmt(node ast.HashStmt) {
|
||||||
line_nr := node.pos.line_nr + 1
|
line_nr := node.pos.line_nr + 1
|
||||||
mut ct_condition := ''
|
mut ct_condition := ''
|
||||||
@ -5451,17 +5469,7 @@ fn (mut g Gen) hash_stmt(node ast.HashStmt) {
|
|||||||
}
|
}
|
||||||
// #include etc
|
// #include etc
|
||||||
if node.kind == 'include' {
|
if node.kind == 'include' {
|
||||||
mut missing_message := 'Header file ${node.main}, needed for module `${node.mod}` was not found.'
|
guarded_include := g.hash_stmt_guarded_include(node)
|
||||||
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 == '<errno.h>' {
|
|
||||||
// fails with musl-gcc and msvc; but an unguarded include works:
|
|
||||||
guarded_include = '#include ${node.main}'
|
|
||||||
}
|
|
||||||
if node.main.contains('.m') {
|
if node.main.contains('.m') {
|
||||||
g.definitions.writeln('')
|
g.definitions.writeln('')
|
||||||
if ct_condition != '' {
|
if ct_condition != '' {
|
||||||
@ -5486,17 +5494,7 @@ fn (mut g Gen) hash_stmt(node ast.HashStmt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if node.kind == 'preinclude' {
|
} else if node.kind == 'preinclude' {
|
||||||
mut missing_message := 'Header file ${node.main}, needed for module `${node.mod}` was not found.'
|
guarded_include := g.hash_stmt_guarded_include(node)
|
||||||
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 == '<errno.h>' {
|
|
||||||
// fails with musl-gcc and msvc; but an unguarded include works:
|
|
||||||
guarded_include = '#include ${node.main}'
|
|
||||||
}
|
|
||||||
if node.main.contains('.m') {
|
if node.main.contains('.m') {
|
||||||
// Might need to support '#preinclude' for .m files as well but for the moment
|
// Might need to support '#preinclude' for .m files as well but for the moment
|
||||||
// this does the same as '#include' for them
|
// this does the same as '#include' for them
|
||||||
@ -5522,6 +5520,17 @@ fn (mut g Gen) hash_stmt(node ast.HashStmt) {
|
|||||||
g.preincludes.writeln('#endif // \$if ${ct_condition}')
|
g.preincludes.writeln('#endif // \$if ${ct_condition}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if node.kind == 'postinclude' {
|
||||||
|
guarded_include := g.hash_stmt_guarded_include(node)
|
||||||
|
g.postincludes.writeln('')
|
||||||
|
if ct_condition != '' {
|
||||||
|
g.postincludes.writeln('#if ${ct_condition}')
|
||||||
|
}
|
||||||
|
g.postincludes.writeln('// added by module `${node.mod}`, file: ${os.file_name(node.source_file)}:${line_nr}:')
|
||||||
|
g.postincludes.writeln(guarded_include)
|
||||||
|
if ct_condition != '' {
|
||||||
|
g.postincludes.writeln('#endif // \$if ${ct_condition}')
|
||||||
|
}
|
||||||
} else if node.kind == 'insert' {
|
} else if node.kind == 'insert' {
|
||||||
if ct_condition != '' {
|
if ct_condition != '' {
|
||||||
g.includes.writeln('#if ${ct_condition}')
|
g.includes.writeln('#if ${ct_condition}')
|
||||||
|
@ -75,7 +75,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match node.kind {
|
match node.kind {
|
||||||
'include', 'preinclude', 'define', 'insert' {
|
'include', 'preinclude', 'postinclude', 'define', 'insert' {
|
||||||
g.v_error('#${node.kind} is not supported with the native backend',
|
g.v_error('#${node.kind} is not supported with the native backend',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user