checker: add pkgconfig to comptime if (#10692)
parent
aa5b609d95
commit
eb96ad11d9
12
doc/docs.md
12
doc/docs.md
|
@ -4017,6 +4017,18 @@ If no flags are passed it will add `--cflags` and `--libs`, both lines below do
|
|||
The `.pc` files are looked up into a hardcoded list of default pkg-config paths, the user can add
|
||||
extra paths by using the `PKG_CONFIG_PATH` environment variable. Multiple modules can be passed.
|
||||
|
||||
To check the existance of a pkg-config use `$pkgconfig('pkg')` as a compile time if condition to
|
||||
check if a pkg-config exists. If it exists the branch will be created. Use `$else` or `$else $if`
|
||||
to handle other cases.
|
||||
|
||||
```v ignore
|
||||
$if $pkgconfig('mysqlclient') {
|
||||
#pkgconfig mysqlclient
|
||||
} $else $if $pkgconfig('mariadb') {
|
||||
#pkgconfig mariadb
|
||||
}
|
||||
```
|
||||
|
||||
### Including C code
|
||||
|
||||
You can also include C code directly in your V module.
|
||||
|
|
|
@ -731,6 +731,7 @@ pub:
|
|||
body_pos token.Position
|
||||
comments []Comment
|
||||
pub mut:
|
||||
pkg_exist bool
|
||||
stmts []Stmt
|
||||
scope &Scope
|
||||
}
|
||||
|
@ -1439,6 +1440,8 @@ pub:
|
|||
//
|
||||
is_env bool
|
||||
env_pos token.Position
|
||||
//
|
||||
is_pkgconfig bool
|
||||
pub mut:
|
||||
sym TypeSymbol
|
||||
result_type Type
|
||||
|
|
|
@ -6185,6 +6185,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
|||
if !node.has_else || i < node.branches.len - 1 {
|
||||
if node.is_comptime {
|
||||
should_skip = c.comp_if_branch(branch.cond, branch.pos)
|
||||
node.branches[i].pkg_exist = !should_skip
|
||||
} else {
|
||||
// check condition type is boolean
|
||||
c.expected_type = ast.bool_type
|
||||
|
@ -6514,6 +6515,15 @@ fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool {
|
|||
return !(expr as ast.BoolLiteral).val
|
||||
}
|
||||
}
|
||||
ast.ComptimeCall {
|
||||
if cond.is_pkgconfig {
|
||||
mut m := pkgconfig.main([cond.args_var]) or {
|
||||
c.error(err.msg, cond.pos)
|
||||
return true
|
||||
}
|
||||
m.run() or { return true }
|
||||
}
|
||||
}
|
||||
else {
|
||||
c.error('invalid `\$if` condition', pos)
|
||||
}
|
||||
|
|
|
@ -1764,6 +1764,8 @@ pub fn (mut f Fmt) comptime_call(node ast.ComptimeCall) {
|
|||
f.write("\$embed_file('$node.embed_file.rpath')")
|
||||
} else if node.is_env {
|
||||
f.write("\$env('$node.args_var')")
|
||||
} else if node.is_pkgconfig {
|
||||
f.write("\$pkgconfig('$node.args_var')")
|
||||
} else {
|
||||
inner_args := if node.args_var != '' {
|
||||
node.args_var
|
||||
|
|
|
@ -232,7 +232,7 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
|||
} else {
|
||||
g.write('#elif ')
|
||||
}
|
||||
comp_if_stmts_skip = !g.comp_if_cond(branch.cond)
|
||||
comp_if_stmts_skip = !g.comp_if_cond(branch.cond, branch.pkg_exist)
|
||||
g.writeln('')
|
||||
}
|
||||
expr_str := g.out.last_n(g.out.len - start_pos).trim_space()
|
||||
|
@ -280,7 +280,7 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
|||
// returning `false` means the statements inside the $if can be skipped
|
||||
*/
|
||||
// returns the value of the bool comptime expression
|
||||
fn (mut g Gen) comp_if_cond(cond ast.Expr) bool {
|
||||
fn (mut g Gen) comp_if_cond(cond ast.Expr, pkg_exist bool) bool {
|
||||
match cond {
|
||||
ast.BoolLiteral {
|
||||
g.expr(cond)
|
||||
|
@ -288,13 +288,13 @@ fn (mut g Gen) comp_if_cond(cond ast.Expr) bool {
|
|||
}
|
||||
ast.ParExpr {
|
||||
g.write('(')
|
||||
is_cond_true := g.comp_if_cond(cond.expr)
|
||||
is_cond_true := g.comp_if_cond(cond.expr, pkg_exist)
|
||||
g.write(')')
|
||||
return is_cond_true
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
g.write(cond.op.str())
|
||||
return g.comp_if_cond(cond.right)
|
||||
return g.comp_if_cond(cond.right, pkg_exist)
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
ifdef := g.comp_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
|
||||
|
@ -307,9 +307,9 @@ fn (mut g Gen) comp_if_cond(cond ast.Expr) bool {
|
|||
ast.InfixExpr {
|
||||
match cond.op {
|
||||
.and, .logical_or {
|
||||
l := g.comp_if_cond(cond.left)
|
||||
l := g.comp_if_cond(cond.left, pkg_exist)
|
||||
g.write(' $cond.op ')
|
||||
r := g.comp_if_cond(cond.right)
|
||||
r := g.comp_if_cond(cond.right, pkg_exist)
|
||||
return if cond.op == .and { l && r } else { l || r }
|
||||
}
|
||||
.key_is, .not_is {
|
||||
|
@ -381,6 +381,10 @@ fn (mut g Gen) comp_if_cond(cond ast.Expr) bool {
|
|||
g.write('defined($ifdef)')
|
||||
return true
|
||||
}
|
||||
ast.ComptimeCall {
|
||||
g.write('$pkg_exist')
|
||||
return true
|
||||
}
|
||||
else {
|
||||
// should be unreachable, but just in case
|
||||
g.write('1')
|
||||
|
|
|
@ -9,7 +9,7 @@ import v.pref
|
|||
import v.token
|
||||
|
||||
const (
|
||||
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file']
|
||||
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig']
|
||||
)
|
||||
|
||||
// // #include, #flag, #v
|
||||
|
@ -45,7 +45,7 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
|
|||
}
|
||||
p.check(.dollar)
|
||||
start_pos := p.prev_tok.position()
|
||||
error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()` and `\$vweb.html()` comptime functions are supported right now'
|
||||
error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()` and `\$vweb.html()` comptime functions are supported right now'
|
||||
if p.peek_tok.kind == .dot {
|
||||
n := p.check_name() // skip `vweb.html()` TODO
|
||||
if n != 'vweb' {
|
||||
|
@ -62,9 +62,9 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
|
|||
is_embed_file := n == 'embed_file'
|
||||
is_html := n == 'html'
|
||||
// $env('ENV_VAR_NAME')
|
||||
if n == 'env' {
|
||||
p.check(.lpar)
|
||||
spos := p.tok.position()
|
||||
if n == 'env' {
|
||||
s := p.tok.lit
|
||||
p.check(.string)
|
||||
p.check(.rpar)
|
||||
|
@ -77,8 +77,19 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
|
|||
pos: spos.extend(p.prev_tok.position())
|
||||
}
|
||||
}
|
||||
p.check(.lpar)
|
||||
spos := p.tok.position()
|
||||
if n == 'pkgconfig' {
|
||||
s := p.tok.lit
|
||||
p.check(.string)
|
||||
p.check(.rpar)
|
||||
return ast.ComptimeCall{
|
||||
scope: 0
|
||||
method_name: n
|
||||
args_var: s
|
||||
is_pkgconfig: true
|
||||
env_pos: spos
|
||||
pos: spos.extend(p.prev_tok.position())
|
||||
}
|
||||
}
|
||||
literal_string_param := if is_html { '' } else { p.tok.lit }
|
||||
path_of_literal_string_param := literal_string_param.replace('/', os.path_separator)
|
||||
if !is_html {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
fn test_comptime_pkgconfig() {
|
||||
$if $pkgconfig('mysqlclient') {
|
||||
assert true
|
||||
return
|
||||
} $else {
|
||||
assert true
|
||||
return
|
||||
}
|
||||
assert false
|
||||
}
|
Loading…
Reference in New Issue