From 79f93e6ed8ff70b8d302b9b66c2c5f5aa5fa4234 Mon Sep 17 00:00:00 2001 From: Spydr <58859306+Spydr06@users.noreply.github.com> Date: Wed, 4 Oct 2023 15:42:15 +0200 Subject: [PATCH] native, builtin, ast: handle `ast.HashStmt` correctly and reduce macro usage in `builtin` (#19498) --- vlib/builtin/backtraces.c.v | 4 +- vlib/builtin/backtraces_nix.c.v | 5 +- vlib/builtin/backtraces_windows.c.v | 2 +- vlib/builtin/builtin.c.v | 8 +- vlib/builtin/builtin_windows.c.v | 29 ++++-- vlib/builtin/cfns.c.v | 2 +- vlib/builtin/float.c.v | 37 ++++++-- vlib/clipboard/clipboard_windows.c.v | 6 +- vlib/os/os_windows.c.v | 6 +- vlib/v/eval/eval.v | 57 +++++++----- vlib/v/gen/native/amd64.v | 6 +- vlib/v/gen/native/comptime.v | 16 +++- vlib/v/gen/native/elf.v | 6 +- vlib/v/gen/native/expr.v | 10 +- vlib/v/gen/native/gen.v | 132 ++++++++++++++++----------- vlib/v/gen/native/pe.v | 9 +- vlib/v/gen/native/readdll.v | 12 ++- vlib/v/gen/native/stmt.v | 60 +++++++++--- 18 files changed, 277 insertions(+), 130 deletions(-) diff --git a/vlib/builtin/backtraces.c.v b/vlib/builtin/backtraces.c.v index 3e07eb702b301f..8b85761f5ee74d 100644 --- a/vlib/builtin/backtraces.c.v +++ b/vlib/builtin/backtraces.c.v @@ -11,7 +11,9 @@ pub fn print_backtrace() { $if freestanding { println(bare_backtrace()) } $else { - $if tinyc { + $if native { + // TODO: native backtrace solution + } $else $if tinyc { C.tcc_backtrace(c'Backtrace') } $else { // NOTE: TCC doesn't have the unwind library diff --git a/vlib/builtin/backtraces_nix.c.v b/vlib/builtin/backtraces_nix.c.v index b4e29501e3fcd5..322562a3e68173 100644 --- a/vlib/builtin/backtraces_nix.c.v +++ b/vlib/builtin/backtraces_nix.c.v @@ -46,7 +46,10 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool { eprintln('Some libc implementations like musl simply do not provide it.') return false } - $if no_backtrace ? { + $if native { + eprintln('native backend does not support backtraces yet.') + return false + } $else $if no_backtrace ? { return false } $else { $if linux && !freestanding { diff --git a/vlib/builtin/backtraces_windows.c.v b/vlib/builtin/backtraces_windows.c.v index 94ed18921af56b..98f7218d62f7da 100644 --- a/vlib/builtin/backtraces_windows.c.v +++ b/vlib/builtin/backtraces_windows.c.v @@ -152,7 +152,7 @@ fn print_backtrace_skipping_top_frames_mingw(skipframes int) bool { fn C.tcc_backtrace(fmt &char) int fn print_backtrace_skipping_top_frames_tcc(skipframes int) bool { - $if tinyc { + $if tinyc && !native { $if no_backtrace ? { eprintln('backtraces are disabled') return false diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index b217e32af764cc..9388e30ea0a554 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -56,7 +56,9 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { eprintln(' file: ${file}:${line_no}') eprintln(' v hash: ${vcommithash()}') eprintln('=========================================') - $if exit_after_panic_message ? { + $if native { + C.exit(1) // TODO: native backtraces + } $else $if exit_after_panic_message ? { C.exit(1) } $else $if no_backtrace ? { C.exit(1) @@ -107,7 +109,9 @@ pub fn panic(s string) { eprint('V panic: ') eprintln(s) eprintln('v hash: ${vcommithash()}') - $if exit_after_panic_message ? { + $if native { + C.exit(1) // TODO: native backtraces + } $else $if exit_after_panic_message ? { C.exit(1) } $else $if no_backtrace ? { C.exit(1) diff --git a/vlib/builtin/builtin_windows.c.v b/vlib/builtin/builtin_windows.c.v index 1b5d4686799b4b..906cea271db004 100644 --- a/vlib/builtin/builtin_windows.c.v +++ b/vlib/builtin/builtin_windows.c.v @@ -7,7 +7,7 @@ module builtin // g_original_codepage - used to restore the original windows console code page when exiting __global g_original_codepage = u32(0) -// utf8 to stdout needs C.SetConsoleOutputCP(C.CP_UTF8) +// utf8 to stdout needs C.SetConsoleOutputCP(cp_utf8) fn C.GetConsoleOutputCP() u32 fn C.SetConsoleOutputCP(wCodePageID u32) bool @@ -23,13 +23,21 @@ fn is_terminal(fd int) int { return int(mode) } +const ( + std_output_handle = -11 + std_error_handle = -12 + enable_processed_output = 1 + enable_wrap_at_eol_output = 2 + evable_virtual_terminal_processing = 4 +) + fn builtin_init() { g_original_codepage = C.GetConsoleOutputCP() - C.SetConsoleOutputCP(C.CP_UTF8) + C.SetConsoleOutputCP(cp_utf8) C.atexit(restore_codepage) if is_terminal(1) > 0 { - C.SetConsoleMode(C.GetStdHandle(C.STD_OUTPUT_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing - C.SetConsoleMode(C.GetStdHandle(C.STD_ERROR_HANDLE), C.ENABLE_PROCESSED_OUTPUT | C.ENABLE_WRAP_AT_EOL_OUTPUT | 0x0004) // enable_virtual_terminal_processing + C.SetConsoleMode(C.GetStdHandle(std_output_handle), enable_processed_output | enable_wrap_at_eol_output | evable_virtual_terminal_processing) + C.SetConsoleMode(C.GetStdHandle(std_error_handle), enable_processed_output | enable_wrap_at_eol_output | evable_virtual_terminal_processing) unsafe { C.setbuf(C.stdout, 0) C.setbuf(C.stderr, 0) @@ -110,15 +118,24 @@ fn break_if_debugger_attached() { } } +const ( + format_message_allocate_buffer = 0x00000100 + format_message_argument_array = 0x00002000 + format_message_from_hmodule = 0x00000800 + format_message_from_string = 0x00000400 + format_message_from_system = 0x00001000 + format_message_ignore_inserts = 0x00000200 +) + // return an error message generated from WinAPI's `LastError` pub fn winapi_lasterr_str() string { err_msg_id := C.GetLastError() if err_msg_id == 8 { - // handle this case special since `FormatMessage()` might not work anymore + // handle this case special since `FormatMessageW()` might not work anymore return 'insufficient memory' } mut msgbuf := &u16(0) - res := C.FormatMessage(C.FORMAT_MESSAGE_ALLOCATE_BUFFER | C.FORMAT_MESSAGE_FROM_SYSTEM | C.FORMAT_MESSAGE_IGNORE_INSERTS, + res := C.FormatMessageW(format_message_allocate_buffer | format_message_from_system | format_message_ignore_inserts, 0, err_msg_id, 0, voidptr(&msgbuf), 0, 0) err_msg := if res == 0 { 'Win-API error ${err_msg_id}' diff --git a/vlib/builtin/cfns.c.v b/vlib/builtin/cfns.c.v index 11a92bc660bdb4..2177f417c3dbf2 100644 --- a/vlib/builtin/cfns.c.v +++ b/vlib/builtin/cfns.c.v @@ -349,7 +349,7 @@ fn C.FindClose(hFindFile voidptr) // macro fn C.MAKELANGID(lgid voidptr, srtid voidptr) int -fn C.FormatMessage(dwFlags u32, lpSource voidptr, dwMessageId u32, dwLanguageId u32, lpBuffer voidptr, nSize u32, arguments ...voidptr) u32 +fn C.FormatMessageW(dwFlags u32, lpSource voidptr, dwMessageId u32, dwLanguageId u32, lpBuffer voidptr, nSize u32, arguments ...voidptr) u32 fn C.CloseHandle(voidptr) int diff --git a/vlib/builtin/float.c.v b/vlib/builtin/float.c.v index c140759d8ea3b6..87dfd018108c58 100644 --- a/vlib/builtin/float.c.v +++ b/vlib/builtin/float.c.v @@ -6,7 +6,10 @@ module builtin // [if !nofloat] import strconv -#include +$if !native { + #include +} + /* ----------------------------------- ----- f64 to string functions ----- @@ -185,10 +188,18 @@ fn f64_min(a f64, b f64) f64 { pub fn (a f32) eq_epsilon(b f32) bool { hi := f32_max(f32_abs(a), f32_abs(b)) delta := f32_abs(a - b) - if hi > f32(1.0) { - return delta <= hi * (4 * f32(C.FLT_EPSILON)) - } else { - return (1 / (4 * f32(C.FLT_EPSILON))) * delta <= hi + $if native { + if hi > f32(1.0) { + return delta <= hi * (4 * 1e-5) + } else { + return (1 / (4 * 1e-5)) * delta <= hi + } + } $else { + if hi > f32(1.0) { + return delta <= hi * (4 * f32(C.FLT_EPSILON)) + } else { + return (1 / (4 * f32(C.FLT_EPSILON))) * delta <= hi + } } } @@ -199,9 +210,17 @@ pub fn (a f32) eq_epsilon(b f32) bool { pub fn (a f64) eq_epsilon(b f64) bool { hi := f64_max(f64_abs(a), f64_abs(b)) delta := f64_abs(a - b) - if hi > 1.0 { - return delta <= hi * (4 * f64(C.DBL_EPSILON)) - } else { - return (1 / (4 * f64(C.DBL_EPSILON))) * delta <= hi + $if native { + if hi > 1.0 { + return delta <= hi * (4 * 1e-9) + } else { + return (1 / (4 * 1e-9)) * delta <= hi + } + } $else { + if hi > 1.0 { + return delta <= hi * (4 * f64(C.DBL_EPSILON)) + } else { + return (1 / (4 * f64(C.DBL_EPSILON))) * delta <= hi + } } } diff --git a/vlib/clipboard/clipboard_windows.c.v b/vlib/clipboard/clipboard_windows.c.v index 8f22b27a89cdc7..9eab9f62f99804 100644 --- a/vlib/clipboard/clipboard_windows.c.v +++ b/vlib/clipboard/clipboard_windows.c.v @@ -136,14 +136,16 @@ pub fn (mut cb Clipboard) free() { cb.foo = 0 } +const cp_utf8 = 65001 + // the string.to_wide doesn't work with SetClipboardData, don't know why fn to_wide(text string) C.HGLOBAL { - len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, + len_required := C.MultiByteToWideChar(clipboard.cp_utf8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, C.NULL, 0) buf := C.GlobalAlloc(C.GMEM_MOVEABLE, i64(sizeof(u16)) * len_required) if buf != C.HGLOBAL(C.NULL) { mut locked := &u16(C.GlobalLock(buf)) - C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, + C.MultiByteToWideChar(clipboard.cp_utf8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, locked, len_required) unsafe { locked[len_required - 1] = u16(0) diff --git a/vlib/os/os_windows.c.v b/vlib/os/os_windows.c.v index 4e519422405502..83b1964d0c1cda 100644 --- a/vlib/os/os_windows.c.v +++ b/vlib/os/os_windows.c.v @@ -222,7 +222,7 @@ pub fn get_module_filename(handle HANDLE) !string { return string_from_wide2(buf, sz) } else { - // Must handled with GetLastError and converted by FormatMessage + // Must handled with GetLastError and converted by FormatMessageW return error('Cannot get file name from handle') } } @@ -231,7 +231,7 @@ pub fn get_module_filename(handle HANDLE) !string { panic('this should be unreachable') // TODO remove unreachable after loop } -// Ref - https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagea#parameters +// Ref - https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-FormatMessageWa#parameters const ( format_message_allocate_buffer = 0x00000100 format_message_argument_array = 0x00002000 @@ -261,7 +261,7 @@ fn ptr_win_get_error_msg(code u32) voidptr { if code > u32(os.max_error_code) { return buf } - C.FormatMessage(os.format_message_allocate_buffer | os.format_message_from_system | os.format_message_ignore_inserts, + C.FormatMessageW(os.format_message_allocate_buffer | os.format_message_from_system | os.format_message_ignore_inserts, 0, code, 0, voidptr(&buf), 0, 0) return buf } diff --git a/vlib/v/eval/eval.v b/vlib/v/eval/eval.v index 44cc397511dc30..14ed1f34814c03 100644 --- a/vlib/v/eval/eval.v +++ b/vlib/v/eval/eval.v @@ -194,6 +194,38 @@ pub fn (mut e Eval) register_symbol_stmts(stmts []ast.Stmt, mod string, file str } } +pub fn (mut e Eval) comptime_cond(cond ast.Expr) bool { + match cond { + ast.Ident { + match cond.name { + 'native' { + return false + } + 'windows' { + return e.pref.os == .windows + } + else { + e.error('unknown compile time if') + } + } + } + ast.PrefixExpr { + match cond.op { + .not { + return !e.comptime_cond(cond.right) + } + else { + e.error('unsupported prefix expression') + } + } + } + else { + e.error('unsupported expression') + } + } + return false +} + pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) { match stmt { ast.Module { @@ -226,28 +258,9 @@ pub fn (mut e Eval) register_symbol(stmt ast.Stmt, mod string, file string) { e.error('only comptime ifs are allowed in top level') } for i, branch in x.branches { - mut do_if := false - println('branch:${branch}') - cond := branch.cond - match cond { - ast.Ident { - match cond.name { - 'windows' { - do_if = e.pref.os == .windows - } - else { - e.error('unknown compile time if') - } - } - do_if = do_if || x.branches.len == i + 1 - if do_if { - e.register_symbol_stmts(branch.stmts, mod, file) - break - } - } - else { - e.error('unsupported expression') - } + if e.comptime_cond(branch.cond) || x.branches.len == i + 1 { + e.register_symbol_stmts(branch.stmts, mod, file) + break } } } diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 200964d838e9dd..001f8ca4d045f2 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -2125,9 +2125,9 @@ fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, n } ast.IfExpr { if right.is_comptime { - if stmts := c.g.comptime_conditional(right) { - for j, stmt in stmts { - if j + 1 != stmts.len { + if branch := c.g.comptime_conditional(right) { + for j, stmt in branch.stmts { + if j + 1 != branch.stmts.len { c.g.stmt(stmt) continue } diff --git a/vlib/v/gen/native/comptime.v b/vlib/v/gen/native/comptime.v index 2cf927c6a08639..cc542fb25e9831 100644 --- a/vlib/v/gen/native/comptime.v +++ b/vlib/v/gen/native/comptime.v @@ -9,7 +9,7 @@ fn (mut g Gen) comptime_at(node ast.AtExpr) string { return node.val } -fn (mut g Gen) comptime_conditional(node ast.IfExpr) ?[]ast.Stmt { +fn (mut g Gen) comptime_conditional(node ast.IfExpr) ?ast.IfBranch { if node.branches.len == 0 { return none } @@ -17,13 +17,25 @@ fn (mut g Gen) comptime_conditional(node ast.IfExpr) ?[]ast.Stmt { for i, branch in node.branches { // handle $else branch, which does not have a condition if (node.has_else && i + 1 == node.branches.len) || g.comptime_is_truthy(branch.cond) { - return branch.stmts + return branch } } return none } +fn (mut g Gen) should_emit_hash_stmt(node ast.HashStmt) bool { + if node.ct_conds.len == 0 { + return true + } + + mut emit := true + for cond in node.ct_conds { + emit = emit && g.comptime_is_truthy(cond) + } + return emit +} + fn (mut g Gen) comptime_is_truthy(cond ast.Expr) bool { match cond { ast.BoolLiteral { diff --git a/vlib/v/gen/native/elf.v b/vlib/v/gen/native/elf.v index 1a383fc6ae3b43..2c84e27585891b 100644 --- a/vlib/v/gen/native/elf.v +++ b/vlib/v/gen/native/elf.v @@ -919,7 +919,7 @@ pub fn (mut g Gen) find_o_path(fname string) string { } pub fn (mut g Gen) get_lpaths() string { - lpaths := match g.pref.arch { + mut lpaths := match g.pref.arch { .amd64 { g.prepend_vobjpath(['/usr/lib/x86_64-linux-gnu', '/usr/lib64', '/lib64', '/usr/lib', '/lib']) @@ -932,6 +932,7 @@ pub fn (mut g Gen) get_lpaths() string { ['/dev/null'] } } + lpaths << g.linker_include_paths return lpaths.map('-L${it}').join(' ') } @@ -960,7 +961,7 @@ pub fn (mut g Gen) link_elf_file(obj_file string) { else { '/dev/null' } } - linker_args := [ + mut linker_args := [ '-v', lpaths, '-m ${arch}', @@ -975,6 +976,7 @@ pub fn (mut g Gen) link_elf_file(obj_file string) { '${obj_file}', '-o ${g.out_name}', ] + linker_args << g.linker_libs slinker_args := linker_args.join(' ') mut ld := 'ld' diff --git a/vlib/v/gen/native/expr.v b/vlib/v/gen/native/expr.v index 4683a1eed31506..775f4642bd5625 100644 --- a/vlib/v/gen/native/expr.v +++ b/vlib/v/gen/native/expr.v @@ -156,8 +156,8 @@ fn (mut g Gen) condition(expr ast.Expr, neg bool) int { fn (mut g Gen) if_expr(node ast.IfExpr) { if node.is_comptime { - if stmts := g.comptime_conditional(node) { - g.stmts(stmts) + if branch := g.comptime_conditional(node) { + g.stmts(branch.stmts) } return } @@ -405,9 +405,9 @@ fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) { } ast.IfExpr { if expr.is_comptime { - if stmts := g.comptime_conditional(expr) { - for i, stmt in stmts { - if i + 1 == stmts.len && stmt is ast.ExprStmt { + if branch := g.comptime_conditional(expr) { + for i, stmt in branch.stmts { + if i + 1 == branch.stmts.len && stmt is ast.ExprStmt { g.gen_print_from_expr(stmt.expr, stmt.typ, name) } else { g.stmt(stmt) diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index e8699a60551d3c..6da097266845c4 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -22,40 +22,43 @@ pub struct Gen { pref &pref.Preferences = unsafe { nil } // Preferences shared from V struct files []&ast.File mut: - code_gen CodeGen - table &ast.Table = unsafe { nil } - buf []u8 - sect_header_name_pos int - offset i64 - file_size_pos i64 - main_fn_addr i64 - main_fn_size i64 - start_symbol_addr i64 - code_start_pos i64 // location of the start of the assembly instructions - symbol_table []SymbolTableSection - extern_symbols []string - extern_fn_calls map[i64]string - fn_addr map[string]i64 - var_offset map[string]int // local var stack offset - var_alloc_size map[string]int // local var allocation size - stack_var_pos int - stack_depth int - debug_pos int - current_file &ast.File = unsafe { nil } - errors []errors.Error - warnings []errors.Warning - syms []Symbol - size_pos []int - nlines int - callpatches []CallPatch - strs []String - labels &LabelTable = unsafe { nil } - defer_stmts []ast.DeferStmt - builtins map[Builtin]BuiltinFn - structs []Struct - eval eval.Eval - enum_vals map[string]Enum - return_type ast.Type + code_gen CodeGen + table &ast.Table = unsafe { nil } + buf []u8 + sect_header_name_pos int + offset i64 + file_size_pos i64 + main_fn_addr i64 + main_fn_size i64 + start_symbol_addr i64 + code_start_pos i64 // location of the start of the assembly instructions + symbol_table []SymbolTableSection + extern_symbols []string + linker_include_paths []string + linker_libs []string + extern_fn_calls map[i64]string + fn_addr map[string]i64 + var_offset map[string]int // local var stack offset + var_alloc_size map[string]int // local var allocation size + stack_var_pos int + stack_depth int + debug_pos int + current_file &ast.File = unsafe { nil } + errors []errors.Error + warnings []errors.Warning + syms []Symbol + size_pos []int + nlines int + callpatches []CallPatch + strs []String + labels &LabelTable = unsafe { nil } + defer_stmts []ast.DeferStmt + builtins map[Builtin]BuiltinFn + structs []Struct + eval eval.Eval + enum_vals map[string]Enum + return_type ast.Type + comptime_omitted_branches []ast.IfBranch // elf specific elf_text_header_addr i64 = -1 elf_rela_section Section @@ -387,30 +390,55 @@ pub fn (mut g Gen) typ(a int) &ast.TypeSymbol { return g.table.type_symbols[a] } -pub fn (mut g Gen) ast_has_external_functions() bool { - for file in g.files { - walker.inspect(file, unsafe { &mut g }, fn (node &ast.Node, data voidptr) bool { - if node is ast.Expr && (node as ast.Expr) is ast.CallExpr - && ((node as ast.Expr) as ast.CallExpr).language != .v { - call := node as ast.CallExpr - unsafe { - mut g := &Gen(data) - if call.name !in g.extern_symbols { - g.extern_symbols << call.name - } - } - return true +fn node_fetch_external_deps(node &ast.Node, data voidptr) bool { + mut g := unsafe { &Gen(data) } + + if node is ast.Expr { + if node is ast.IfExpr && (node as ast.IfExpr).is_comptime { + eval_branch := g.comptime_conditional(node) or { + g.comptime_omitted_branches << node.branches + return false } - return true - }) + g.comptime_omitted_branches << node.branches.filter(it != eval_branch) + } else if node is ast.CallExpr && (node as ast.CallExpr).language != .v { + call := node as ast.CallExpr + if call.name !in g.extern_symbols { + g.extern_symbols << call.name + } + } else if node is ast.Ident && (node as ast.Ident).language != .v { + ident := node as ast.Ident + if ident.name !in g.extern_symbols { + g.extern_symbols << ident.name + } + } + } else if node is ast.Stmt && (node as ast.Stmt) is ast.HashStmt { + hash_stmt := node as ast.HashStmt + if hash_stmt.kind == 'flag' && g.should_emit_hash_stmt(hash_stmt) { + g.gen_flag_hash_stmt(hash_stmt) + } + } else if node is ast.IfBranch { + return node !in g.comptime_omitted_branches } + return true +} + +pub fn (mut g Gen) has_external_deps() bool { return g.extern_symbols.len != 0 } +pub fn (mut g Gen) ast_fetch_external_deps() bool { + for file in g.files { + g.current_file = file + walker.inspect(file, unsafe { &mut g }, node_fetch_external_deps) + } + + return g.has_external_deps() +} + pub fn (mut g Gen) generate_header() { - g.requires_linking = g.ast_has_external_functions() + g.requires_linking = g.ast_fetch_external_deps() match g.pref.os { .macos { @@ -1112,11 +1140,11 @@ pub fn (mut g Gen) v_error(s string, pos token.Pos) { // of guessed from the pref.path ... mut kind := 'error:' if g.pref.output_mode == .stdout { - util.show_compiler_message(kind, pos: pos, file_path: g.pref.path, message: s) + util.show_compiler_message(kind, pos: pos, file_path: g.current_file.path, message: s) exit(1) } else { g.errors << errors.Error{ - file_path: g.pref.path + file_path: g.current_file.path pos: pos reporter: .gen message: s diff --git a/vlib/v/gen/native/pe.v b/vlib/v/gen/native/pe.v index 43211e0a7640ff..c7073079dbee2b 100644 --- a/vlib/v/gen/native/pe.v +++ b/vlib/v/gen/native/pe.v @@ -608,9 +608,12 @@ fn (mut g Gen) gen_pe_idata() { idata_pos := g.pos() idata_section.set_pointer_to_raw_data(mut g, int(idata_pos)) - dll_files := ['KERNEL32.DLL', 'USER32.DLL', 'msvcrt.dll'] + g.linker_include_paths << '.' + + mut dll_files := ['KERNEL32.DLL', 'USER32.DLL', 'msvcrt.dll'] + dll_files << g.linker_libs.map(it + '.dll') mut dlls := dll_files - .map(lookup_system_dll(it) or { g.n_error('${it}: ${err}') }) + .map(g.lookup_system_dll(it) or { g.n_error('${it}: ${err}') }) .map(index_dll(it) or { g.n_error('${it}: ${err}') }) g.extern_symbols << [ @@ -620,7 +623,7 @@ fn (mut g Gen) gen_pe_idata() { ] for symbol in g.extern_symbols { - sym := symbol.trim_left('C.') + sym := symbol.all_after('C.') mut found := false for mut dll in dlls { if sym in dll.exports { diff --git a/vlib/v/gen/native/readdll.v b/vlib/v/gen/native/readdll.v index 6744a1aed4448d..19c8042288d2fd 100644 --- a/vlib/v/gen/native/readdll.v +++ b/vlib/v/gen/native/readdll.v @@ -21,7 +21,17 @@ struct SystemDll { fn C.SearchPathA(lp_path &char, lp_file_name &char, lp_extension &char, n_buffer_length u32, lp_buffer &char, lp_file_part &&char) u32 fn C.GetLastError() u32 -fn lookup_system_dll(dll string) !SystemDll { +fn (mut g Gen) lookup_system_dll(dll string) !SystemDll { + for path in g.linker_include_paths { + full_path := os.join_path(path, dll) + if os.exists(full_path) { + return SystemDll{ + name: dll + full_path: full_path + } + } + } + $if windows { unsafe { buffer := malloc(1024) diff --git a/vlib/v/gen/native/stmt.v b/vlib/v/gen/native/stmt.v index 0b7e477ed5393c..9ceec7a8006934 100644 --- a/vlib/v/gen/native/stmt.v +++ b/vlib/v/gen/native/stmt.v @@ -69,23 +69,21 @@ fn (mut g Gen) stmt(node ast.Stmt) { g.for_stmt(node) } ast.HashStmt { - words := node.val.split(' ') - mut unsupported := false - for word in words { - if word.len != 2 { - unsupported = true - break - } - b := unsafe { C.strtol(&char(word.str), 0, 16) } - // b := word.u8() - // println('"$word" $b') - g.write8(b) + if !g.should_emit_hash_stmt(node) { + return } - if unsupported { - if !g.pref.experimental { - g.warning('opcodes format: xx xx xx xx\nhash statements are not allowed with the native backend, use the C backend for extended C interoperability.', + match node.kind { + 'include', 'preinclude', 'define', 'insert' { + g.warning('#${node.kind} is not supported with the native backend', node.pos) + // TODO: replace with error once issues with builtin are resolved + } + 'flag' { + // flags are already handled when dispatching extern dependencies + } + else { + g.gen_native_hash_stmt(node) } } } @@ -343,3 +341,37 @@ fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) { g.labels.addrs[label] = g.pos() g.println('; label ${label}') } + +fn (mut g Gen) gen_flag_hash_stmt(node ast.HashStmt) { + if node.main.contains('-l') { + g.linker_libs << node.main.all_after('-l').trim_space() + } else if node.main.contains('-L') { + g.linker_include_paths << node.main.all_after('-L').trim_space() + } else if node.main.contains('-D') || node.main.contains('-I') { + g.v_error('`-D` and `-I` flags are not supported with the native backend', node.pos) + } else { + g.v_error('unknown `#flag` format: `${node.main}`', node.pos) + } +} + +fn (mut g Gen) gen_native_hash_stmt(node ast.HashStmt) { + words := node.val.split(' ') + mut unsupported := false + for word in words { + if word.len != 2 { + unsupported = true + break + } + b := unsafe { C.strtol(&char(word.str), 0, 16) } + // b := word.u8() + // println('"$word" $b') + g.write8(b) + } + + if unsupported { + if !g.pref.experimental { + g.warning('opcodes format: xx xx xx xx\nhash statements are not allowed with the native backend, use the C backend for extended C interoperability.', + node.pos) + } + } +}