Skip to content

Commit bcfc16a

Browse files
authored
all: add OS-specific headers support for #include directives (#26654) (fixes #26562)
1 parent 0a6f7c2 commit bcfc16a

12 files changed

Lines changed: 99 additions & 15 deletions

File tree

vlib/v/ast/ast.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1504,7 +1504,8 @@ pub mut:
15041504
msg string // : 'please install openssl'
15051505
ct_conds []Expr // *all* comptime conditions, that must be true, for the hash to be processed
15061506
// ct_conds is filled by the checker, based on the current nesting of `$if cond1 {}` blocks
1507-
attrs []Attr
1507+
ct_low_level_cond string // optional low-level comptime condition e.g. 'linux', 'darwin' for `#include linux <pty.h>`
1508+
attrs []Attr
15081509
}
15091510

15101511
// variable assign statement

vlib/v/checker/checker.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2950,6 +2950,11 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) {
29502950
if c.ct_cond_stack.len > 0 {
29512951
node.ct_conds = c.ct_cond_stack.clone()
29522952
}
2953+
if node.ct_low_level_cond.len > 0
2954+
&& node.ct_low_level_cond !in ast.valid_comptime_not_user_defined {
2955+
c.error('invalid OS/platform condition `${node.ct_low_level_cond}` in #${node.kind}',
2956+
node.pos)
2957+
}
29532958
if c.pref.backend == .golang || c.is_js_backend {
29542959
// consider the best way to handle the .go.vv files
29552960
if !c.file.path.ends_with('.js.v') && !c.file.path.ends_with('.go.v')

vlib/v/gen/c/cgen.v

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6214,6 +6214,16 @@ fn (mut g Gen) gen_hash_stmts(mut sb strings.Builder, node &ast.HashStmtNode, se
62146214
if !need_gen_stmt {
62156215
return
62166216
}
6217+
// OS-specific condition e.g. `#include linux <pty.h>` wraps the output with #if / #endif
6218+
has_low_level_cond := node.ct_low_level_cond.len > 0
6219+
if has_low_level_cond {
6220+
ifdef := ast.comptime_if_to_ifdef(node.ct_low_level_cond, g.pref) or {
6221+
g.error('#${node.kind} has invalid condition `${node.ct_low_level_cond}`',
6222+
node.pos)
6223+
return
6224+
}
6225+
sb.writeln('\n#if defined(${ifdef})')
6226+
}
62176227
line_nr := node.pos.line_nr + 1
62186228
match node.kind {
62196229
'include', 'preinclude', 'postinclude' {
@@ -6233,6 +6243,9 @@ fn (mut g Gen) gen_hash_stmts(mut sb strings.Builder, node &ast.HashStmtNode, se
62336243
}
62346244
else {}
62356245
}
6246+
if has_low_level_cond {
6247+
sb.writeln('#endif')
6248+
}
62366249
}
62376250
// TODO: support $match
62386251
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#if defined(__linux__)
2+
#include <pty.h>
3+
#endif
4+
#if defined(__DARWIN__)
5+
#include <util.h>
6+
#endif
7+
#if defined(_WIN32)
8+
#include "win_header.h"
9+
#endif
10+
#if defined(__FreeBSD__)
11+
#include <libutil.h>
12+
#endif
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// vtest vflags: -os cross
2+
module main
3+
4+
#include linux <pty.h>
5+
#include darwin <util.h>
6+
#include windows "win_header.h"
7+
#include freebsd <libutil.h>
8+
9+
fn main() {
10+
}

vlib/v/gen/native/comptime.v

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ fn (mut g Gen) comptime_conditional(node ast.IfExpr) ?ast.IfBranch {
1515
}
1616

1717
fn (mut g Gen) should_emit_hash_stmt(node ast.HashStmt) bool {
18+
if node.ct_low_level_cond.len > 0 {
19+
if !g.comptime_ident(node.ct_low_level_cond, false) {
20+
return false
21+
}
22+
}
1823
return node.ct_conds.all(g.comptime_is_truthy(it))
1924
}
2025

vlib/v/parser/comptime.v

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ fn (mut p Parser) hash() ast.HashStmt {
9393
p.next()
9494
mut main_str := ''
9595
mut msg := ''
96+
mut ct_low_level_cond := ''
9697
content := val.all_after('${kind} ').all_before('//')
9798
if content.contains(' #') {
9899
main_str = content.all_before(' #').trim_space()
@@ -102,6 +103,19 @@ fn (mut p Parser) hash() ast.HashStmt {
102103
msg = ''
103104
}
104105

106+
// Detect OS-specific conditions like `#include linux <pty.h>` or `#include darwin "util.h"`.
107+
// The condition is the first word before the actual include path.
108+
if kind in ['include', 'preinclude', 'postinclude', 'insert'] {
109+
first_space := main_str.index_u8(` `)
110+
if first_space > 0 {
111+
maybe_cond := main_str[..first_space]
112+
if maybe_cond in ast.valid_comptime_not_user_defined {
113+
ct_low_level_cond = maybe_cond
114+
main_str = main_str[first_space + 1..].trim_space()
115+
}
116+
}
117+
}
118+
105119
mut is_use_once := false
106120
for fna in attrs {
107121
match fna.name {
@@ -111,15 +125,16 @@ fn (mut p Parser) hash() ast.HashStmt {
111125
}
112126

113127
return ast.HashStmt{
114-
mod: p.mod
115-
source_file: p.file_path
116-
val: val
117-
kind: kind
118-
main: main_str
119-
msg: msg
120-
pos: pos
121-
attrs: attrs
122-
is_use_once: is_use_once
128+
mod: p.mod
129+
source_file: p.file_path
130+
val: val
131+
kind: kind
132+
main: main_str
133+
msg: msg
134+
pos: pos
135+
attrs: attrs
136+
is_use_once: is_use_once
137+
ct_low_level_cond: ct_low_level_cond
123138
}
124139
}
125140

vlib/v2/ast/ast.v

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -810,8 +810,9 @@ pub:
810810
// #flag / #include
811811
pub struct Directive {
812812
pub:
813-
name string
814-
value string
813+
name string
814+
value string
815+
ct_cond string // optional comptime condition e.g. 'linux', 'darwin' for `#include linux <pty.h>`
815816
}
816817

817818
pub struct EnumDecl {

vlib/v2/ast_dump/ast_dump.v

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,12 @@ fn (mut jb JsonBuilder) write_directive(stmt ast.Directive) {
404404
jb.write_indent()
405405
jb.sb.write_string('"value": ')
406406
jb.write_string(stmt.value)
407+
if stmt.ct_cond.len > 0 {
408+
jb.sb.write_string(',\n')
409+
jb.write_indent()
410+
jb.sb.write_string('"ct_cond": ')
411+
jb.write_string(stmt.ct_cond)
412+
}
407413
jb.sb.write_string('\n')
408414

409415
jb.indent--

vlib/v2/gen/cleanc/stmt.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ fn (mut g Gen) gen_stmt(node ast.Stmt) {
287287
}
288288
ast.Directive {
289289
g.write_indent()
290-
g.sb.writeln('/* [TODO] Directive: #${node.name} ${node.value} */')
290+
ct_cond_str := if node.ct_cond.len > 0 { ' ct_cond=${node.ct_cond}' } else { '' }
291+
g.sb.writeln('/* [TODO] Directive: #${node.name} ${node.value}${ct_cond_str} */')
291292
}
292293
ast.ForInStmt {
293294
panic('bug in v2 compiler: ForInStmt should have been lowered in v2.transformer')

0 commit comments

Comments
 (0)