mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: refactoring - extract cheaders.v and live.v from main.v .
This commit is contained in:
parent
cf23c289ec
commit
9ff8793666
108
compiler/cheaders.v
Normal file
108
compiler/cheaders.v
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
CommonCHeaders = '
|
||||||
|
|
||||||
|
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdarg.h> // for va_list
|
||||||
|
#include <inttypes.h> // int64_t etc
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
|
#define STRUCT_DEFAULT_VALUE {}
|
||||||
|
#define EMPTY_STRUCT_DECLARATION
|
||||||
|
#define EMPTY_STRUCT_INIT
|
||||||
|
#define OPTION_CAST(x) (x)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// must be included after <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
|
||||||
|
#include <io.h> // _waccess
|
||||||
|
#include <fcntl.h> // _O_U8TEXT
|
||||||
|
#include <direct.h> // _wgetcwd
|
||||||
|
//#include <WinSock2.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// On MSVC these are the same (as long as /volatile:ms is passed)
|
||||||
|
#define _Atomic volatile
|
||||||
|
|
||||||
|
// MSVC can\'t parse some things properly
|
||||||
|
#undef STRUCT_DEFAULT_VALUE
|
||||||
|
#define STRUCT_DEFAULT_VALUE {0}
|
||||||
|
#undef EMPTY_STRUCT_DECLARATION
|
||||||
|
#define EMPTY_STRUCT_DECLARATION void *____dummy_variable;
|
||||||
|
#undef EMPTY_STRUCT_INIT
|
||||||
|
#define EMPTY_STRUCT_INIT 0
|
||||||
|
#undef OPTION_CAST
|
||||||
|
#define OPTION_CAST(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void pthread_mutex_lock(HANDLE *m) {
|
||||||
|
WaitForSingleObject(*m, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pthread_mutex_unlock(HANDLE *m) {
|
||||||
|
ReleaseMutex(*m);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//================================== TYPEDEFS ================================*/
|
||||||
|
|
||||||
|
typedef unsigned char byte;
|
||||||
|
typedef unsigned int uint;
|
||||||
|
typedef int64_t i64;
|
||||||
|
typedef int32_t i32;
|
||||||
|
typedef int16_t i16;
|
||||||
|
typedef int8_t i8;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint32_t rune;
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
typedef unsigned char* byteptr;
|
||||||
|
typedef int* intptr;
|
||||||
|
typedef void* voidptr;
|
||||||
|
typedef struct array array;
|
||||||
|
typedef struct map map;
|
||||||
|
typedef array array_string;
|
||||||
|
typedef array array_int;
|
||||||
|
typedef array array_byte;
|
||||||
|
typedef array array_uint;
|
||||||
|
typedef array array_float;
|
||||||
|
typedef array array_f32;
|
||||||
|
typedef array array_f64;
|
||||||
|
typedef map map_int;
|
||||||
|
typedef map map_string;
|
||||||
|
#ifndef bool
|
||||||
|
typedef int bool;
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//============================== HELPER C MACROS =============================*/
|
||||||
|
|
||||||
|
#define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);}
|
||||||
|
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push_many(arr, tmp.data, tmp.len);}
|
||||||
|
#define _IN(typ, val, arr) array_##typ##_contains(arr, val)
|
||||||
|
#define _IN_MAP(val, m) map__exists(m, val)
|
||||||
|
#define ALLOC_INIT(type, ...) (type *)memdup((type[]){ __VA_ARGS__ }, sizeof(type))
|
||||||
|
|
||||||
|
//================================== GLOBALS =================================*/
|
||||||
|
//int V_ZERO = 0;
|
||||||
|
byteptr g_str_buf;
|
||||||
|
int load_so(byteptr);
|
||||||
|
void reload_so();
|
||||||
|
void init_consts();
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
)
|
182
compiler/live.v
Normal file
182
compiler/live.v
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
fn (v mut V) generate_hotcode_reloading_compiler_flags() []string {
|
||||||
|
mut a := []string
|
||||||
|
if v.pref.is_live || v.pref.is_so {
|
||||||
|
// See 'man dlopen', and test running a GUI program compiled with -live
|
||||||
|
if (v.os == .linux || os.user_os() == 'linux'){
|
||||||
|
a << '-rdynamic'
|
||||||
|
}
|
||||||
|
if (v.os == .mac || os.user_os() == 'mac'){
|
||||||
|
a << '-flat_namespace'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (v mut V) generate_hotcode_reloading_declarations() {
|
||||||
|
mut cgen := v.cgen
|
||||||
|
if v.os != .windows && v.os != .msvc {
|
||||||
|
if v.pref.is_so {
|
||||||
|
cgen.genln('pthread_mutex_t live_fn_mutex;')
|
||||||
|
}
|
||||||
|
if v.pref.is_live {
|
||||||
|
cgen.genln('pthread_mutex_t live_fn_mutex = PTHREAD_MUTEX_INITIALIZER;')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if v.pref.is_so {
|
||||||
|
cgen.genln('HANDLE live_fn_mutex;')
|
||||||
|
}
|
||||||
|
if v.pref.is_live {
|
||||||
|
cgen.genln('HANDLE live_fn_mutex = 0;')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (v mut V) generate_hotcode_reloading_code() {
|
||||||
|
mut cgen := v.cgen
|
||||||
|
|
||||||
|
// Hot code reloading
|
||||||
|
if v.pref.is_live {
|
||||||
|
file := v.dir
|
||||||
|
file_base := v.dir.replace('.v', '')
|
||||||
|
so_name := file_base + '.so'
|
||||||
|
// Need to build .so file before building the live application
|
||||||
|
// The live app needs to load this .so file on initialization.
|
||||||
|
mut vexe := os.args[0]
|
||||||
|
|
||||||
|
if os.user_os() == 'windows' {
|
||||||
|
vexe = vexe.replace('\\', '\\\\')
|
||||||
|
}
|
||||||
|
|
||||||
|
mut msvc := ''
|
||||||
|
if v.os == .msvc {
|
||||||
|
msvc = '-os msvc'
|
||||||
|
}
|
||||||
|
|
||||||
|
mut debug := ''
|
||||||
|
|
||||||
|
if v.pref.is_debug {
|
||||||
|
debug = '-debug'
|
||||||
|
}
|
||||||
|
|
||||||
|
os.system('$vexe $msvc $debug -o $file_base -shared $file')
|
||||||
|
cgen.genln('
|
||||||
|
|
||||||
|
void lfnmutex_print(char *s){
|
||||||
|
if(0){
|
||||||
|
fflush(stderr);
|
||||||
|
fprintf(stderr,">> live_fn_mutex: %p | %s\\n", &live_fn_mutex, s);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
')
|
||||||
|
|
||||||
|
if v.os != .windows && v.os != .msvc {
|
||||||
|
cgen.genln('
|
||||||
|
#include <dlfcn.h>
|
||||||
|
void* live_lib=0;
|
||||||
|
int load_so(byteptr path) {
|
||||||
|
char cpath[1024];
|
||||||
|
sprintf(cpath,"./%s", path);
|
||||||
|
//printf("load_so %s\\n", cpath);
|
||||||
|
if (live_lib) dlclose(live_lib);
|
||||||
|
live_lib = dlopen(cpath, RTLD_LAZY);
|
||||||
|
if (!live_lib) {
|
||||||
|
puts("open failed");
|
||||||
|
exit(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
')
|
||||||
|
for so_fn in cgen.so_fns {
|
||||||
|
cgen.genln('$so_fn = dlsym(live_lib, "$so_fn"); ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cgen.genln('
|
||||||
|
void* live_lib=0;
|
||||||
|
int load_so(byteptr path) {
|
||||||
|
char cpath[1024];
|
||||||
|
sprintf(cpath, "./%s", path);
|
||||||
|
if (live_lib) FreeLibrary(live_lib);
|
||||||
|
live_lib = LoadLibraryA(cpath);
|
||||||
|
if (!live_lib) {
|
||||||
|
puts("open failed");
|
||||||
|
exit(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
')
|
||||||
|
|
||||||
|
for so_fn in cgen.so_fns {
|
||||||
|
cgen.genln('$so_fn = (void *)GetProcAddress(live_lib, "$so_fn"); ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cgen.genln('return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _live_reloads = 0;
|
||||||
|
void reload_so() {
|
||||||
|
char new_so_base[1024];
|
||||||
|
char new_so_name[1024];
|
||||||
|
char compile_cmd[1024];
|
||||||
|
int last = os__file_last_mod_unix(tos2("$file"));
|
||||||
|
while (1) {
|
||||||
|
// TODO use inotify
|
||||||
|
int now = os__file_last_mod_unix(tos2("$file"));
|
||||||
|
if (now != last) {
|
||||||
|
last = now;
|
||||||
|
_live_reloads++;
|
||||||
|
|
||||||
|
//v -o bounce -shared bounce.v
|
||||||
|
sprintf(new_so_base, ".tmp.%d.${file_base}", _live_reloads);
|
||||||
|
#ifdef _WIN32
|
||||||
|
// We have to make this directory becuase windows WILL NOT
|
||||||
|
// do it for us
|
||||||
|
os__mkdir(string_all_before_last(tos2(new_so_base), tos2("/")));
|
||||||
|
#endif
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
sprintf(new_so_name, "%s.dll", new_so_base);
|
||||||
|
#else
|
||||||
|
sprintf(new_so_name, "%s.so", new_so_base);
|
||||||
|
#endif
|
||||||
|
sprintf(compile_cmd, "$vexe $msvc -o %s -shared $file", new_so_base);
|
||||||
|
os__system(tos2(compile_cmd));
|
||||||
|
|
||||||
|
if( !os__file_exists(tos2(new_so_name)) ) {
|
||||||
|
fprintf(stderr, "Errors while compiling $file\\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfnmutex_print("reload_so locking...");
|
||||||
|
pthread_mutex_lock(&live_fn_mutex);
|
||||||
|
lfnmutex_print("reload_so locked");
|
||||||
|
|
||||||
|
live_lib = 0; // hack: force skipping dlclose/1, the code may be still used...
|
||||||
|
load_so(new_so_name);
|
||||||
|
#ifndef _WIN32
|
||||||
|
unlink(new_so_name); // removing the .so file from the filesystem after dlopen-ing it is safe, since it will still be mapped in memory.
|
||||||
|
#else
|
||||||
|
_unlink(new_so_name);
|
||||||
|
#endif
|
||||||
|
//if(0 == rename(new_so_name, "${so_name}")){
|
||||||
|
// load_so("${so_name}");
|
||||||
|
//}
|
||||||
|
|
||||||
|
lfnmutex_print("reload_so unlocking...");
|
||||||
|
pthread_mutex_unlock(&live_fn_mutex);
|
||||||
|
lfnmutex_print("reload_so unlocked");
|
||||||
|
|
||||||
|
}
|
||||||
|
time__sleep_ms(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' )
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.pref.is_so {
|
||||||
|
cgen.genln(' int load_so(byteptr path) { return 0; }')
|
||||||
|
}
|
||||||
|
}
|
298
compiler/main.v
298
compiler/main.v
@ -243,123 +243,11 @@ fn (v mut V) compile() {
|
|||||||
if v.pref.is_debug {
|
if v.pref.is_debug {
|
||||||
cgen.genln('#define VDEBUG (1) ')
|
cgen.genln('#define VDEBUG (1) ')
|
||||||
}
|
}
|
||||||
cgen.genln('
|
|
||||||
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually
|
cgen.genln(CommonCHeaders)
|
||||||
#include <stdlib.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdarg.h> // for va_list
|
|
||||||
#include <inttypes.h> // int64_t etc
|
|
||||||
#include <string.h> // memcpy
|
|
||||||
|
|
||||||
#define STRUCT_DEFAULT_VALUE {}
|
|
||||||
#define EMPTY_STRUCT_DECLARATION
|
|
||||||
#define EMPTY_STRUCT_INIT
|
|
||||||
#define OPTION_CAST(x) (x)
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// must be included after <windows.h>
|
|
||||||
#include <shellapi.h>
|
|
||||||
|
|
||||||
#include <io.h> // _waccess
|
|
||||||
#include <fcntl.h> // _O_U8TEXT
|
|
||||||
#include <direct.h> // _wgetcwd
|
|
||||||
//#include <WinSock2.h>
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// On MSVC these are the same (as long as /volatile:ms is passed)
|
|
||||||
#define _Atomic volatile
|
|
||||||
|
|
||||||
// MSVC can\'t parse some things properly
|
|
||||||
#undef STRUCT_DEFAULT_VALUE
|
|
||||||
#define STRUCT_DEFAULT_VALUE {0}
|
|
||||||
#undef EMPTY_STRUCT_DECLARATION
|
|
||||||
#define EMPTY_STRUCT_DECLARATION void *____dummy_variable;
|
|
||||||
#undef EMPTY_STRUCT_INIT
|
|
||||||
#define EMPTY_STRUCT_INIT 0
|
|
||||||
#undef OPTION_CAST
|
|
||||||
#define OPTION_CAST(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void pthread_mutex_lock(HANDLE *m) {
|
|
||||||
WaitForSingleObject(*m, INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pthread_mutex_unlock(HANDLE *m) {
|
|
||||||
ReleaseMutex(*m);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//================================== TYPEDEFS ================================*/
|
|
||||||
|
|
||||||
typedef unsigned char byte;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef int64_t i64;
|
|
||||||
typedef int32_t i32;
|
|
||||||
typedef int16_t i16;
|
|
||||||
typedef int8_t i8;
|
|
||||||
typedef uint64_t u64;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef uint32_t rune;
|
|
||||||
typedef float f32;
|
|
||||||
typedef double f64;
|
|
||||||
typedef unsigned char* byteptr;
|
|
||||||
typedef int* intptr;
|
|
||||||
typedef void* voidptr;
|
|
||||||
typedef struct array array;
|
|
||||||
typedef struct map map;
|
|
||||||
typedef array array_string;
|
|
||||||
typedef array array_int;
|
|
||||||
typedef array array_byte;
|
|
||||||
typedef array array_uint;
|
|
||||||
typedef array array_float;
|
|
||||||
typedef array array_f32;
|
|
||||||
typedef array array_f64;
|
|
||||||
typedef map map_int;
|
|
||||||
typedef map map_string;
|
|
||||||
#ifndef bool
|
|
||||||
typedef int bool;
|
|
||||||
#define true 1
|
|
||||||
#define false 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//============================== HELPER C MACROS =============================*/
|
|
||||||
|
|
||||||
#define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);}
|
|
||||||
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push_many(arr, tmp.data, tmp.len);}
|
|
||||||
#define _IN(typ, val, arr) array_##typ##_contains(arr, val)
|
|
||||||
#define _IN_MAP(val, m) map__exists(m, val)
|
|
||||||
#define ALLOC_INIT(type, ...) (type *)memdup((type[]){ __VA_ARGS__ }, sizeof(type))
|
|
||||||
|
|
||||||
//================================== GLOBALS =================================*/
|
|
||||||
//int V_ZERO = 0;
|
|
||||||
byteptr g_str_buf;
|
|
||||||
int load_so(byteptr);
|
|
||||||
void reload_so();
|
|
||||||
void init_consts();')
|
|
||||||
|
|
||||||
if v.os != .windows && v.os != .msvc {
|
|
||||||
if v.pref.is_so {
|
|
||||||
cgen.genln('pthread_mutex_t live_fn_mutex;')
|
|
||||||
}
|
|
||||||
if v.pref.is_live {
|
|
||||||
cgen.genln('pthread_mutex_t live_fn_mutex = PTHREAD_MUTEX_INITIALIZER;')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if v.pref.is_so {
|
|
||||||
cgen.genln('HANDLE live_fn_mutex;')
|
|
||||||
}
|
|
||||||
if v.pref.is_live {
|
|
||||||
cgen.genln('HANDLE live_fn_mutex = 0;')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
v.generate_hotcode_reloading_declarations()
|
||||||
|
|
||||||
imports_json := v.table.imports.contains('json')
|
imports_json := v.table.imports.contains('json')
|
||||||
// TODO remove global UI hack
|
// TODO remove global UI hack
|
||||||
if v.os == .mac && ((v.pref.build_mode == .embed_vlib && v.table.imports.contains('ui')) ||
|
if v.os == .mac && ((v.pref.build_mode == .embed_vlib && v.table.imports.contains('ui')) ||
|
||||||
@ -422,6 +310,22 @@ void init_consts();')
|
|||||||
}
|
}
|
||||||
dd := d.str()
|
dd := d.str()
|
||||||
cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile
|
cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile
|
||||||
|
|
||||||
|
v.generate_main()
|
||||||
|
|
||||||
|
v.generate_hotcode_reloading_code()
|
||||||
|
|
||||||
|
cgen.save()
|
||||||
|
if v.pref.is_verbose {
|
||||||
|
v.log('flags=')
|
||||||
|
println(v.table.flags)
|
||||||
|
}
|
||||||
|
v.cc()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (v mut V) generate_main() {
|
||||||
|
mut cgen := v.cgen
|
||||||
|
|
||||||
// if v.build_mode in [.default, .embed_vlib] {
|
// if v.build_mode in [.default, .embed_vlib] {
|
||||||
if v.pref.build_mode == .default_mode || v.pref.build_mode == .embed_vlib {
|
if v.pref.build_mode == .default_mode || v.pref.build_mode == .embed_vlib {
|
||||||
mut consts_init_body := cgen.consts_init.join_lines()
|
mut consts_init_body := cgen.consts_init.join_lines()
|
||||||
@ -477,6 +381,7 @@ string _STR_TMP(const char *fmt, ...) {
|
|||||||
|
|
||||||
')
|
')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the main function exists
|
// Make sure the main function exists
|
||||||
// Obviously we don't need it in libraries
|
// Obviously we don't need it in libraries
|
||||||
if v.pref.build_mode != .build {
|
if v.pref.build_mode != .build {
|
||||||
@ -496,7 +401,7 @@ string _STR_TMP(const char *fmt, ...) {
|
|||||||
// Generate `main` which calls every single test function
|
// Generate `main` which calls every single test function
|
||||||
else if v.pref.is_test {
|
else if v.pref.is_test {
|
||||||
cgen.genln('int main() { init_consts();')
|
cgen.genln('int main() { init_consts();')
|
||||||
for key, f in v.table.fns {
|
for _, f in v.table.fns {
|
||||||
if f.name.starts_with('test_') {
|
if f.name.starts_with('test_') {
|
||||||
cgen.genln('$f.name();')
|
cgen.genln('$f.name();')
|
||||||
}
|
}
|
||||||
@ -504,153 +409,6 @@ string _STR_TMP(const char *fmt, ...) {
|
|||||||
cgen.genln('return g_test_ok == 0; }')
|
cgen.genln('return g_test_ok == 0; }')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Hot code reloading
|
|
||||||
if v.pref.is_live {
|
|
||||||
file := v.dir
|
|
||||||
file_base := v.dir.replace('.v', '')
|
|
||||||
so_name := file_base + '.so'
|
|
||||||
// Need to build .so file before building the live application
|
|
||||||
// The live app needs to load this .so file on initialization.
|
|
||||||
mut vexe := os.args[0]
|
|
||||||
|
|
||||||
if os.user_os() == 'windows' {
|
|
||||||
vexe = vexe.replace('\\', '\\\\')
|
|
||||||
}
|
|
||||||
|
|
||||||
mut msvc := ''
|
|
||||||
if v.os == .msvc {
|
|
||||||
msvc = '-os msvc'
|
|
||||||
}
|
|
||||||
|
|
||||||
mut debug := ''
|
|
||||||
|
|
||||||
if v.pref.is_debug {
|
|
||||||
debug = '-debug'
|
|
||||||
}
|
|
||||||
|
|
||||||
os.system('$vexe $msvc $debug -o $file_base -shared $file')
|
|
||||||
cgen.genln('
|
|
||||||
|
|
||||||
void lfnmutex_print(char *s){
|
|
||||||
if(0){
|
|
||||||
fflush(stderr);
|
|
||||||
fprintf(stderr,">> live_fn_mutex: %p | %s\\n", &live_fn_mutex, s);
|
|
||||||
fflush(stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
')
|
|
||||||
|
|
||||||
if v.os != .windows && v.os != .msvc {
|
|
||||||
cgen.genln('
|
|
||||||
#include <dlfcn.h>
|
|
||||||
void* live_lib=0;
|
|
||||||
int load_so(byteptr path) {
|
|
||||||
char cpath[1024];
|
|
||||||
sprintf(cpath,"./%s", path);
|
|
||||||
//printf("load_so %s\\n", cpath);
|
|
||||||
if (live_lib) dlclose(live_lib);
|
|
||||||
live_lib = dlopen(cpath, RTLD_LAZY);
|
|
||||||
if (!live_lib) {
|
|
||||||
puts("open failed");
|
|
||||||
exit(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
')
|
|
||||||
for so_fn in cgen.so_fns {
|
|
||||||
cgen.genln('$so_fn = dlsym(live_lib, "$so_fn"); ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cgen.genln('
|
|
||||||
void* live_lib=0;
|
|
||||||
int load_so(byteptr path) {
|
|
||||||
char cpath[1024];
|
|
||||||
sprintf(cpath, "./%s", path);
|
|
||||||
if (live_lib) FreeLibrary(live_lib);
|
|
||||||
live_lib = LoadLibraryA(cpath);
|
|
||||||
if (!live_lib) {
|
|
||||||
puts("open failed");
|
|
||||||
exit(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
')
|
|
||||||
|
|
||||||
for so_fn in cgen.so_fns {
|
|
||||||
cgen.genln('$so_fn = (void *)GetProcAddress(live_lib, "$so_fn"); ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cgen.genln('return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _live_reloads = 0;
|
|
||||||
void reload_so() {
|
|
||||||
char new_so_base[1024];
|
|
||||||
char new_so_name[1024];
|
|
||||||
char compile_cmd[1024];
|
|
||||||
int last = os__file_last_mod_unix(tos2("$file"));
|
|
||||||
while (1) {
|
|
||||||
// TODO use inotify
|
|
||||||
int now = os__file_last_mod_unix(tos2("$file"));
|
|
||||||
if (now != last) {
|
|
||||||
last = now;
|
|
||||||
_live_reloads++;
|
|
||||||
|
|
||||||
//v -o bounce -shared bounce.v
|
|
||||||
sprintf(new_so_base, ".tmp.%d.${file_base}", _live_reloads);
|
|
||||||
#ifdef _WIN32
|
|
||||||
// We have to make this directory becuase windows WILL NOT
|
|
||||||
// do it for us
|
|
||||||
os__mkdir(string_all_before_last(tos2(new_so_base), tos2("/")));
|
|
||||||
#endif
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
sprintf(new_so_name, "%s.dll", new_so_base);
|
|
||||||
#else
|
|
||||||
sprintf(new_so_name, "%s.so", new_so_base);
|
|
||||||
#endif
|
|
||||||
sprintf(compile_cmd, "$vexe $msvc -o %s -shared $file", new_so_base);
|
|
||||||
os__system(tos2(compile_cmd));
|
|
||||||
|
|
||||||
if( !os__file_exists(tos2(new_so_name)) ) {
|
|
||||||
fprintf(stderr, "Errors while compiling $file\\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lfnmutex_print("reload_so locking...");
|
|
||||||
pthread_mutex_lock(&live_fn_mutex);
|
|
||||||
lfnmutex_print("reload_so locked");
|
|
||||||
|
|
||||||
live_lib = 0; // hack: force skipping dlclose/1, the code may be still used...
|
|
||||||
load_so(new_so_name);
|
|
||||||
#ifndef _WIN32
|
|
||||||
unlink(new_so_name); // removing the .so file from the filesystem after dlopen-ing it is safe, since it will still be mapped in memory.
|
|
||||||
#else
|
|
||||||
_unlink(new_so_name);
|
|
||||||
#endif
|
|
||||||
//if(0 == rename(new_so_name, "${so_name}")){
|
|
||||||
// load_so("${so_name}");
|
|
||||||
//}
|
|
||||||
|
|
||||||
lfnmutex_print("reload_so unlocking...");
|
|
||||||
pthread_mutex_unlock(&live_fn_mutex);
|
|
||||||
lfnmutex_print("reload_so unlocked");
|
|
||||||
|
|
||||||
}
|
|
||||||
time__sleep_ms(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
' )
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.pref.is_so {
|
|
||||||
cgen.genln(' int load_so(byteptr path) { return 0; }')
|
|
||||||
}
|
|
||||||
cgen.save()
|
|
||||||
if v.pref.is_verbose {
|
|
||||||
v.log('flags=')
|
|
||||||
println(v.table.flags)
|
|
||||||
}
|
|
||||||
v.cc()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn final_target_out_name(out_name string) string {
|
fn final_target_out_name(out_name string) string {
|
||||||
@ -790,15 +548,11 @@ fn (v mut V) cc() {
|
|||||||
else {
|
else {
|
||||||
a << '-g'
|
a << '-g'
|
||||||
}
|
}
|
||||||
if v.pref.is_live || v.pref.is_so {
|
|
||||||
// See 'man dlopen', and test running a GUI program compiled with -live
|
for f in v.generate_hotcode_reloading_compiler_flags() {
|
||||||
if (v.os == .linux || os.user_os() == 'linux'){
|
a << f
|
||||||
a << '-rdynamic'
|
|
||||||
}
|
|
||||||
if (v.os == .mac || os.user_os() == 'mac'){
|
|
||||||
a << '-flat_namespace'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mut libs := ''// builtin.o os.o http.o etc
|
mut libs := ''// builtin.o os.o http.o etc
|
||||||
if v.pref.build_mode == .build {
|
if v.pref.build_mode == .build {
|
||||||
a << '-c'
|
a << '-c'
|
||||||
|
Loading…
Reference in New Issue
Block a user