From 719c3b3221faeae337aa8c25c80c25987395f873 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 21 Feb 2025 13:10:12 +0200 Subject: [PATCH] v.cflag: support `#flag $when_first_existing(libABC.a, /some/path/libABC.a, ...)`, without panicing (unlike `#flag $first_existing(...)`) --- vlib/v/cflag/cflags.v | 52 +++++++++++++++++++++++++++------------- vlib/v/parser/comptime.v | 3 ++- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/vlib/v/cflag/cflags.v b/vlib/v/cflag/cflags.v index 82ce4513c88242..b9a275ed2d3c01 100644 --- a/vlib/v/cflag/cflags.v +++ b/vlib/v/cflag/cflags.v @@ -22,28 +22,46 @@ pub fn (c &CFlag) str() string { } const fexisting_literal = r'$first_existing' +const wexisting_literal = r'$when_first_existing' + +fn find_first_existing_path(remainder string, literal string) (bool, string, int, []string) { + sparams := remainder[literal.len + 1..].all_before(')') + delta_i := sparams.len + literal.len + 1 + svalues := sparams.replace(',', '\n').split_into_lines().map(it.trim('\t \'"')) + for spath in svalues { + if os.exists(spath) { + return true, spath, delta_i, []string{} + } + } + return false, '', delta_i, svalues +} // expand the flag value -pub fn (cf &CFlag) eval() string { +pub fn (cf &CFlag) eval() ?string { mut value_builder := strings.new_builder(10 * cf.value.len) cflag_eval_outer_loop: for i := 0; i < cf.value.len; i++ { x := cf.value[i] if x == `$` { remainder := cf.value[i..] if remainder.starts_with(fexisting_literal) { - sparams := remainder[fexisting_literal.len + 1..].all_before(')') - i += sparams.len + fexisting_literal.len + 1 - svalues := sparams.replace(',', '\n').split_into_lines().map(it.trim('\t \'"')) - // mut found_spath := '' - for spath in svalues { - if os.exists(spath) { - // found_spath = spath - value_builder.write_string(spath) - continue cflag_eval_outer_loop - } + found, spath, delta_i, svalues := find_first_existing_path(remainder, + fexisting_literal) + if found { + value_builder.write_string(spath) + i += delta_i + continue } panic('>> error: none of the paths ${svalues} exist') - continue + } + if remainder.starts_with(wexisting_literal) { + found, spath, delta_i, svalues := find_first_existing_path(remainder, + wexisting_literal) + if found { + value_builder.write_string(spath) + i += delta_i + continue + } + return none } } value_builder.write_string(x.ascii_str()) @@ -52,12 +70,12 @@ pub fn (cf &CFlag) eval() string { } // format flag -pub fn (cf &CFlag) format() string { +pub fn (cf &CFlag) format() ?string { mut value := '' if cf.cached != '' { value = cf.cached } else { - value = cf.eval() + value = cf.eval()? } if cf.name in ['-l', '-Wa', '-Wl', '-Wp'] && value != '' { return '${cf.name}${value}'.trim_space() @@ -97,7 +115,7 @@ pub fn (cflags []CFlag) c_options_without_object_files() []string { if flag.value.ends_with('.o') || flag.value.ends_with('.obj') { continue } - args << flag.format() + args << flag.format() or { continue } } return args } @@ -108,10 +126,10 @@ pub fn (cflags []CFlag) c_options_only_object_files() []string { // TODO figure out a better way to copy cross compiling flags to the linker if flag.value.ends_with('.o') || flag.value.ends_with('.obj') || (flag.name == '-l' && flag.value == 'pq') { - args << flag.format() + args << flag.format() or { continue } } } - return args + return args.filter(it != '') } pub fn (cflags []CFlag) defines_others_libs() ([]string, []string, []string) { diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 639ae728a6ee65..63989db83038be 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -112,6 +112,8 @@ fn (mut p Parser) hash() ast.HashStmt { } } +const error_msg = 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()`, `\$compile_warn()`, `\$d()` and `\$res()` comptime functions are supported right now' + fn (mut p Parser) comptime_call() ast.ComptimeCall { err_node := ast.ComptimeCall{ scope: unsafe { nil } @@ -119,7 +121,6 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { start_pos := p.tok.pos() p.check(.dollar) mut is_veb := false - error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()`, `\$compile_warn()`, `\$d()` and `\$res()` comptime functions are supported right now' if p.peek_tok.kind == .dot { name := p.check_name() // skip `vweb.html()` TODO if name != 'vweb' && name != 'veb' {