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
|
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.
|
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
|
### Including C code
|
||||||
|
|
||||||
You can also include C code directly in your V module.
|
You can also include C code directly in your V module.
|
||||||
|
|
|
@ -731,8 +731,9 @@ pub:
|
||||||
body_pos token.Position
|
body_pos token.Position
|
||||||
comments []Comment
|
comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
stmts []Stmt
|
pkg_exist bool
|
||||||
scope &Scope
|
stmts []Stmt
|
||||||
|
scope &Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UnsafeExpr {
|
pub struct UnsafeExpr {
|
||||||
|
@ -1439,6 +1440,8 @@ pub:
|
||||||
//
|
//
|
||||||
is_env bool
|
is_env bool
|
||||||
env_pos token.Position
|
env_pos token.Position
|
||||||
|
//
|
||||||
|
is_pkgconfig bool
|
||||||
pub mut:
|
pub mut:
|
||||||
sym TypeSymbol
|
sym TypeSymbol
|
||||||
result_type Type
|
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.has_else || i < node.branches.len - 1 {
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
should_skip = c.comp_if_branch(branch.cond, branch.pos)
|
should_skip = c.comp_if_branch(branch.cond, branch.pos)
|
||||||
|
node.branches[i].pkg_exist = !should_skip
|
||||||
} else {
|
} else {
|
||||||
// check condition type is boolean
|
// check condition type is boolean
|
||||||
c.expected_type = ast.bool_type
|
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
|
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 {
|
else {
|
||||||
c.error('invalid `\$if` condition', pos)
|
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')")
|
f.write("\$embed_file('$node.embed_file.rpath')")
|
||||||
} else if node.is_env {
|
} else if node.is_env {
|
||||||
f.write("\$env('$node.args_var')")
|
f.write("\$env('$node.args_var')")
|
||||||
|
} else if node.is_pkgconfig {
|
||||||
|
f.write("\$pkgconfig('$node.args_var')")
|
||||||
} else {
|
} else {
|
||||||
inner_args := if node.args_var != '' {
|
inner_args := if node.args_var != '' {
|
||||||
node.args_var
|
node.args_var
|
||||||
|
|
|
@ -232,7 +232,7 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
||||||
} else {
|
} else {
|
||||||
g.write('#elif ')
|
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('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
expr_str := g.out.last_n(g.out.len - start_pos).trim_space()
|
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
|
// returning `false` means the statements inside the $if can be skipped
|
||||||
*/
|
*/
|
||||||
// returns the value of the bool comptime expression
|
// 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 {
|
match cond {
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
g.expr(cond)
|
g.expr(cond)
|
||||||
|
@ -288,13 +288,13 @@ fn (mut g Gen) comp_if_cond(cond ast.Expr) bool {
|
||||||
}
|
}
|
||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
is_cond_true := g.comp_if_cond(cond.expr)
|
is_cond_true := g.comp_if_cond(cond.expr, pkg_exist)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
return is_cond_true
|
return is_cond_true
|
||||||
}
|
}
|
||||||
ast.PrefixExpr {
|
ast.PrefixExpr {
|
||||||
g.write(cond.op.str())
|
g.write(cond.op.str())
|
||||||
return g.comp_if_cond(cond.right)
|
return g.comp_if_cond(cond.right, pkg_exist)
|
||||||
}
|
}
|
||||||
ast.PostfixExpr {
|
ast.PostfixExpr {
|
||||||
ifdef := g.comp_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
|
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 {
|
ast.InfixExpr {
|
||||||
match cond.op {
|
match cond.op {
|
||||||
.and, .logical_or {
|
.and, .logical_or {
|
||||||
l := g.comp_if_cond(cond.left)
|
l := g.comp_if_cond(cond.left, pkg_exist)
|
||||||
g.write(' $cond.op ')
|
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 }
|
return if cond.op == .and { l && r } else { l || r }
|
||||||
}
|
}
|
||||||
.key_is, .not_is {
|
.key_is, .not_is {
|
||||||
|
@ -381,6 +381,10 @@ fn (mut g Gen) comp_if_cond(cond ast.Expr) bool {
|
||||||
g.write('defined($ifdef)')
|
g.write('defined($ifdef)')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
ast.ComptimeCall {
|
||||||
|
g.write('$pkg_exist')
|
||||||
|
return true
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// should be unreachable, but just in case
|
// should be unreachable, but just in case
|
||||||
g.write('1')
|
g.write('1')
|
||||||
|
|
|
@ -9,7 +9,7 @@ import v.pref
|
||||||
import v.token
|
import v.token
|
||||||
|
|
||||||
const (
|
const (
|
||||||
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file']
|
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig']
|
||||||
)
|
)
|
||||||
|
|
||||||
// // #include, #flag, #v
|
// // #include, #flag, #v
|
||||||
|
@ -45,7 +45,7 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
|
||||||
}
|
}
|
||||||
p.check(.dollar)
|
p.check(.dollar)
|
||||||
start_pos := p.prev_tok.position()
|
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 {
|
if p.peek_tok.kind == .dot {
|
||||||
n := p.check_name() // skip `vweb.html()` TODO
|
n := p.check_name() // skip `vweb.html()` TODO
|
||||||
if n != 'vweb' {
|
if n != 'vweb' {
|
||||||
|
@ -62,9 +62,9 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
|
||||||
is_embed_file := n == 'embed_file'
|
is_embed_file := n == 'embed_file'
|
||||||
is_html := n == 'html'
|
is_html := n == 'html'
|
||||||
// $env('ENV_VAR_NAME')
|
// $env('ENV_VAR_NAME')
|
||||||
|
p.check(.lpar)
|
||||||
|
spos := p.tok.position()
|
||||||
if n == 'env' {
|
if n == 'env' {
|
||||||
p.check(.lpar)
|
|
||||||
spos := p.tok.position()
|
|
||||||
s := p.tok.lit
|
s := p.tok.lit
|
||||||
p.check(.string)
|
p.check(.string)
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
|
@ -77,8 +77,19 @@ fn (mut p Parser) comp_call() ast.ComptimeCall {
|
||||||
pos: spos.extend(p.prev_tok.position())
|
pos: spos.extend(p.prev_tok.position())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.check(.lpar)
|
if n == 'pkgconfig' {
|
||||||
spos := p.tok.position()
|
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 }
|
literal_string_param := if is_html { '' } else { p.tok.lit }
|
||||||
path_of_literal_string_param := literal_string_param.replace('/', os.path_separator)
|
path_of_literal_string_param := literal_string_param.replace('/', os.path_separator)
|
||||||
if !is_html {
|
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