v2 / vlib / v / gen / c / live.v
175 lines · 164 sloc · 5.92 KB · 66d9d481d93b6fd03a0b3459ade58d0907352549
Raw
1module c
2
3import os
4import v.pref
5import v.util
6
7fn live_runtime_quoted_path(target_os pref.OS, path string) string {
8 return match target_os {
9 .windows { '"${path.replace('"', '\\"')}"' }
10 else { "'" + path.replace("'", "'\\''") + "'" }
11 }
12}
13
14fn live_runtime_quoted_path_for_c_string(target_os pref.OS, path string) string {
15 return live_runtime_quoted_path(target_os, path).replace('\\', '\\\\').replace('"', '\\"')
16}
17
18fn (mut g Gen) generate_hotcode_reloading_declarations() {
19 if g.pref.os == .windows {
20 g.hotcode_definitions.writeln('HANDLE live_fn_mutex = 0;')
21 g.hotcode_definitions.writeln('
22HANDLE* v_live_fn_mutex_ptr(void) {
23 if (g_live_reload_info) {
24 v__live__LiveReloadInfo* live_info = (v__live__LiveReloadInfo*)g_live_reload_info;
25 if (live_info->live_fn_mutex) {
26 return (HANDLE*)live_info->live_fn_mutex;
27 }
28 }
29 if (!live_fn_mutex) {
30 live_fn_mutex = CreateMutexA(0, 0, 0);
31 }
32 return &live_fn_mutex;
33}
34void pthread_mutex_lock(HANDLE *m) {
35 WaitForSingleObject(*m, INFINITE);
36}
37void pthread_mutex_unlock(HANDLE *m) {
38 ReleaseMutex(*m);
39}
40')
41 } else {
42 g.hotcode_definitions.writeln('pthread_mutex_t live_fn_mutex;')
43 g.hotcode_definitions.writeln('pthread_once_t live_fn_mutex_once = PTHREAD_ONCE_INIT;')
44 g.hotcode_definitions.writeln('
45void v_init_live_mutex(void) {
46 pthread_mutexattr_t live_fn_mutex_attr;
47 pthread_mutexattr_init(&live_fn_mutex_attr);
48 pthread_mutexattr_settype(&live_fn_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
49 pthread_mutex_init(&live_fn_mutex, &live_fn_mutex_attr);
50 pthread_mutexattr_destroy(&live_fn_mutex_attr);
51}
52
53pthread_mutex_t* v_live_fn_mutex_ptr(void) {
54 if (g_live_reload_info) {
55 v__live__LiveReloadInfo* live_info = (v__live__LiveReloadInfo*)g_live_reload_info;
56 if (live_info->live_fn_mutex) {
57 return (pthread_mutex_t*)live_info->live_fn_mutex;
58 }
59 }
60 pthread_once(&live_fn_mutex_once, v_init_live_mutex);
61 return &live_fn_mutex;
62}
63')
64 }
65}
66
67fn (mut g Gen) generate_hotcode_reloader_code() {
68 if g.pref.is_liveshared {
69 g.hotcode_definitions.writeln('')
70 return
71 }
72 // Hot code reloading
73 if g.pref.is_livemain {
74 mut phd := ''
75 mut load_code := []string{}
76 if g.pref.os != .windows {
77 for so_fn in g.hotcode_fn_names {
78 load_code << '\tvoid* live_sym_${so_fn} = dlsym(live_lib, "impl_live_${so_fn}");'
79 load_code << '\tif (live_sym_${so_fn}) {'
80 load_code << '\t\timpl_live_${so_fn} = live_sym_${so_fn};'
81 load_code << '\t} else {'
82 load_code << '\t\timpl_live_${so_fn} = no_impl_${so_fn};'
83 load_code << '\t}'
84 }
85 load_code << 'void (* fn_set_live_reload_pointer)(void *) = (void *)dlsym(live_lib, "set_live_reload_pointer");'
86 phd = posix_hotcode_definitions_1
87 } else {
88 for so_fn in g.hotcode_fn_names {
89 load_code << '\tvoid* live_sym_${so_fn} = (void *)GetProcAddress(live_lib, "impl_live_${so_fn}");'
90 load_code << '\tif (live_sym_${so_fn}) {'
91 load_code << '\t\timpl_live_${so_fn} = live_sym_${so_fn};'
92 load_code << '\t} else {'
93 load_code << '\t\timpl_live_${so_fn} = no_impl_${so_fn};'
94 load_code << '\t}'
95 }
96 load_code << 'void (* fn_set_live_reload_pointer)(void *) = (void *)GetProcAddress(live_lib, "set_live_reload_pointer");'
97 phd = windows_hotcode_definitions_1
98 }
99 // Ensure that g_live_reload_info from the executable is passed to the DLL .
100 // See also vlib/v/live/sharedlib/live_sharedlib.v .
101 load_code << 'if(fn_set_live_reload_pointer){ fn_set_live_reload_pointer( g_live_reload_info ); }'
102
103 g.hotcode_definitions.writeln(phd.replace('@LOAD_FNS@', load_code.join('\n')))
104 }
105}
106
107const posix_hotcode_definitions_1 = '
108void v_bind_live_symbols(void* live_lib){
109 @LOAD_FNS@
110}
111'
112
113const windows_hotcode_definitions_1 = '
114void v_bind_live_symbols(void* live_lib){
115 @LOAD_FNS@
116}
117'
118
119fn (mut g Gen) generate_hotcode_reloading_main_caller() {
120 if !g.pref.is_livemain {
121 return
122 }
123 g.writeln('')
124 // We are in live code reload mode, so start the .so loader in the background
125 g.writeln2('\t// live code initialization section:', '\t{')
126 g.writeln('\t\t// initialization of live function pointers')
127 for fname in g.hotcode_fn_names {
128 g.writeln('\t\timpl_live_${fname} = no_impl_${fname};')
129 }
130 vexe := util.cescaped_path(pref.vexe_path())
131 file := util.cescaped_path(g.pref.path)
132 ccpath := live_runtime_quoted_path_for_c_string(g.pref.os, g.pref.ccompiler)
133 ccompiler := '-cc ${ccpath}'
134 so_debug_flag := if g.pref.is_debug { '-cg' } else { '' }
135 mut vopts := '${ccompiler} ${so_debug_flag} -sharedlive -shared'
136 if g.pref.os == .windows && g.is_cc_msvc && 'sokol' in g.table.imports {
137 mut import_lib_path := g.pref.out_name
138 ext := os.file_ext(import_lib_path)
139 if ext != '' {
140 import_lib_path = import_lib_path[..import_lib_path.len - ext.len] + '.lib'
141 } else {
142 import_lib_path += '.lib'
143 }
144 escaped_import_lib_path := util.cescaped_path(os.abs_path(import_lib_path))
145 vopts += " -ldflags \\\"${escaped_import_lib_path}\\\""
146 }
147
148 g.writeln('\t\t// start background reloading thread')
149 g.writeln('\t\tvoid* live_fn_mutex_addr = v_live_fn_mutex_ptr();')
150 g.writeln('\t\tv__live__LiveReloadInfo* live_info = v__live__executable__new_live_reload_info(')
151 g.writeln('\t\t\t\t\t builtin__tos2("${file}"),')
152 g.writeln('\t\t\t\t\t builtin__tos2("${vexe}"),')
153 g.writeln('\t\t\t\t\t builtin__tos2("${vopts}"),')
154 g.writeln('\t\t\t\t\t live_fn_mutex_addr,')
155 g.writeln('\t\t\t\t\t v_bind_live_symbols')
156 g.writeln('\t\t);')
157 mut already_added := map[string]bool{}
158 for f in g.hotcode_fpaths {
159 already_added[f] = true
160 }
161 mut idx := 0
162 for f, _ in already_added {
163 fpath := os.real_path(f)
164 g.writeln('\t\tv__live__executable__add_live_monitored_file(live_info, ${ctoslit(fpath)}); // source V file with @[live] ${
165 idx + 1}/${already_added.len}')
166 idx++
167 }
168 g.writeln('')
169 // g_live_reload_info gives access to the LiveReloadInfo methods,
170 // to the custom user code, through calling v_live_info()
171 g.writeln('\t\tg_live_reload_info = (void*)live_info;')
172 g.writeln('\t\tv__live__executable__start_reloader(live_info);')
173 g.writeln('\t}\t// end of live code initialization section')
174 g.writeln('')
175}
176