From decdd8be9f0b1bcadc0e3400112c21dcc4a9698e Mon Sep 17 00:00:00 2001 From: Emily Hudson Date: Mon, 12 Aug 2019 11:17:26 +0000 Subject: [PATCH] Prevent people on platforms that arent 'windows' from being able to build with msvc --- compiler/main.v | 8 +- compiler/{msvc_win.v => msvc.v} | 188 +++++++++++++++++--------------- compiler/msvc_nix.v | 8 -- 3 files changed, 110 insertions(+), 94 deletions(-) rename compiler/{msvc_win.v => msvc.v} (68%) delete mode 100644 compiler/msvc_nix.v diff --git a/compiler/main.v b/compiler/main.v index 57f5defa8a..bcde3d9f05 100644 --- a/compiler/main.v +++ b/compiler/main.v @@ -210,6 +210,11 @@ fn main() { } fn (v mut V) compile() { + // Emily: Stop people on linux from being able to build with msvc + if os.user_os() != 'windows' && v.os == .msvc { + panic('Cannot build with msvc on ${os.user_os()}') + } + mut cgen := v.cgen cgen.genln('// Generated by V') v.add_v_files_to_compile() @@ -753,7 +758,8 @@ fn (v mut V) cc() { v.cc_msvc() return } - } + } + 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 diff --git a/compiler/msvc_win.v b/compiler/msvc.v similarity index 68% rename from compiler/msvc_win.v rename to compiler/msvc.v index 6bd65fd6f7..8d7346762a 100644 --- a/compiler/msvc_win.v +++ b/compiler/msvc.v @@ -5,16 +5,16 @@ import os #flag windows -l shell32 struct MsvcResult { - exe_path string + exe_path string - um_lib_path string - ucrt_lib_path string - vs_lib_path string + um_lib_path string + ucrt_lib_path string + vs_lib_path string - um_include_path string - ucrt_include_path string - vs_include_path string - shared_include_path string + um_include_path string + ucrt_include_path string + vs_include_path string + shared_include_path string } // Mimics a HKEY @@ -30,36 +30,38 @@ const ( // Given a root key look for one of the subkeys in 'versions' and get the path fn find_windows_kit_internal(key RegKey, versions []string) ?string { - for version in versions { - required_bytes := 0 // TODO mut - result := C.RegQueryValueExW(key, version.to_wide(), 0, 0, 0, &required_bytes) + $if windows { + for version in versions { + required_bytes := 0 // TODO mut + result := C.RegQueryValueExW(key, version.to_wide(), 0, 0, 0, &required_bytes) - length := required_bytes / 2 + length := required_bytes / 2 - if result != 0 { - continue + if result != 0 { + continue + } + + alloc_length := (required_bytes + 2) + + mut value := &u16(malloc(alloc_length)) + if !value { + continue + } + + result2 := C.RegQueryValueExW(key, version.to_wide(), 0, 0, value, &alloc_length) + + if result2 != 0 { + continue + } + + // We might need to manually null terminate this thing + // So just make sure that we do that + if (value[length - 1] != u16(0)) { + value[length] = u16(0) + } + + return string_from_wide(value) } - - alloc_length := (required_bytes + 2) - - mut value := &u16(malloc(alloc_length)) - if !value { - continue - } - - result2 := C.RegQueryValueExW(key, version.to_wide(), 0, 0, value, &alloc_length) - - if result2 != 0 { - continue - } - - // We might need to manually null terminate this thing - // So just make sure that we do that - if (value[length - 1] != u16(0)) { - value[length] = u16(0) - } - - return string_from_wide(value) } return error('windows kit not found') } @@ -75,50 +77,53 @@ struct WindowsKit { // Try and find the root key for installed windows kits fn find_windows_kit_root() ?WindowsKit { - root_key := RegKey(0) - rc := C.RegOpenKeyExA( - HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots', 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &root_key) - - defer {C.RegCloseKey(root_key)} + $if windows { + root_key := RegKey(0) + rc := C.RegOpenKeyExA( + HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots', 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &root_key) - if rc != 0 { - return error('Unable to open root key') - } - // Try and find win10 kit - kit_root := find_windows_kit_internal(root_key, ['KitsRoot10', 'KitsRoot81']) or { - return error('Unable to find a windows kit') - } + defer {C.RegCloseKey(root_key)} - kit_lib := kit_root + 'Lib' + if rc != 0 { + return error('Unable to open root key') + } + // Try and find win10 kit + kit_root := find_windows_kit_internal(root_key, ['KitsRoot10', 'KitsRoot81']) or { + return error('Unable to find a windows kit') + } - // println(kit_lib) + kit_lib := kit_root + 'Lib' - files := os.ls(kit_lib) - mut highest_path := '' - mut highest_int := 0 - for f in files { - no_dot := f.replace('.', '') - v_int := no_dot.int() + // println(kit_lib) - if v_int > highest_int { - highest_int = v_int - highest_path = f + files := os.ls(kit_lib) + mut highest_path := '' + mut highest_int := 0 + for f in files { + no_dot := f.replace('.', '') + v_int := no_dot.int() + + if v_int > highest_int { + highest_int = v_int + highest_path = f + } + } + + kit_lib_highest := kit_lib + '\\$highest_path' + kit_include_highest := kit_lib_highest.replace('Lib', 'Include') + + // println('$kit_lib_highest $kit_include_highest') + + return WindowsKit { + um_lib_path: kit_lib_highest + '\\um\\x64' + ucrt_lib_path: kit_lib_highest + '\\ucrt\\x64' + + um_include_path: kit_include_highest + '\\um' + ucrt_include_path: kit_include_highest + '\\ucrt' + shared_include_path: kit_include_highest + '\\shared' } } - - kit_lib_highest := kit_lib + '\\$highest_path' - kit_include_highest := kit_lib_highest.replace('Lib', 'Include') - - // println('$kit_lib_highest $kit_include_highest') - - return WindowsKit { - um_lib_path: kit_lib_highest + '\\um\\x64' - ucrt_lib_path: kit_lib_highest + '\\ucrt\\x64' - - um_include_path: kit_include_highest + '\\um' - ucrt_include_path: kit_include_highest + '\\ucrt' - shared_include_path: kit_include_highest + '\\shared' - } + return error('Host OS does not support funding a windows kit') } struct VsInstallation { @@ -128,6 +133,9 @@ struct VsInstallation { } fn find_vs() ?VsInstallation { + $if !windows { + return error('Host OS does not support finding a Vs installation') + } // Emily: // VSWhere is guaranteed to be installed at this location now // If its not there then end user needs to update their visual studio @@ -192,23 +200,28 @@ fn find_msvc() ?MsvcResult { } } $else { - panic('Cannot find msvc on this platform') + panic('Cannot find msvc on this OS') } } pub fn (v mut V) cc_msvc() { r := find_msvc() or { - println('Could not find MSVC') - // 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') } - return + panic('Cannot find MSVC on this OS.') } + out_name_obj := v.out_name_c + '.obj' + // Default arguments - mut a := ['-w', '/volatile:ms', '/D_UNICODE', '/DUNICODE'] + + // volatile:ms enables atomic volatile (gcc _Atomic) + // -w: no warnings + // 2 unicode defines + // /Fo sets the object file name - needed so we can clean up after ourselves properly + mut a := ['-w', '/volatile:ms', '/D_UNICODE', '/DUNICODE', '/Fo$out_name_obj'] if v.pref.is_prod { a << '/O2' @@ -219,7 +232,6 @@ pub fn (v mut V) cc_msvc() { } if v.pref.is_so { - // Dont think we have to do anything for this if !v.out_name.ends_with('.dll') { v.out_name = v.out_name + '.dll' } @@ -258,6 +270,9 @@ pub fn (v mut V) cc_msvc() { //a << '"$TmpPath/$v.out_name_c"' a << '".$v.out_name_c"' + // Emily: + // Not all of these are needed (but the compiler should discard them if they are not used) + // these are the defaults used by msbuild and visual studio mut real_libs := [ 'kernel32.lib', 'user32.lib', @@ -287,6 +302,10 @@ pub fn (v mut V) cc_msvc() { if f.starts_with('-l') { lib_base := f.right(2).trim_space() + if lib_base.ends_with('.dll') { + panic('MSVC cannot link against a dll (`#flag -l $lib_base`)') + } + // MSVC has no method of linking against a .dll // TODO: we should look for .defs aswell lib_lib := lib_base + '.lib' @@ -307,11 +326,9 @@ 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"' - // Msvc also doesnt have atomic - // TODO: dont rely on gcc's _Atomic semantics! a << other_flags - // TODO: libs will need to be actually handled properly + // Libs are passed to cl.exe which passes them to the linker a << real_libs.join(' ') a << '/link' @@ -349,8 +366,9 @@ 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') + os.rm('$out_name_obj') + } } @@ -389,5 +407,5 @@ fn build_thirdparty_obj_file_with_msvc(flag string) { panic(err) } println(res) -} +} diff --git a/compiler/msvc_nix.v b/compiler/msvc_nix.v deleted file mode 100644 index e464c4cfc3..0000000000 --- a/compiler/msvc_nix.v +++ /dev/null @@ -1,8 +0,0 @@ -module main - -fn (v mut V) cc_msvc() { -} - -fn build_thirdparty_obj_file_with_msvc(flag string) { - -}