cgen: fix os.args initialization, so that `const x = os.args[0]` works
parent
0081e5740d
commit
722a603222
|
@ -7,6 +7,10 @@ const (
|
|||
tfolder = os.join_path(os.temp_dir(), 'v', 'tests', 'os_test')
|
||||
)
|
||||
|
||||
// os.args has to be *already initialized* with the program's argc/argv at this point
|
||||
// thus it can be used for other consts too:
|
||||
const args_at_start = os.args.clone()
|
||||
|
||||
fn testsuite_begin() {
|
||||
eprintln('testsuite_begin, tfolder = $tfolder')
|
||||
os.rmdir_all(tfolder)
|
||||
|
@ -14,6 +18,9 @@ fn testsuite_begin() {
|
|||
os.mkdir_all(tfolder)
|
||||
os.chdir(tfolder)
|
||||
assert os.is_dir(tfolder)
|
||||
// println('args_at_start: $args_at_start')
|
||||
assert args_at_start.len > 0
|
||||
assert args_at_start == os.args
|
||||
}
|
||||
|
||||
fn testsuite_end() {
|
||||
|
|
|
@ -36,7 +36,7 @@ mut:
|
|||
typedefs2 strings.Builder
|
||||
type_definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
||||
definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
||||
inits map[string]strings.Builder // contents of `void _vinit(){}`
|
||||
inits map[string]strings.Builder // contents of `void _vinit/2{}`
|
||||
cleanups map[string]strings.Builder // contents of `void _vcleanup(){}`
|
||||
gowrappers strings.Builder // all go callsite wrappers
|
||||
stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined
|
||||
|
@ -224,7 +224,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
|||
// anon fn may include assert and thus this needs
|
||||
// to be included before any test contents are written
|
||||
if g.is_test && !tests_inited {
|
||||
g.write_tests_main()
|
||||
g.write_tests_definitions()
|
||||
tests_inited = true
|
||||
}
|
||||
g.stmts(file.stmts)
|
||||
|
@ -421,7 +421,9 @@ pub fn (mut g Gen) finish() {
|
|||
if g.pref.is_livemain || g.pref.is_liveshared {
|
||||
g.generate_hotcode_reloader_code()
|
||||
}
|
||||
if !g.pref.is_test {
|
||||
if g.pref.is_test {
|
||||
g.gen_c_main_for_tests()
|
||||
} else {
|
||||
g.gen_c_main()
|
||||
}
|
||||
}
|
||||
|
@ -4397,13 +4399,20 @@ fn (mut g Gen) const_decl_simple_define(name string, val string) {
|
|||
}
|
||||
|
||||
fn (mut g Gen) const_decl_init_later(mod string, name string, val string, typ table.Type) {
|
||||
// Initialize more complex consts in `void _vinit(){}`
|
||||
// Initialize more complex consts in `void _vinit/2{}`
|
||||
// (C doesn't allow init expressions that can't be resolved at compile time).
|
||||
styp := g.typ(typ)
|
||||
//
|
||||
cname := '_const_$name'
|
||||
g.definitions.writeln('$styp $cname; // inited later')
|
||||
g.inits[mod].writeln('\t$cname = $val;')
|
||||
if cname == '_const_os__args' {
|
||||
if g.pref.os == .windows {
|
||||
g.inits[mod].writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);')
|
||||
} else {
|
||||
g.inits[mod].writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
|
||||
}
|
||||
} else {
|
||||
g.inits[mod].writeln('\t$cname = $val;')
|
||||
}
|
||||
if g.is_autofree {
|
||||
if styp.starts_with('array_') {
|
||||
g.cleanups[mod].writeln('\tarray_free(&$cname);')
|
||||
|
@ -4697,14 +4706,8 @@ fn (mut g Gen) write_init_function() {
|
|||
return
|
||||
}
|
||||
fn_vinit_start_pos := g.out.len
|
||||
needs_constructor := g.pref.is_shared && g.pref.os != .windows
|
||||
if needs_constructor {
|
||||
g.writeln('__attribute__ ((constructor))')
|
||||
g.writeln('void _vinit() {')
|
||||
g.writeln('static bool once = false; if (once) {return;} once = true;')
|
||||
} else {
|
||||
g.writeln('void _vinit() {')
|
||||
}
|
||||
// ___argv is declared as voidptr here, because that unifies the windows/unix logic
|
||||
g.writeln('void _vinit(int ___argc, voidptr ___argv) {')
|
||||
if g.is_autofree {
|
||||
// Pre-allocate the string buffer
|
||||
// s_str_buf_size := os.getenv('V_STRBUF_MB')
|
||||
|
@ -4750,6 +4753,17 @@ fn (mut g Gen) write_init_function() {
|
|||
println(g.out.after(fn_vcleanup_start_pos))
|
||||
}
|
||||
}
|
||||
needs_constructor := g.pref.is_shared && g.pref.os != .windows
|
||||
if needs_constructor {
|
||||
// shared libraries need a way to call _vinit/2. For that purpose,
|
||||
// provide a constructor, ensuring that all constants are initialized just once.
|
||||
// NB: os.args in this case will be [].
|
||||
g.writeln('__attribute__ ((constructor))')
|
||||
g.writeln('void _vinit_caller() {')
|
||||
g.writeln('\tstatic bool once = false; if (once) {return;} once = true;')
|
||||
g.writeln('\t_vinit(0,0);')
|
||||
g.writeln('}')
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -306,7 +306,7 @@ static inline bool _us64_lt(uint64_t a, int64_t b) { return a < INT64_MAX && (in
|
|||
byte* g_str_buf;
|
||||
int load_so(byteptr);
|
||||
void reload_so();
|
||||
void _vinit();
|
||||
void _vinit(int ___argc, voidptr ___argv);
|
||||
void _vcleanup();
|
||||
#define sigaction_size sizeof(sigaction);
|
||||
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
||||
|
|
|
@ -49,6 +49,12 @@ fn (mut g Gen) gen_c_main_function_header() {
|
|||
}
|
||||
// GUI application
|
||||
g.writeln('int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, LPWSTR cmd_line, int show_cmd){')
|
||||
g.writeln('\tLPWSTR full_cmd_line = GetCommandLineW(); // NB: do not use cmd_line')
|
||||
g.writeln('\ttypedef LPWSTR*(WINAPI *cmd_line_to_argv)(LPCWSTR, int*);')
|
||||
g.writeln('\tHMODULE shell32_module = LoadLibrary(L"shell32.dll");')
|
||||
g.writeln('\tcmd_line_to_argv CommandLineToArgvW = (cmd_line_to_argv)GetProcAddress(shell32_module, "CommandLineToArgvW");')
|
||||
g.writeln('\tint ___argc;')
|
||||
g.writeln('\twchar_t** ___argv = CommandLineToArgvW(full_cmd_line, &___argc);')
|
||||
} else {
|
||||
// Console application
|
||||
g.writeln('int wmain(int ___argc, wchar_t* ___argv[], wchar_t* ___envp[]){')
|
||||
|
@ -60,30 +66,12 @@ fn (mut g Gen) gen_c_main_function_header() {
|
|||
|
||||
fn (mut g Gen) gen_c_main_header() {
|
||||
g.gen_c_main_function_header()
|
||||
if g.pref.os == .windows && g.is_gui_app() {
|
||||
g.writeln('\tLPWSTR full_cmd_line = GetCommandLineW(); // NB: do not use cmd_line')
|
||||
g.writeln('\ttypedef LPWSTR*(WINAPI *cmd_line_to_argv)(LPCWSTR, int*);')
|
||||
g.writeln('\tHMODULE shell32_module = LoadLibrary(L"shell32.dll");')
|
||||
g.writeln('\tcmd_line_to_argv CommandLineToArgvW = (cmd_line_to_argv)GetProcAddress(shell32_module, "CommandLineToArgvW");')
|
||||
g.writeln('\tint ___argc;')
|
||||
g.writeln('\twchar_t** ___argv = CommandLineToArgvW(full_cmd_line, &___argc);')
|
||||
}
|
||||
g.writeln('\t_vinit();')
|
||||
g.writeln('\t_vinit(___argc, (voidptr)___argv);')
|
||||
if g.pref.is_prof {
|
||||
g.writeln('')
|
||||
g.writeln('\tatexit(vprint_profile_stats);')
|
||||
g.writeln('')
|
||||
}
|
||||
if g.is_importing_os() {
|
||||
if g.is_autofree {
|
||||
g.writeln('free(_const_os__args.data); // empty, inited in _vinit()')
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
g.writeln('\t_const_os__args = os__init_os_args_wide(___argc, ___argv);')
|
||||
} else {
|
||||
g.writeln('\t_const_os__args = os__init_os_args(___argc, (byteptr*)___argv);')
|
||||
}
|
||||
}
|
||||
if g.pref.is_livemain {
|
||||
g.generate_hotcode_reloading_main_caller()
|
||||
}
|
||||
|
@ -123,7 +111,7 @@ void (_vsokol_cleanup_userdata_cb)(void* user_data) {
|
|||
sapp_desc sokol_main(int argc, char* argv[]) {
|
||||
(void)argc; (void)argv;
|
||||
|
||||
_vinit();
|
||||
_vinit(argc, (voidptr)argv);
|
||||
main__main();
|
||||
')
|
||||
if g.is_autofree {
|
||||
|
@ -142,21 +130,24 @@ sapp_desc sokol_main(int argc, char* argv[]) {
|
|||
g.writeln('}')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) write_tests_main() {
|
||||
pub fn (mut g Gen) write_tests_definitions() {
|
||||
g.includes.writeln('#include <setjmp.h> // write_tests_main')
|
||||
g.definitions.writeln('int g_test_oks = 0;')
|
||||
g.definitions.writeln('int g_test_fails = 0;')
|
||||
g.definitions.writeln('jmp_buf g_jump_buffer;')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_c_main_for_tests() {
|
||||
main_fn_start_pos := g.out.len
|
||||
g.gen_c_main_function_header()
|
||||
g.writeln('\t_vinit();')
|
||||
g.writeln('')
|
||||
g.gen_c_main_function_header()
|
||||
g.writeln('\t_vinit(___argc, (voidptr)___argv);')
|
||||
all_tfuncs := g.get_all_test_function_names()
|
||||
if g.pref.is_stats {
|
||||
g.writeln('\tmain__BenchedTests bt = main__start_testing($all_tfuncs.len, _SLIT("$g.pref.path"));')
|
||||
}
|
||||
g.writeln('')
|
||||
for t in all_tfuncs {
|
||||
g.writeln('')
|
||||
if g.pref.is_stats {
|
||||
g.writeln('\tmain__BenchedTests_testing_step_start(&bt, _SLIT("$t"));')
|
||||
}
|
||||
|
@ -169,7 +160,6 @@ pub fn (mut g Gen) write_tests_main() {
|
|||
if g.pref.is_stats {
|
||||
g.writeln('\tmain__BenchedTests_end_testing(&bt);')
|
||||
}
|
||||
g.writeln('')
|
||||
if g.is_autofree {
|
||||
g.writeln('\t_vcleanup();')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue