compiler: build tetris executable on windows with both msvc and mingw gcc
parent
fcc6dd1d4d
commit
c9a39dfdb5
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -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…
Reference in New Issue