Browse Source

compiler: build tetris executable on windows with both msvc and mingw gcc

master
Delyan Angelov 1 year ago
committed by Alexander Medvednikov
parent
commit
c9a39dfdb5
7 changed files with 81 additions and 36 deletions
  1. +10
    -1
      compiler/cc.v
  2. +5
    -4
      compiler/cgen.v
  3. +4
    -2
      compiler/cheaders.v
  4. +2
    -0
      compiler/comptime.v
  5. +59
    -29
      compiler/msvc.v
  6. BIN
      thirdparty/glfw/msvc/glfw3.lib
  7. +1
    -0
      vlib/builtin/string.v

+ 10
- 1
compiler/cc.v View File

@@ -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'


+ 5
- 4
compiler/cgen.v View File

@@ -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
}


+ 4
- 2
compiler/cheaders.v View File

@@ -43,7 +43,9 @@ CommonCHeaders = '
#include <windows.h>

// must be included after <windows.h>
#ifndef __TINYC__
#include <shellapi.h>
#endif

#include <io.h> // _waccess
#include <fcntl.h> // _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


+ 2
- 0
compiler/comptime.v View File

@@ -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)
}


+ 59
- 29
compiler/msvc.v View File

@@ -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
}


BIN
thirdparty/glfw/msvc/glfw3.lib View File


+ 1
- 0
vlib/builtin/string.v View File

@@ -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.
}

// ==


Loading…
Cancel
Save