From d2d0930aa2b5235520f1a8e45e4c4f033e126e8b Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Fri, 3 Jan 2025 10:04:42 +0800 Subject: [PATCH 01/16] cgen: fix windows hot reload --- vlib/v/gen/c/cgen.v | 3 --- 1 file changed, 3 deletions(-) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 61da187473bd05..4a8cbd46bae078 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6094,9 +6094,6 @@ fn (mut g Gen) write_init_function() { defer { util.timing_measure(@METHOD) } - if g.pref.is_liveshared { - return - } fn_vinit_start_pos := g.out.len // ___argv is declared as voidptr here, because that unifies the windows/unix logic From dc2d152649ae4a1c8ca2579600ee78f6b691c8ee Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Fri, 3 Jan 2025 10:12:20 +0800 Subject: [PATCH 02/16] fix windows --- vlib/v/gen/c/cgen.v | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 4a8cbd46bae078..79a6bad86a3365 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6094,6 +6094,13 @@ fn (mut g Gen) write_init_function() { defer { util.timing_measure(@METHOD) } + + // Force generate _vinit_caller, _vcleanup_caller , these are needed under Windows, + // because dl.open() / dl.close() will call them when loading/unloading shared dll. + if g.pref.is_liveshared && g.pref.os != .windows { + return + } + fn_vinit_start_pos := g.out.len // ___argv is declared as voidptr here, because that unifies the windows/unix logic From 42984242cacfe8ae9a79568de64d85681e60f603 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Fri, 3 Jan 2025 16:01:42 +0800 Subject: [PATCH 03/16] fix pointer assignment --- vlib/v/live/common.c.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlib/v/live/common.c.v b/vlib/v/live/common.c.v index 9ba61c3bd9f704..186ef0be4e3c81 100644 --- a/vlib/v/live/common.c.v +++ b/vlib/v/live/common.c.v @@ -59,7 +59,7 @@ pub fn info() &LiveReloadInfo { mut x := &LiveReloadInfo{} unsafe { mut p := &u64(&C.g_live_info) - *p = &u64(x) + *p = u64(x) _ = p } return x From 9364c5b54d5e9e69a59b20351d35fa058f28e984 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Fri, 3 Jan 2025 17:20:21 +0800 Subject: [PATCH 04/16] simplify code --- vlib/v/live/common.c.v | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/vlib/v/live/common.c.v b/vlib/v/live/common.c.v index 186ef0be4e3c81..8275ead93868ff 100644 --- a/vlib/v/live/common.c.v +++ b/vlib/v/live/common.c.v @@ -48,19 +48,15 @@ pub mut: // live.info - give user access to program's LiveReloadInfo struct, // so that the user can set callbacks, read meta information, etc. pub fn info() &LiveReloadInfo { - if C.g_live_info != 0 { - return unsafe { &LiveReloadInfo(C.g_live_info) } + if C.g_live_info == 0 { + // When the current program is not compiled with -live, simply + // return a new empty struct LiveReloadInfo in order to prevent + // crashes. In this case, the background reloader thread is not + // started, and the structure LiveReloadInfo will not get updated. + // All its fields will be 0, but still safe to access. + unsafe { + C.g_live_info = int(&LiveReloadInfo{}) + } } - // When the current program is not compiled with -live, simply - // return a new empty struct LiveReloadInfo in order to prevent - // crashes. In this case, the background reloader thread is not - // started, and the structure LiveReloadInfo will not get updated. - // All its fields will be 0, but still safe to access. - mut x := &LiveReloadInfo{} - unsafe { - mut p := &u64(&C.g_live_info) - *p = u64(x) - _ = p - } - return x + return unsafe { &LiveReloadInfo(C.g_live_info) } } From 89a969820bca098c35f1d08b7e5d5f1e74560cd1 Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Fri, 3 Jan 2025 17:30:56 +0800 Subject: [PATCH 05/16] remove unsafe --- vlib/v/live/common.c.v | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vlib/v/live/common.c.v b/vlib/v/live/common.c.v index 8275ead93868ff..8cd61ac472c989 100644 --- a/vlib/v/live/common.c.v +++ b/vlib/v/live/common.c.v @@ -54,9 +54,7 @@ pub fn info() &LiveReloadInfo { // crashes. In this case, the background reloader thread is not // started, and the structure LiveReloadInfo will not get updated. // All its fields will be 0, but still safe to access. - unsafe { - C.g_live_info = int(&LiveReloadInfo{}) - } + C.g_live_info = int(&LiveReloadInfo{}) } - return unsafe { &LiveReloadInfo(C.g_live_info) } + return &LiveReloadInfo(C.g_live_info) } From 46b058547912e2da0c10ad4214fd5180d6866ee2 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 12:04:35 +0200 Subject: [PATCH 06/16] use a V global in builtin, instead of the one generated in cheaders.v --- vlib/builtin/builtin.c.v | 3 +++ vlib/v/live/common.c.v | 6 +++--- vlib/v/live/executable/reloader.c.v | 7 +++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 2f8e5c9683ef51..11a24a6512de65 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -768,6 +768,9 @@ __global g_main_argc = int(0) @[markused] __global g_main_argv = unsafe { nil } +@[markused] +__global g_live_reload_info = unsafe { nil } + // arguments returns the command line arguments, used for starting the current program as a V array of strings. // The first string in the array (index 0), is the name of the program, used for invoking the program. // The second string in the array (index 1), if it exists, is the first argument to the program, etc. diff --git a/vlib/v/live/common.c.v b/vlib/v/live/common.c.v index 8cd61ac472c989..95e17523dde34e 100644 --- a/vlib/v/live/common.c.v +++ b/vlib/v/live/common.c.v @@ -48,13 +48,13 @@ pub mut: // live.info - give user access to program's LiveReloadInfo struct, // so that the user can set callbacks, read meta information, etc. pub fn info() &LiveReloadInfo { - if C.g_live_info == 0 { + if g_live_reload_info == 0 { // When the current program is not compiled with -live, simply // return a new empty struct LiveReloadInfo in order to prevent // crashes. In this case, the background reloader thread is not // started, and the structure LiveReloadInfo will not get updated. // All its fields will be 0, but still safe to access. - C.g_live_info = int(&LiveReloadInfo{}) + g_live_reload_info = &LiveReloadInfo{} } - return &LiveReloadInfo(C.g_live_info) + return &LiveReloadInfo(g_live_reload_info) } diff --git a/vlib/v/live/executable/reloader.c.v b/vlib/v/live/executable/reloader.c.v index 8868fe4d748ef1..a98d645dd1dff6 100644 --- a/vlib/v/live/executable/reloader.c.v +++ b/vlib/v/live/executable/reloader.c.v @@ -16,7 +16,7 @@ pub fn new_live_reload_info(original string, vexe string, vopts string, live_fn_ so_extension = '.dylib' } // $if msvc { so_extension = '.dll' } $else { so_extension = '.so' } - return &live.LiveReloadInfo{ + res := &live.LiveReloadInfo{ original: original vexe: vexe vopts: vopts @@ -28,6 +28,8 @@ pub fn new_live_reload_info(original string, vexe string, vopts string, live_fn_ reloads: 0 reload_time_ms: 0 } + elog(res, @FN) + return res } // Note: start_reloader will be called by generated code inside main(), to start @@ -35,6 +37,7 @@ pub fn new_live_reload_info(original string, vexe string, vopts string, live_fn_ // the original main thread. @[markused] pub fn start_reloader(mut r live.LiveReloadInfo) { + elog(r, @FN) // The shared library should be loaded once in the main thread // If that fails, the program would crash anyway, just provide // an error message to the user and exit: @@ -62,7 +65,7 @@ pub fn add_live_monitored_file(mut lri live.LiveReloadInfo, path string) { @[if debuglive ?] fn elog(r &live.LiveReloadInfo, s string) { - eprintln(s) + eprintln('> debuglive r: ${voidptr(r)} ${s}') } fn compile_and_reload_shared_lib(mut r live.LiveReloadInfo) !bool { From 4531896c0d9090b817db5aa2266976a9b48dd720 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 12:10:06 +0200 Subject: [PATCH 07/16] add some state to the message.v example, to make it easier to test --- examples/hot_reload/message.v | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/examples/hot_reload/message.v b/examples/hot_reload/message.v index 336a2cfaff4bf7..3533f8fbe1f90d 100644 --- a/examples/hot_reload/message.v +++ b/examples/hot_reload/message.v @@ -4,15 +4,27 @@ module main import time import v.live +struct App { +mut: + x int + counter int +} + @[live] -fn print_message() { +fn print_message(mut app App) { info := live.info() println('OK reloads: ${info.reloads_ok:4d} | Total reloads: ${info.reloads:4d} | Hello! Modify this message while the program is running.') + eprintln('>> app: ${voidptr(app)} | g_live_reload_info: ${voidptr(g_live_reload_info)}') + app.x = 9991 // try changing this to another value, while the program is running ... + app.counter++ + dump(app) } fn main() { + unbuffer_stdout() + mut app := &App{} for { - print_message() + print_message(mut app) time.sleep(500 * time.millisecond) } } From 644ce96fb879e987d56686f9a12b129e3da79fae Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 12:26:17 +0200 Subject: [PATCH 08/16] modify cgen to set tg_live_reload_info --- vlib/builtin/builtin.c.v | 4 ++-- vlib/v/gen/c/live.v | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 11a24a6512de65..6a40a4a6b1184e 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -69,7 +69,7 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) { eprint(' function: '); eprint(fn_name); eprintln('()') eprint(' message: '); eprintln(s) eprint(' file: '); eprint(file); eprint(':'); - C.fprintf(C.stderr, c'%d\n', line_no) + C.fprintf(C.stderr, c'%d\n', line_no) eprint(' v hash: '); eprintln(@VCURRENTHASH) eprintln('=========================================') // vfmt on @@ -768,7 +768,7 @@ __global g_main_argc = int(0) @[markused] __global g_main_argv = unsafe { nil } -@[markused] +@[markused; export: 'g_live_reload_info'] __global g_live_reload_info = unsafe { nil } // arguments returns the command line arguments, used for starting the current program as a V array of strings. diff --git a/vlib/v/gen/c/live.v b/vlib/v/gen/c/live.v index 5bf52521dea620..7eef1b5efeec80 100644 --- a/vlib/v/gen/c/live.v +++ b/vlib/v/gen/c/live.v @@ -107,9 +107,9 @@ fn (mut g Gen) generate_hotcode_reloading_main_caller() { idx++ } g.writeln('') - // g_live_info gives access to the LiveReloadInfo methods, + // g_live_reload_info gives access to the LiveReloadInfo methods, // to the custom user code, through calling v_live_info() - g.writeln('\t\tg_live_info = (void*)live_info;') + g.writeln('\t\tg_live_reload_info = (void*)live_info;') g.writeln('\t\tv__live__executable__start_reloader(live_info);') g.writeln('\t}\t// end of live code initialization section') g.writeln('') From 7b17589ed94969f5c04d5e717dda9a6432f3898d Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 12:27:20 +0200 Subject: [PATCH 09/16] run `v fmt -w vlib/builtin` --- vlib/builtin/builtin.c.v | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 6a40a4a6b1184e..6fa45f9ecc037b 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -768,7 +768,8 @@ __global g_main_argc = int(0) @[markused] __global g_main_argv = unsafe { nil } -@[markused; export: 'g_live_reload_info'] +@[export: 'g_live_reload_info'] +@[markused] __global g_live_reload_info = unsafe { nil } // arguments returns the command line arguments, used for starting the current program as a V array of strings. From 4b638b351e7634ae1e70e149484e29e1a5de0a5c Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 13:11:20 +0200 Subject: [PATCH 10/16] fix bootstrapping with -cstrict --- examples/hot_reload/message.v | 4 ++-- vlib/builtin/builtin.c.v | 5 ++--- vlib/v/gen/c/live.v | 4 ++-- vlib/v/live/common.c.v | 2 +- vlib/v/live/executable/reloader.c.v | 2 +- vlib/v/live/sharedlib/live_sharedlib.v | 4 ++++ 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/examples/hot_reload/message.v b/examples/hot_reload/message.v index 3533f8fbe1f90d..6f53f32cc83fbb 100644 --- a/examples/hot_reload/message.v +++ b/examples/hot_reload/message.v @@ -13,9 +13,9 @@ mut: @[live] fn print_message(mut app App) { info := live.info() - println('OK reloads: ${info.reloads_ok:4d} | Total reloads: ${info.reloads:4d} | Hello! Modify this message while the program is running.') + println('1 OK reloads: ${info.reloads_ok:4d} | Total reloads: ${info.reloads:4d} | Hello! Modify this message while the program is running.') eprintln('>> app: ${voidptr(app)} | g_live_reload_info: ${voidptr(g_live_reload_info)}') - app.x = 9991 // try changing this to another value, while the program is running ... + app.x = 341 // try changing this to another value, while the program is running ... app.counter++ dump(app) } diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 6fa45f9ecc037b..5bfdceb97f7b09 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -394,7 +394,7 @@ fn _memory_panic(fname string, size isize) { $if freestanding || vinix { eprint('size') // TODO: use something more informative here } $else { - C.fprintf(C.stderr, c'%ld', size) + C.fprintf(C.stderr, c'%lld', size) } if size < 0 { eprint(' < 0') @@ -768,9 +768,8 @@ __global g_main_argc = int(0) @[markused] __global g_main_argv = unsafe { nil } -@[export: 'g_live_reload_info'] @[markused] -__global g_live_reload_info = unsafe { nil } +__global g_live_reload_info voidptr // arguments returns the command line arguments, used for starting the current program as a V array of strings. // The first string in the array (index 0), is the name of the program, used for invoking the program. diff --git a/vlib/v/gen/c/live.v b/vlib/v/gen/c/live.v index 7eef1b5efeec80..611c3cc025c94b 100644 --- a/vlib/v/gen/c/live.v +++ b/vlib/v/gen/c/live.v @@ -41,12 +41,12 @@ fn (mut g Gen) generate_hotcode_reloader_code() { mut load_code := []string{} if g.pref.os != .windows { for so_fn in g.hotcode_fn_names { - load_code << 'impl_live_${so_fn} = dlsym(live_lib, "impl_live_${so_fn}");' + load_code << '\timpl_live_${so_fn} = dlsym(live_lib, "impl_live_${so_fn}");' } phd = posix_hotcode_definitions_1 } else { for so_fn in g.hotcode_fn_names { - load_code << 'impl_live_${so_fn} = (void *)GetProcAddress(live_lib, "impl_live_${so_fn}"); ' + load_code << '\timpl_live_${so_fn} = (void *)GetProcAddress(live_lib, "impl_live_${so_fn}"); ' } phd = windows_hotcode_definitions_1 } diff --git a/vlib/v/live/common.c.v b/vlib/v/live/common.c.v index 95e17523dde34e..d3ba3358442df7 100644 --- a/vlib/v/live/common.c.v +++ b/vlib/v/live/common.c.v @@ -56,5 +56,5 @@ pub fn info() &LiveReloadInfo { // All its fields will be 0, but still safe to access. g_live_reload_info = &LiveReloadInfo{} } - return &LiveReloadInfo(g_live_reload_info) + return unsafe { &LiveReloadInfo(g_live_reload_info) } } diff --git a/vlib/v/live/executable/reloader.c.v b/vlib/v/live/executable/reloader.c.v index a98d645dd1dff6..f5259df0f66038 100644 --- a/vlib/v/live/executable/reloader.c.v +++ b/vlib/v/live/executable/reloader.c.v @@ -65,7 +65,7 @@ pub fn add_live_monitored_file(mut lri live.LiveReloadInfo, path string) { @[if debuglive ?] fn elog(r &live.LiveReloadInfo, s string) { - eprintln('> debuglive r: ${voidptr(r)} ${s}') + eprintln('> debuglive r: ${voidptr(r)} &g_live_reload_info: ${voidptr(&g_live_reload_info)} | g_live_reload_info: ${voidptr(g_live_reload_info)} ${s}') } fn compile_and_reload_shared_lib(mut r live.LiveReloadInfo) !bool { diff --git a/vlib/v/live/sharedlib/live_sharedlib.v b/vlib/v/live/sharedlib/live_sharedlib.v index e19b418b827483..2a79e84041fe7b 100644 --- a/vlib/v/live/sharedlib/live_sharedlib.v +++ b/vlib/v/live/sharedlib/live_sharedlib.v @@ -1,3 +1,7 @@ module sharedlib import v.live as _ + +pub fn set_live_reload_pointer(p voidptr) { + eprintln('> set_live_reload_pointer, p: ${p}') +} From f19b4f2a05565dd85a90068c1152d06607b410db Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 13:18:40 +0200 Subject: [PATCH 11/16] use a more explicit cast in the C.fprintf call in _memory_panic --- vlib/builtin/builtin.c.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 5bfdceb97f7b09..a9680eed30e107 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -394,7 +394,7 @@ fn _memory_panic(fname string, size isize) { $if freestanding || vinix { eprint('size') // TODO: use something more informative here } $else { - C.fprintf(C.stderr, c'%lld', size) + C.fprintf(C.stderr, c'%ld', i64(size)) } if size < 0 { eprint(' < 0') From f7be8f5f2292198e91552dc1ad624606307506cc Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 13:42:55 +0200 Subject: [PATCH 12/16] use %p, do not bother with sizes at all --- vlib/builtin/builtin.c.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index a9680eed30e107..831f7d543173b4 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -394,7 +394,7 @@ fn _memory_panic(fname string, size isize) { $if freestanding || vinix { eprint('size') // TODO: use something more informative here } $else { - C.fprintf(C.stderr, c'%ld', i64(size)) + C.fprintf(C.stderr, c'%p', voidptr(size)) } if size < 0 { eprint(' < 0') From 4f8e4e6a83f4b55406806c7ee3beaa54d6e05565 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 13:34:32 +0200 Subject: [PATCH 13/16] renumber global setting comments --- vlib/v/gen/c/consts_and_globals.v | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vlib/v/gen/c/consts_and_globals.v b/vlib/v/gen/c/consts_and_globals.v index 2fb214b526f118..b6d6c4fca20a9c 100644 --- a/vlib/v/gen/c/consts_and_globals.v +++ b/vlib/v/gen/c/consts_and_globals.v @@ -440,7 +440,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { fn_type_name := g.get_anon_fn_type_name(mut anon_fn_expr, field.name) g.global_const_defs[util.no_dots(fn_type_name)] = GlobalConstDef{ mod: node.mod - def: '${fn_type_name} = ${g.table.sym(field.typ).name}; // global2' + def: '${fn_type_name} = ${g.table.sym(field.typ).name}; // global 1' order: -1 } continue @@ -451,7 +451,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { modifier := if field.is_volatile { ' volatile ' } else { '' } def_builder.write_string('${extern}${visibility_kw}${modifier}${styp} ${attributes}${field.name}') if cextern { - def_builder.writeln('; // global5') + def_builder.writeln('; // global 2') g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{ mod: node.mod def: def_builder.str() @@ -484,7 +484,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { if field.name in ['g_main_argc', 'g_main_argv'] { init = '\t// skipping ${field.name}, it was initialised in main' } else { - init = '\t${field.name} = ${g.expr_string(field.expr)}; // 3global' + init = '\t${field.name} = ${g.expr_string(field.expr)}; // global 3' } } } else if !g.pref.translated { // don't zero globals from C code @@ -493,18 +493,18 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { if default_initializer == '{0}' && should_init { def_builder.write_string(' = {0}') } else if default_initializer == '{EMPTY_STRUCT_INITIALIZATION}' && should_init { - init = '\tmemcpy(${field.name}, (${styp}){${default_initializer}}, sizeof(${styp})); // global' + init = '\tmemcpy(${field.name}, (${styp}){${default_initializer}}, sizeof(${styp})); // global 4' } else { if field.name !in ['as_cast_type_indexes', 'g_memory_block', 'global_allocator'] { decls := g.type_default_vars.str() if decls != '' { init = '\t${decls}' } - init += '\t${field.name} = *(${styp}*)&((${styp}[]){${default_initializer}}[0]); // global' + init += '\t${field.name} = *(${styp}*)&((${styp}[]){${default_initializer}}[0]); // global 5' } } } - def_builder.writeln('; // global4') + def_builder.writeln('; // global 6') g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{ mod: node.mod def: def_builder.str() From 94b8810ef189ae1659e3b57f4dfd2d14a8c808d7 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 14:35:13 +0200 Subject: [PATCH 14/16] fix and cleanup --- examples/hot_reload/message.v | 8 +++----- vlib/v/gen/c/live.v | 4 ++++ vlib/v/live/sharedlib/live_sharedlib.v | 14 +++++++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/examples/hot_reload/message.v b/examples/hot_reload/message.v index 6f53f32cc83fbb..7e619431a56684 100644 --- a/examples/hot_reload/message.v +++ b/examples/hot_reload/message.v @@ -12,12 +12,10 @@ mut: @[live] fn print_message(mut app App) { - info := live.info() - println('1 OK reloads: ${info.reloads_ok:4d} | Total reloads: ${info.reloads:4d} | Hello! Modify this message while the program is running.') - eprintln('>> app: ${voidptr(app)} | g_live_reload_info: ${voidptr(g_live_reload_info)}') - app.x = 341 // try changing this to another value, while the program is running ... + i := live.info() + println('OK reloads: ${i.reloads_ok:4d} | Total reloads: ${i.reloads:4d} | ${voidptr(i)} Hello! Modify this message while the program is running. app: ${app}') + app.x = 2 // try changing this to another value, while the program is running ... app.counter++ - dump(app) } fn main() { diff --git a/vlib/v/gen/c/live.v b/vlib/v/gen/c/live.v index 611c3cc025c94b..c7383b3dbf17de 100644 --- a/vlib/v/gen/c/live.v +++ b/vlib/v/gen/c/live.v @@ -50,6 +50,10 @@ fn (mut g Gen) generate_hotcode_reloader_code() { } phd = windows_hotcode_definitions_1 } + // Ensure that g_live_reload_info from the executable is passed to the DLL/SO . + // See also vlib/v/live/sharedlib/live_sharedlib.v . + load_code << 'void (* fn_set_live_reload_pointer)(void *) = (void *)GetProcAddress(live_lib, "set_live_reload_pointer");' + load_code << 'if(fn_set_live_reload_pointer){ fn_set_live_reload_pointer( g_live_reload_info ); }' g.hotcode_definitions.writeln(phd.replace('@LOAD_FNS@', load_code.join('\n'))) } } diff --git a/vlib/v/live/sharedlib/live_sharedlib.v b/vlib/v/live/sharedlib/live_sharedlib.v index 2a79e84041fe7b..819445235104f9 100644 --- a/vlib/v/live/sharedlib/live_sharedlib.v +++ b/vlib/v/live/sharedlib/live_sharedlib.v @@ -2,6 +2,18 @@ module sharedlib import v.live as _ +@[export: 'set_live_reload_pointer'] +@[markused] pub fn set_live_reload_pointer(p voidptr) { - eprintln('> set_live_reload_pointer, p: ${p}') + // NOTE: the `g_live_reload_info` global on windows, in the DLL, has a different address itself, + // compared to the g_live_reload_info in the main executable. + // + // The code here, ensures that *its value* will be the same, + // since the executable, will make sure to load the DLL, and then call set_live_reload_pointer() + // after binding it, in its generaged `v_bind_live_symbols`, with the value of its own `g_live_reload_info` global. + // + // This is not necessary on macos and linux, but it is best to have the same code across systems anyway. + // eprintln('>>>>> before &g_live_reload_info: ${voidptr(&g_live_reload_info)} | g_live_reload_info: ${voidptr(g_live_reload_info)}') + g_live_reload_info = p + // eprintln('>>>>> after &g_live_reload_info: ${voidptr(&g_live_reload_info)} | g_live_reload_info: ${voidptr(g_live_reload_info)}') } From aa16e41a472d917d156b56d61e0600bbe14d82bc Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 14:45:26 +0200 Subject: [PATCH 15/16] more cleanup, fix compilation on posix (use dlsym) --- examples/hot_reload/message.v | 4 ++-- vlib/v/gen/c/live.v | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/hot_reload/message.v b/examples/hot_reload/message.v index 7e619431a56684..c6d7cdd07a61bf 100644 --- a/examples/hot_reload/message.v +++ b/examples/hot_reload/message.v @@ -13,8 +13,8 @@ mut: @[live] fn print_message(mut app App) { i := live.info() - println('OK reloads: ${i.reloads_ok:4d} | Total reloads: ${i.reloads:4d} | ${voidptr(i)} Hello! Modify this message while the program is running. app: ${app}') - app.x = 2 // try changing this to another value, while the program is running ... + println('OK reloads: ${i.reloads_ok:4d} | Total reloads: ${i.reloads:4d} | Hello! Modify this message while the program is running. app: ${voidptr(app)} | app.x: ${app.x:6} | app.counter: ${app.counter:6}') + // app.x = 99 // try changing this to another value, while the program is running ... app.counter++ } diff --git a/vlib/v/gen/c/live.v b/vlib/v/gen/c/live.v index c7383b3dbf17de..4f9aacfd1d8968 100644 --- a/vlib/v/gen/c/live.v +++ b/vlib/v/gen/c/live.v @@ -43,17 +43,19 @@ fn (mut g Gen) generate_hotcode_reloader_code() { for so_fn in g.hotcode_fn_names { load_code << '\timpl_live_${so_fn} = dlsym(live_lib, "impl_live_${so_fn}");' } + load_code << 'void (* fn_set_live_reload_pointer)(void *) = (void *)dlsym(live_lib, "set_live_reload_pointer");' phd = posix_hotcode_definitions_1 } else { for so_fn in g.hotcode_fn_names { load_code << '\timpl_live_${so_fn} = (void *)GetProcAddress(live_lib, "impl_live_${so_fn}"); ' } + load_code << 'void (* fn_set_live_reload_pointer)(void *) = (void *)GetProcAddress(live_lib, "set_live_reload_pointer");' phd = windows_hotcode_definitions_1 } - // Ensure that g_live_reload_info from the executable is passed to the DLL/SO . + // Ensure that g_live_reload_info from the executable is passed to the DLL . // See also vlib/v/live/sharedlib/live_sharedlib.v . - load_code << 'void (* fn_set_live_reload_pointer)(void *) = (void *)GetProcAddress(live_lib, "set_live_reload_pointer");' load_code << 'if(fn_set_live_reload_pointer){ fn_set_live_reload_pointer( g_live_reload_info ); }' + g.hotcode_definitions.writeln(phd.replace('@LOAD_FNS@', load_code.join('\n'))) } } From 225d319fffbe2f2af8f481b5731f0843313fd20a Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 3 Jan 2025 15:18:53 +0200 Subject: [PATCH 16/16] fix live_test.v on windows --- vlib/v/live/live_test.v | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/vlib/v/live/live_test.v b/vlib/v/live/live_test.v index da2b51b30071bd..a708f21d5afc48 100644 --- a/vlib/v/live/live_test.v +++ b/vlib/v/live/live_test.v @@ -36,7 +36,7 @@ const vtmp_folder = os.join_path(os.vtmp_dir(), 'live_tests') const main_source_file = os.join_path(vtmp_folder, 'main.v') const tmp_file = os.join_path(vtmp_folder, 'mymodule', 'generated_live_module.tmp') const source_file = os.join_path(vtmp_folder, 'mymodule', 'mymodule.v') -const genexe_file = os.join_path(vtmp_folder, 'generated_live_program') +const genexe_file = os.join_path(vtmp_folder, 'generated_live_program.exe') const output_file = os.join_path(vtmp_folder, 'generated_live_program.output.txt') const res_original_file = os.join_path(vtmp_folder, 'ORIGINAL.txt') const res_changed_file = os.join_path(vtmp_folder, 'CHANGED.txt') @@ -46,7 +46,7 @@ const live_program_source = get_source_template() fn get_source_template() string { src := os.read_file(os.join_path(os.dir(@FILE), 'live_test_template.vv')) or { panic(err) } - return src.replace('#OUTPUT_FILE#', output_file) + return src.replace('#OUTPUT_FILE#', output_file.replace('\\', '\\\\')) } fn atomic_write_source(source string) { @@ -168,19 +168,30 @@ fn setup_cycles_environment() { os.setenv('WAIT_CYCLES', '${max_wait_cycles}', true) } -// +fn run_in_background(cmd string) { + spawn fn (cmd string) { + res := os.execute(cmd) + if res.exit_code != 0 { + eprintln('----------------------- background command failed: --------------------------') + eprintln('----- exit_code: ${res.exit_code}, cmd: ${cmd}, output:') + eprintln(res.output) + eprintln('-----------------------------------------------------------------------------') + } + assert res.exit_code == 0 + }(cmd) + time.sleep(1000 * time.millisecond) + eprintln('... run_in_background, cmd: ${cmd}') +} + fn test_live_program_can_be_compiled() { setup_cycles_environment() eprintln('Compiling...') compile_cmd := '${os.quoted_path(vexe)} -cg -keepc -nocolor -live -o ${os.quoted_path(genexe_file)} ${os.quoted_path(main_source_file)}' eprintln('> compile_cmd: ${compile_cmd}') - os.system(compile_cmd) - - cmd := '${os.quoted_path(genexe_file)} > /dev/null &' - eprintln('Running with: ${cmd}') - res := os.system(cmd) - assert res == 0 - eprintln('... running in the background') + time.sleep(1000 * time.millisecond) // improve chances of working on windows + compile_res := os.system(compile_cmd) + assert compile_res == 0 + run_in_background('${os.quoted_path(genexe_file)}') wait_for_file('ORIGINAL') }