diff --git a/compiler/msvc.v b/compiler/msvc.v index a7e9f69e49..e0dfc57cf9 100644 --- a/compiler/msvc.v +++ b/compiler/msvc.v @@ -204,6 +204,11 @@ fn find_msvc() ?MsvcResult { } } +struct ParsedFlag { + f string + arg string +} + pub fn (v mut V) cc_msvc() { r := find_msvc() or { // TODO: code reuse @@ -296,31 +301,74 @@ pub fn (v mut V) cc_msvc() { // this is a hack to try and support -l -L and object files // passed on the command line for f in v.table.flags { - // We need to see if the flag contains -l - // -l isnt recognised and these libs will be passed straight to the linker - // by the compiler - if f.starts_with('-l') { - lib_base := f.right(2).trim_space() + // People like to put multiple flags per line (which really complicates things) + // ...so we need to handle that + mut rest := f - if lib_base.ends_with('.dll') { - panic('MSVC cannot link against a dll (`#flag -l $lib_base`)') + mut flags := []ParsedFlag{} + for { + mut base := rest + + fl := if rest.starts_with('-') { + base = rest.right(2).trim_space() + rest.left(2) + } else { + '' } - // MSVC has no method of linking against a .dll - // TODO: we should look for .defs aswell - lib_lib := lib_base + '.lib' - real_libs << lib_lib - } - else if f.starts_with('-L') { - lib_paths << f.right(2).trim_space() + // Which ever one of these is lowest we use + // TODO: we really shouldnt support all of these cmon + mut lowest := base.index('-') + for x in [base.index(' '), base.index(',')] { + if (x < lowest && x != -1) || lowest == -1 { + lowest = x + } + } + arg := if lowest != -1 { + rest = base.right(lowest).trim_space().trim(`,`) + base.left(lowest).trim_space().trim(`,`) + } else { + rest = '' + base.trim_space() + } + + flags << ParsedFlag { + fl, arg + } + + if rest.len == 0 { + break + } } - else if f.ends_with('.o') { - // msvc expects .obj not .o - other_flags << f + 'bj' - } - else { - other_flags << f + + for flag in flags { + fl := flag.f + arg := flag.arg + // We need to see if the flag contains -l + // -l isnt recognised and these libs will be passed straight to the linker + // by the compiler + if fl == '-l' { + if arg.ends_with('.dll') { + panic('MSVC cannot link against a dll (`#flag -l $arg`)') + } + + // MSVC has no method of linking against a .dll + // TODO: we should look for .defs aswell + lib_lib := arg + '.lib' + real_libs << lib_lib + } + else if fl == '-L' { + lib_paths << f.right(2).trim_space() + } + else if arg.ends_with('.o') { + // msvc expects .obj not .o + other_flags << arg + 'bj' + } + else { + other_flags << arg + } } + } // Include the base paths @@ -369,9 +417,10 @@ pub fn (v mut V) cc_msvc() { if !v.pref.is_debug && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' { os.rm('.$v.out_name_c') - os.rm('$out_name_obj') } + // Always remove the object file - it is completely unnecessary + os.rm('$out_name_obj') } fn build_thirdparty_obj_file_with_msvc(flag string) { diff --git a/compiler/tests/msvc_test.v b/compiler/tests/msvc_test.v new file mode 100644 index 0000000000..e932eff379 --- /dev/null +++ b/compiler/tests/msvc_test.v @@ -0,0 +1,49 @@ +fn test_flag_parsing() { + mut rest := '-lGlfw -f gl2,-ltest_nice_meme,-l cc,-Ldl test.o a.o ' //, whatever.o' + result := ['-l', 'Glfw', + '-f', 'gl2', + '-l', 'test_nice_meme', + '-l', 'cc', + '-L', 'dl', + '', 'test.o', + '', 'a.o'] + + mut flags := []string + for { + mut base := rest + + fl := if rest.starts_with('-') { + base = rest.right(2).trim_space() + rest.left(2) + } else { + '' + } + + // Which ever one of these is lowest we use + // TODO: we really shouldnt support all of these cmon + mut lowest := base.index('-') + for x in [base.index(' '), base.index(',')] { + if (x < lowest && x != -1) || lowest == -1 { + lowest = x + } + } + arg := if lowest != -1 { + rest = base.right(lowest).trim_space().trim(`,`) + base.left(lowest).trim_space().trim(`,`) + } else { + rest = '' + base.trim_space() + } + + flags << fl + flags << arg + + if rest.len == 0 { + break + } + } + + for i, f in flags { + assert f == result[i] + } +} \ No newline at end of file