diff --git a/compiler/cc.v b/compiler/cc.v index ee56eed215..8272a440d5 100644 --- a/compiler/cc.v +++ b/compiler/cc.v @@ -32,7 +32,16 @@ fn (v mut V) cc() { linux_host := os.user_os() == 'linux' v.log('cc() isprod=$v.pref.is_prod outname=$v.out_name') mut a := [v.pref.cflags, '-std=gnu11', '-w'] // arguments for the C compiler - flags := v.table.flags.join(' ') + + mut seenflags := map[string]int + mut uniqueflags := []string + for f in v.table.flags { + seenflags[ f ] = seenflags[ f ] + 1 + if seenflags[ f ] > 1 { continue } + uniqueflags << f + } + flags := uniqueflags.join(' ') + //mut shared := '' if v.pref.is_so { a << '-shared -fPIC '// -Wl,-z,defs' diff --git a/compiler/cgen.v b/compiler/cgen.v index 22892a5324..bd86ecb064 100644 --- a/compiler/cgen.v +++ b/compiler/cgen.v @@ -246,18 +246,19 @@ fn build_thirdparty_obj_file(flag string) { return } println('$obj_path not found, building it...') - parent := obj_path.all_before_last('/').trim_space() + parent := os.dir( obj_path ) files := os.ls(parent) - //files := os.ls(parent).filter(_.ends_with('.c')) TODO mut cfiles := '' for file in files { if file.ends_with('.c') { - cfiles += parent + '/' + file + ' ' + cfiles += '"' + os.realpath( parent + os.PathSeparator + file ) + '" ' } } cc := find_c_compiler() cc_thirdparty_options := find_c_compiler_thirdparty_options() - res := os.exec('$cc $cc_thirdparty_options -c -o $obj_path $cfiles') or { + cmd := '$cc $cc_thirdparty_options -c -o "$obj_path" $cfiles' + res := os.exec(cmd) or { + println('failed thirdparty object build cmd: $cmd') cerror(err) return } diff --git a/compiler/cheaders.v b/compiler/cheaders.v index 3dc700699b..8424b37f98 100644 --- a/compiler/cheaders.v +++ b/compiler/cheaders.v @@ -43,7 +43,9 @@ CommonCHeaders = ' #include // must be included after +#ifndef __TINYC__ #include +#endif #include // _waccess #include // _O_U8TEXT @@ -54,8 +56,8 @@ CommonCHeaders = ' #define _Atomic volatile // MSVC cannot parse some things properly -#undef EMPTY_STRUCT_DECLARATION -#define EMPTY_STRUCT_DECLARATION void *____dummy_variable +//#undef EMPTY_STRUCT_DECLARATION +//#define EMPTY_STRUCT_DECLARATION void *____dummy_variable #undef OPTION_CAST #define OPTION_CAST(x) #endif diff --git a/compiler/comptime.v b/compiler/comptime.v index 7cdbfb8bf8..a503ff798b 100644 --- a/compiler/comptime.v +++ b/compiler/comptime.v @@ -171,6 +171,8 @@ fn (p mut Parser) chash() { p.log('adding flag "$flag"') // `@VROOT/thirdparty/glad/glad.o`, make sure it exists, otherwise build it if (has_vroot || has_vmod) && flag.contains('.o') { + flag = os.realpath( flag ) + //println( 'absolute filepath to objectfile is now: $flag | os is: $p.os ') if p.os == .msvc { build_thirdparty_obj_file_with_msvc(flag) } diff --git a/compiler/msvc.v b/compiler/msvc.v index f7834ddf85..a0a9a56591 100644 --- a/compiler/msvc.v +++ b/compiler/msvc.v @@ -5,6 +5,7 @@ import os #flag windows -l shell32 struct MsvcResult { + full_cl_exe_path string exe_path string um_lib_path string @@ -187,6 +188,7 @@ fn find_msvc() ?MsvcResult { } return MsvcResult { + full_cl_exe_path: os.realpath( vs.exe_path + os.PathSeparator + 'cl.exe' ) exe_path: vs.exe_path, um_lib_path: wk.um_lib_path, @@ -214,13 +216,13 @@ pub fn (v mut V) cc_msvc() { r := find_msvc() or { // TODO: code reuse 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(v.out_name_c) } cerror('Cannot find MSVC on this OS.') return } - out_name_obj := v.out_name_c + '.obj' + out_name_obj := os.realpath( v.out_name_c + '.obj' ) // Default arguments @@ -228,7 +230,7 @@ pub fn (v mut V) cc_msvc() { // -w: no warnings // 2 unicode defines // /Fo sets the object file name - needed so we can clean up after ourselves properly - mut a := ['-w', '/we4013', '/volatile:ms', '/D_UNICODE', '/DUNICODE', '/Fo$out_name_obj'] + mut a := ['-w', '/we4013', '/volatile:ms', '/D_UNICODE', '/DUNICODE', '/Fo"$out_name_obj"'] if v.pref.is_prod { a << '/O2' @@ -249,15 +251,18 @@ pub fn (v mut V) cc_msvc() { v.out_name = v.out_name + '.exe' } - mut libs := ''// builtin.o os.o http.o etc + v.out_name = os.realpath( v.out_name ) + + mut alibs := []string // builtin.o os.o http.o etc if v.pref.build_mode == .build { } else if v.pref.build_mode == .embed_vlib { // } else if v.pref.build_mode == .default_mode { - libs = '"$ModPath/vlib/builtin.obj"' - if !os.file_exists(libs) { + b := os.realpath( '$ModPath/vlib/builtin.obj' ) + alibs << '"$b"' + if !os.file_exists(b) { println('`builtin.obj` not found') exit(1) } @@ -265,7 +270,7 @@ pub fn (v mut V) cc_msvc() { if imp == 'webview' { continue } - libs += ' "$ModPath/vlib/${imp}.obj"' + alibs << '"' + os.realpath( '$ModPath/vlib/${imp}.obj' ) + '"' } } @@ -275,7 +280,7 @@ pub fn (v mut V) cc_msvc() { // The C file we are compiling //a << '"$TmpPath/$v.out_name_c"' - a << '"$v.out_name_c"' + a << '"' + os.realpath( v.out_name_c ) + '"' // Emily: // Not all of these are needed (but the compiler should discard them if they are not used) @@ -296,13 +301,17 @@ pub fn (v mut V) cc_msvc() { 'vcruntime.lib', ] + mut inc_paths := []string{} mut lib_paths := []string{} mut other_flags := []string{} // Emily: // this is a hack to try and support -l -L and object files // passed on the command line + mut seenflags := map[string]int // no need to add the same flags more than once for f in v.table.flags { + seenflags[ f ] = seenflags[ f ] + 1 + if seenflags[ f ] > 1 { continue } // People like to put multiple flags per line (which really complicates things) // ...so we need to handle that mut rest := f @@ -345,7 +354,12 @@ pub fn (v mut V) cc_msvc() { for flag in flags { fl := flag.f - arg := flag.arg + mut arg := flag.arg + if fl == '-I' || fl == '-L' { + arg = os.realpath( arg ) + } + //println('fl: $fl | flag arg: $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 @@ -353,14 +367,23 @@ pub fn (v mut V) cc_msvc() { if arg.ends_with('.dll') { cerror('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 == '-I' { + inc_paths << ' -I "$arg" ' + } else if fl == '-L' { - lib_paths << f.right(2).trim_space() + lpath := f.right(2).trim_space() + lib_paths << lpath + lib_paths << lpath + os.PathSeparator + 'msvc' + // The above allows putting msvc specific .lib files in a subfolder msvc/ , + // where gcc will NOT find them, but cl will do... + // NB: gcc is smart enough to not need .lib files at all in most cases, the .dll is enough. + // When both a msvc .lib file and .dll file are present in the same folder, + // as for example for glfw3, compilation with gcc would fail. } else if arg.ends_with('.o') { // msvc expects .obj not .o @@ -374,7 +397,12 @@ pub fn (v mut V) cc_msvc() { } // Include the base paths - a << '-I "$r.ucrt_include_path" -I "$r.vs_include_path" -I "$r.um_include_path" -I "$r.shared_include_path"' + a << ' -I "$r.ucrt_include_path" ' + a << ' -I "$r.vs_include_path" ' + a << ' -I "$r.um_include_path" ' + a << ' -I "$r.shared_include_path" ' + + a << inc_paths a << other_flags @@ -383,14 +411,14 @@ pub fn (v mut V) cc_msvc() { a << '/link' a << '/NOLOGO' - a << '/OUT:$v.out_name' + a << '/OUT:"$v.out_name"' a << '/LIBPATH:"$r.ucrt_lib_path"' a << '/LIBPATH:"$r.um_lib_path"' a << '/LIBPATH:"$r.vs_lib_path"' a << '/INCREMENTAL:NO' // Disable incremental linking for l in lib_paths { - a << '/LIBPATH:"$l"' + a << '/LIBPATH:"' + os.realpath(l) + '"' } if !v.pref.is_prod { @@ -401,16 +429,13 @@ pub fn (v mut V) cc_msvc() { args := a.join(' ') - // println('$args') - // println('$exe_path') - - escaped_path := r.exe_path - - cmd := '""$escaped_path\\cl.exe" $args"' - + cmd := '""$r.full_cl_exe_path" $args"' + // It is hard to see it at first, but the quotes above ARE balanced :-| ... + // Also the double quotes at the start ARE needed. if v.pref.show_c_cmd || v.pref.is_verbose { - println('\n==========') + println('\n========== cl cmd line:') println(cmd) + println('==========\n') } // println('$cmd') @@ -427,11 +452,11 @@ pub fn (v mut V) cc_msvc() { // println('C OUTPUT:') 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(v.out_name_c) } // Always remove the object file - it is completely unnecessary - os.rm('$out_name_obj') + os.rm(out_name_obj) } fn build_thirdparty_obj_file_with_msvc(flag string) { @@ -448,24 +473,29 @@ fn build_thirdparty_obj_file_with_msvc(flag string) { } if os.file_exists(obj_path) { + println('$obj_path already build.') return } + println('$obj_path not found, building it (with msvc)...') - parent := obj_path.all_before_last('/').trim_space() + parent := os.dir( obj_path ) files := os.ls(parent) mut cfiles := '' for file in files { if file.ends_with('.c') { - cfiles += parent + '/' + file + ' ' + cfiles += '"' + os.realpath( parent + os.PathSeparator + file ) + '" ' } } include_string := '-I "$msvc.ucrt_include_path" -I "$msvc.vs_include_path" -I "$msvc.um_include_path" -I "$msvc.shared_include_path"' - println('$cfiles') + //println('cfiles: $cfiles') - res := os.exec('""$msvc.exe_path\\cl.exe" /volatile:ms /Z7 $include_string /c $cfiles /Fo"$obj_path" /D_UNICODE /DUNICODE"') or { + cmd := '""$msvc.full_cl_exe_path" /volatile:ms /Z7 $include_string /c $cfiles /Fo"$obj_path" /D_UNICODE /DUNICODE"' + //NB: the quotes above ARE balanced. + println('thirdparty cmd line: $cmd') + res := os.exec(cmd) or { cerror(err) return } diff --git a/thirdparty/glfw/msvc/glfw3.lib b/thirdparty/glfw/msvc/glfw3.lib new file mode 100644 index 0000000000..9051189fc3 Binary files /dev/null and b/thirdparty/glfw/msvc/glfw3.lib differ diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 503a3380e2..232206406b 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -151,6 +151,7 @@ pub fn (s string) u32() u32 { pub fn (s string) u64() u64 { return C.strtoull(s.str, 0, 0) + //return C.atoll(s.str) // temporary fix for tcc on windows. } // ==