From 2b4831c8d65f1d8699c55733f231465bff846aa3 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 19 Apr 2026 23:41:39 +0300 Subject: [PATCH] all: more fixes --- vlib/net/jsonrpc/server_test.v | 16 +++---- .../mbedtls/mbedtls_tcc_arm64_compiles_test.v | 4 +- vlib/os/file.c.v | 2 +- vlib/v/builder/cc.v | 45 ++++++++++++++----- vlib/v/cflag/cflags.v | 3 +- vlib/v/gen/c/struct.v | 11 +++++ vlib/v/gen/c/utils.v | 24 ++++++++-- vlib/v/pref/pref.v | 1 + 8 files changed, 81 insertions(+), 25 deletions(-) diff --git a/vlib/net/jsonrpc/server_test.v b/vlib/net/jsonrpc/server_test.v index 722630719..131dc57fe 100644 --- a/vlib/net/jsonrpc/server_test.v +++ b/vlib/net/jsonrpc/server_test.v @@ -8,8 +8,8 @@ mut: } fn (mut s StringRW) read(mut buf []u8) !int { - len := s.buf.len - buf = s.buf.str().bytes() + data := s.buf.str().bytes() + len := copy(mut buf, data) s.buf = strings.new_builder(4096) return len } @@ -45,12 +45,12 @@ fn test_server_request_response() { key: 'foo' value: 'bar' } - stream.write(new_request(method, params, id).encode().bytes())! + srv.stream.write(new_request(method, params, id).encode().bytes())! srv.respond()! mut enc_resp := []u8{len: 4096} - stream.read(mut enc_resp)! + srv.stream.read(mut enc_resp)! resp := decode_response(enc_resp.bytestr())! assert resp.jsonrpc == version @@ -74,12 +74,12 @@ fn test_server_router_request_response() { key: 'foo' value: 'bar' } - stream.write(new_request(method, params, id).encode().bytes())! + srv.stream.write(new_request(method, params, id).encode().bytes())! srv.respond()! mut enc_resp := []u8{len: 4096} - stream.read(mut enc_resp)! + srv.stream.read(mut enc_resp)! mut resp := decode_response(enc_resp.bytestr())! assert resp.jsonrpc == version @@ -87,12 +87,12 @@ fn test_server_router_request_response() { assert resp.error == ResponseError{} assert resp.id == id - stream.write(new_request('unknown', params, id).encode().bytes())! + srv.stream.write(new_request('unknown', params, id).encode().bytes())! srv.respond()! enc_resp = []u8{len: 4096} - stream.read(mut enc_resp)! + srv.stream.read(mut enc_resp)! resp = decode_response(enc_resp.bytestr())! assert resp.jsonrpc == version diff --git a/vlib/net/mbedtls/mbedtls_tcc_arm64_compiles_test.v b/vlib/net/mbedtls/mbedtls_tcc_arm64_compiles_test.v index 6f7c667fb..b33078d56 100644 --- a/vlib/net/mbedtls/mbedtls_tcc_arm64_compiles_test.v +++ b/vlib/net/mbedtls/mbedtls_tcc_arm64_compiles_test.v @@ -12,10 +12,12 @@ fn test_mbedtls_compiles_with_tcc_on_arm64_macos() { defer { os.rmdir_all(workdir) or {} } + vcache := os.join_path(workdir, 'vcache') + os.mkdir_all(vcache) or { panic(err) } src := os.join_path(workdir, 'main.v') out := os.join_path(workdir, 'main') os.write_file(src, 'import net.mbedtls as _\n\nfn main() {}\n') or { panic(err) } - cmd := '${os.quoted_path(vexe)} -nocache -cc tcc -no-retry-compilation -o ${os.quoted_path(out)} ${os.quoted_path(src)}' + cmd := 'env VCACHE=${os.quoted_path(vcache)} ${os.quoted_path(vexe)} -nocache -cc tcc -gc none -no-retry-compilation -o ${os.quoted_path(out)} ${os.quoted_path(src)}' res := os.execute(cmd) if res.exit_code != 0 { panic('command failed:\n${cmd}\n${res.output}') diff --git a/vlib/os/file.c.v b/vlib/os/file.c.v index 306a494d9..8311ab87d 100644 --- a/vlib/os/file.c.v +++ b/vlib/os/file.c.v @@ -660,7 +660,7 @@ pub fn (mut f File) seek(pos i64, mode SeekMode) ! { $if windows { res = C._fseeki64(f.cfile, pos, whence) } $else { - res = C.fseeko(f.cfile, pos, whence) + res = C.fseek(f.cfile, pos, whence) } } $if x32 { diff --git a/vlib/v/builder/cc.v b/vlib/v/builder/cc.v index 81d89277e..9c6f56524 100644 --- a/vlib/v/builder/cc.v +++ b/vlib/v/builder/cc.v @@ -1745,18 +1745,22 @@ fn c_project_source_from_object_path(obj_path string) ?string { return none } +fn (v &Builder) should_compile_bundled_thirdparty_object_from_source(obj_path string, source_file string, source_kind SourceKind) bool { + if source_kind == .unknown { + return false + } + if os.exists(obj_path) && os.file_last_mod_unix(obj_path) < os.file_last_mod_unix(source_file) { + return true + } + return v.ccoptions.cc == .tcc && v.pref.os == .macos +} + fn (mut v Builder) build_thirdparty_obj_file(mod string, path string, moduleflags []cflag.CFlag) { trace_thirdparty_obj_files := 'trace_thirdparty_obj_files' in v.pref.compile_defines obj_path := os.real_path(path) opath := v.pref.cache_manager.mod_postfix_with_key2cpath(mod, '.o', obj_path) - if os.exists(obj_path) { - // Some .o files are distributed with no source - // for example thirdparty\tcc\lib\openlibm.o - // the best we can do for them is just copy them, - // and hope that they work with any compiler... - os.cp(obj_path, opath) or { panic(err) } - return - } + thirdparty_desc_path := v.pref.cache_manager.mod_postfix_with_key2cpath(mod, + '.thirdparty.description.txt', obj_path) mut source_file := c_project_source_from_object_path(obj_path) or { '' } source_kind := if source_file.ends_with('.c') { SourceKind.c @@ -1767,14 +1771,35 @@ fn (mut v Builder) build_thirdparty_obj_file(mod string, path string, moduleflag } else { SourceKind.unknown } + compile_bundled_source := v.should_compile_bundled_thirdparty_object_from_source(obj_path, + source_file, source_kind) + if os.exists(obj_path) && !compile_bundled_source { + // Some .o files are distributed with no source + // for example thirdparty\tcc\lib\openlibm.o + // the best we can do for them is just copy them, + // and hope that they work with any compiler... + os.cp(obj_path, opath) or { panic(err) } + return + } if source_kind == .unknown { base := obj_path.all_before_last('.') eprintln('> File not found: ${base}{.c,.cpp,.S}') verror('build_thirdparty_obj_file only support .c, .cpp, and .S source file.') } - mut rebuild_reason_message := '${os.quoted_path(obj_path)} not found, building it in ${os.quoted_path(opath)} ...' + bundled_object_is_stale := os.exists(obj_path) + && os.file_last_mod_unix(obj_path) < os.file_last_mod_unix(source_file) + cached_object_was_built_from_source := os.exists(thirdparty_desc_path) + mut rebuild_reason_message := if bundled_object_is_stale { + '${os.quoted_path(obj_path)} is older than ${os.quoted_path(source_file)}, rebuilding it in ${os.quoted_path(opath)} ...' + } else if compile_bundled_source { + '${os.quoted_path(obj_path)} is bundled for a different object format; rebuilding it in ${os.quoted_path(opath)} from ${os.quoted_path(source_file)} ...' + } else { + '${os.quoted_path(obj_path)} not found, building it in ${os.quoted_path(opath)} ...' + } if os.exists(opath) { - if os.file_last_mod_unix(opath) < os.file_last_mod_unix(source_file) { + if compile_bundled_source && !cached_object_was_built_from_source { + rebuild_reason_message = '${os.quoted_path(opath)} was copied from a bundled object, rebuilding it from ${os.quoted_path(source_file)} ...' + } else if os.file_last_mod_unix(opath) < os.file_last_mod_unix(source_file) { rebuild_reason_message = '${os.quoted_path(opath)} is older than ${os.quoted_path(source_file)}, rebuilding ...' } else { return diff --git a/vlib/v/cflag/cflags.v b/vlib/v/cflag/cflags.v index 09649fd55..5b2128a8c 100644 --- a/vlib/v/cflag/cflags.v +++ b/vlib/v/cflag/cflags.v @@ -148,7 +148,8 @@ pub fn (cflags []CFlag) defines_others_libs() ([]string, []string, []string) { libs << copt continue } - if copt.ends_with('.a') { + if copt.ends_with('.a') || copt.ends_with('.so') || copt.ends_with('.dylib') + || copt.ends_with('.dll') || copt.ends_with('.lib') { libs << '"${copt}"' continue } diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index fdab6c8e0..c3fcd0cbe 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -375,7 +375,10 @@ fn (mut g Gen) struct_init(node ast.StructInit) { } } if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 { + old_inside_return := g.inside_return + g.inside_return = false resolved_sfield_typ := g.resolved_expr_type(ast.Expr(sfield.expr), sfield.typ) + g.inside_return = old_inside_return if resolved_sfield_typ != 0 { sfield.typ = g.unwrap_generic(g.recheck_concrete_type(resolved_sfield_typ)) } @@ -578,8 +581,11 @@ fn (mut g Gen) direct_heap_struct_init(node ast.StructInit, styp string, info as } } if g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 { + old_inside_return := g.inside_return + g.inside_return = false resolved_field_typ := g.resolved_expr_type(ast.Expr(resolved_field.expr), resolved_field.typ) + g.inside_return = old_inside_return if resolved_field_typ != 0 { resolved_field.typ = g.unwrap_generic(g.recheck_concrete_type(resolved_field_typ)) } @@ -999,6 +1005,11 @@ fn (mut g Gen) struct_init_ptr_field(target string, sfield ast.StructInitField, } fn (mut g Gen) struct_init_field_value(sfield ast.StructInitField) { + old_inside_return := g.inside_return + g.inside_return = false + defer { + g.inside_return = old_inside_return + } field_type_sym := g.table.sym(sfield.typ) mut cloned := false if g.is_autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] { diff --git a/vlib/v/gen/c/utils.v b/vlib/v/gen/c/utils.v index 404951d7c..1392911d3 100644 --- a/vlib/v/gen/c/utils.v +++ b/vlib/v/gen/c/utils.v @@ -120,6 +120,14 @@ fn (mut g Gen) infer_branch_expr_type(stmts []ast.Stmt) ast.Type { } fn (mut g Gen) infer_if_expr_type(node ast.IfExpr) ast.Type { + if g.inside_return && g.inside_struct_init { + for branch in node.branches { + branch_typ := g.infer_branch_expr_type(branch.stmts) + if branch_typ != 0 && branch_typ != ast.void_type { + return branch_typ + } + } + } if node.typ != 0 && node.typ != ast.void_type { resolved := g.unwrap_generic(g.recheck_concrete_type(node.typ)) // In generic functions, node.typ may have been mutated by the checker @@ -128,8 +136,8 @@ fn (mut g Gen) infer_if_expr_type(node ast.IfExpr) ast.Type { // return type instead, which correctly resolves via cur_concrete_types. // Only apply this override when the function's return type is actually // generic — otherwise the if-expression type is concrete and correct. - if g.inside_return && g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 - && g.cur_fn.return_type.has_flag(.generic) { + if g.inside_return && !g.inside_struct_init && g.cur_fn != unsafe { nil } + && g.cur_concrete_types.len > 0 && g.cur_fn.return_type.has_flag(.generic) { fn_ret := g.unwrap_generic(g.recheck_concrete_type(g.cur_fn.return_type)) if fn_ret != 0 && fn_ret != ast.void_type { if node.typ.has_flag(.result) && !fn_ret.has_flag(.result) { @@ -152,6 +160,14 @@ fn (mut g Gen) infer_if_expr_type(node ast.IfExpr) ast.Type { } fn (mut g Gen) infer_match_expr_type(node ast.MatchExpr) ast.Type { + if g.inside_return && g.inside_struct_init { + for branch in node.branches { + branch_typ := g.infer_branch_expr_type(branch.stmts) + if branch_typ != 0 && branch_typ != ast.void_type { + return branch_typ + } + } + } if node.return_type != 0 && node.return_type != ast.void_type { resolved := g.unwrap_generic(g.recheck_concrete_type(node.return_type)) // In generic functions, node.return_type may have been mutated by the checker @@ -160,8 +176,8 @@ fn (mut g Gen) infer_match_expr_type(node ast.MatchExpr) ast.Type { // instead, which correctly resolves via cur_concrete_types. // Only apply this override when the function's return type is actually // generic — otherwise the match expression type is concrete and correct. - if g.inside_return && g.cur_fn != unsafe { nil } && g.cur_concrete_types.len > 0 - && g.cur_fn.return_type.has_flag(.generic) { + if g.inside_return && !g.inside_struct_init && g.cur_fn != unsafe { nil } + && g.cur_concrete_types.len > 0 && g.cur_fn.return_type.has_flag(.generic) { fn_ret := g.unwrap_generic(g.recheck_concrete_type(g.cur_fn.return_type)) if fn_ret != 0 && fn_ret != ast.void_type { // Preserve option/result flags from the match's return_type diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index e04c33a39..cf09d502a 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -756,6 +756,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin } '-no-retry-compilation' { res.retry_compilation = false + res.build_options << arg } '-musl' { res.is_musl = true -- 2.39.5