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')
|
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() {
|
fn testsuite_begin() {
|
||||||
eprintln('testsuite_begin, tfolder = $tfolder')
|
eprintln('testsuite_begin, tfolder = $tfolder')
|
||||||
os.rmdir_all(tfolder)
|
os.rmdir_all(tfolder)
|
||||||
|
@ -14,6 +18,9 @@ fn testsuite_begin() {
|
||||||
os.mkdir_all(tfolder)
|
os.mkdir_all(tfolder)
|
||||||
os.chdir(tfolder)
|
os.chdir(tfolder)
|
||||||
assert os.is_dir(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() {
|
fn testsuite_end() {
|
||||||
|
|
|
@ -36,7 +36,7 @@ mut:
|
||||||
typedefs2 strings.Builder
|
typedefs2 strings.Builder
|
||||||
type_definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
|
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)
|
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(){}`
|
cleanups map[string]strings.Builder // contents of `void _vcleanup(){}`
|
||||||
gowrappers strings.Builder // all go callsite wrappers
|
gowrappers strings.Builder // all go callsite wrappers
|
||||||
stringliterals strings.Builder // all string literals (they depend on tos3() beeing defined
|
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
|
// anon fn may include assert and thus this needs
|
||||||
// to be included before any test contents are written
|
// to be included before any test contents are written
|
||||||
if g.is_test && !tests_inited {
|
if g.is_test && !tests_inited {
|
||||||
g.write_tests_main()
|
g.write_tests_definitions()
|
||||||
tests_inited = true
|
tests_inited = true
|
||||||
}
|
}
|
||||||
g.stmts(file.stmts)
|
g.stmts(file.stmts)
|
||||||
|
@ -421,7 +421,9 @@ pub fn (mut g Gen) finish() {
|
||||||
if g.pref.is_livemain || g.pref.is_liveshared {
|
if g.pref.is_livemain || g.pref.is_liveshared {
|
||||||
g.generate_hotcode_reloader_code()
|
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()
|
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) {
|
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).
|
// (C doesn't allow init expressions that can't be resolved at compile time).
|
||||||
styp := g.typ(typ)
|
styp := g.typ(typ)
|
||||||
//
|
|
||||||
cname := '_const_$name'
|
cname := '_const_$name'
|
||||||
g.definitions.writeln('$styp $cname; // inited later')
|
g.definitions.writeln('$styp $cname; // inited later')
|
||||||
|
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;')
|
g.inits[mod].writeln('\t$cname = $val;')
|
||||||
|
}
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
if styp.starts_with('array_') {
|
if styp.starts_with('array_') {
|
||||||
g.cleanups[mod].writeln('\tarray_free(&$cname);')
|
g.cleanups[mod].writeln('\tarray_free(&$cname);')
|
||||||
|
@ -4697,14 +4706,8 @@ fn (mut g Gen) write_init_function() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fn_vinit_start_pos := g.out.len
|
fn_vinit_start_pos := g.out.len
|
||||||
needs_constructor := g.pref.is_shared && g.pref.os != .windows
|
// ___argv is declared as voidptr here, because that unifies the windows/unix logic
|
||||||
if needs_constructor {
|
g.writeln('void _vinit(int ___argc, voidptr ___argv) {')
|
||||||
g.writeln('__attribute__ ((constructor))')
|
|
||||||
g.writeln('void _vinit() {')
|
|
||||||
g.writeln('static bool once = false; if (once) {return;} once = true;')
|
|
||||||
} else {
|
|
||||||
g.writeln('void _vinit() {')
|
|
||||||
}
|
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
// Pre-allocate the string buffer
|
// Pre-allocate the string buffer
|
||||||
// s_str_buf_size := os.getenv('V_STRBUF_MB')
|
// 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))
|
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 (
|
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;
|
byte* g_str_buf;
|
||||||
int load_so(byteptr);
|
int load_so(byteptr);
|
||||||
void reload_so();
|
void reload_so();
|
||||||
void _vinit();
|
void _vinit(int ___argc, voidptr ___argv);
|
||||||
void _vcleanup();
|
void _vcleanup();
|
||||||
#define sigaction_size sizeof(sigaction);
|
#define sigaction_size sizeof(sigaction);
|
||||||
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
#define _ARR_LEN(a) ( (sizeof(a)) / (sizeof(a[0])) )
|
||||||
|
|
|
@ -49,6 +49,12 @@ fn (mut g Gen) gen_c_main_function_header() {
|
||||||
}
|
}
|
||||||
// GUI application
|
// GUI application
|
||||||
g.writeln('int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, LPWSTR cmd_line, int show_cmd){')
|
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 {
|
} else {
|
||||||
// Console application
|
// Console application
|
||||||
g.writeln('int wmain(int ___argc, wchar_t* ___argv[], wchar_t* ___envp[]){')
|
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() {
|
fn (mut g Gen) gen_c_main_header() {
|
||||||
g.gen_c_main_function_header()
|
g.gen_c_main_function_header()
|
||||||
if g.pref.os == .windows && g.is_gui_app() {
|
g.writeln('\t_vinit(___argc, (voidptr)___argv);')
|
||||||
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();')
|
|
||||||
if g.pref.is_prof {
|
if g.pref.is_prof {
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
g.writeln('\tatexit(vprint_profile_stats);')
|
g.writeln('\tatexit(vprint_profile_stats);')
|
||||||
g.writeln('')
|
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 {
|
if g.pref.is_livemain {
|
||||||
g.generate_hotcode_reloading_main_caller()
|
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[]) {
|
sapp_desc sokol_main(int argc, char* argv[]) {
|
||||||
(void)argc; (void)argv;
|
(void)argc; (void)argv;
|
||||||
|
|
||||||
_vinit();
|
_vinit(argc, (voidptr)argv);
|
||||||
main__main();
|
main__main();
|
||||||
')
|
')
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
|
@ -142,21 +130,24 @@ sapp_desc sokol_main(int argc, char* argv[]) {
|
||||||
g.writeln('}')
|
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.includes.writeln('#include <setjmp.h> // write_tests_main')
|
||||||
g.definitions.writeln('int g_test_oks = 0;')
|
g.definitions.writeln('int g_test_oks = 0;')
|
||||||
g.definitions.writeln('int g_test_fails = 0;')
|
g.definitions.writeln('int g_test_fails = 0;')
|
||||||
g.definitions.writeln('jmp_buf g_jump_buffer;')
|
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
|
main_fn_start_pos := g.out.len
|
||||||
g.gen_c_main_function_header()
|
|
||||||
g.writeln('\t_vinit();')
|
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
|
g.gen_c_main_function_header()
|
||||||
|
g.writeln('\t_vinit(___argc, (voidptr)___argv);')
|
||||||
all_tfuncs := g.get_all_test_function_names()
|
all_tfuncs := g.get_all_test_function_names()
|
||||||
if g.pref.is_stats {
|
if g.pref.is_stats {
|
||||||
g.writeln('\tmain__BenchedTests bt = main__start_testing($all_tfuncs.len, _SLIT("$g.pref.path"));')
|
g.writeln('\tmain__BenchedTests bt = main__start_testing($all_tfuncs.len, _SLIT("$g.pref.path"));')
|
||||||
}
|
}
|
||||||
for t in all_tfuncs {
|
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
|
for t in all_tfuncs {
|
||||||
if g.pref.is_stats {
|
if g.pref.is_stats {
|
||||||
g.writeln('\tmain__BenchedTests_testing_step_start(&bt, _SLIT("$t"));')
|
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 {
|
if g.pref.is_stats {
|
||||||
g.writeln('\tmain__BenchedTests_end_testing(&bt);')
|
g.writeln('\tmain__BenchedTests_end_testing(&bt);')
|
||||||
}
|
}
|
||||||
g.writeln('')
|
|
||||||
if g.is_autofree {
|
if g.is_autofree {
|
||||||
g.writeln('\t_vcleanup();')
|
g.writeln('\t_vcleanup();')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue