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'
|
linux_host := os.user_os() == 'linux'
|
||||||
v.log('cc() isprod=$v.pref.is_prod outname=$v.out_name')
|
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
|
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 := ''
|
//mut shared := ''
|
||||||
if v.pref.is_so {
|
if v.pref.is_so {
|
||||||
a << '-shared -fPIC '// -Wl,-z,defs'
|
a << '-shared -fPIC '// -Wl,-z,defs'
|
||||||
|
|
|
@ -246,18 +246,19 @@ fn build_thirdparty_obj_file(flag string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
println('$obj_path not found, building it...')
|
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)
|
||||||
//files := os.ls(parent).filter(_.ends_with('.c')) TODO
|
|
||||||
mut cfiles := ''
|
mut cfiles := ''
|
||||||
for file in files {
|
for file in files {
|
||||||
if file.ends_with('.c') {
|
if file.ends_with('.c') {
|
||||||
cfiles += parent + '/' + file + ' '
|
cfiles += '"' + os.realpath( parent + os.PathSeparator + file ) + '" '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cc := find_c_compiler()
|
cc := find_c_compiler()
|
||||||
cc_thirdparty_options := find_c_compiler_thirdparty_options()
|
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)
|
cerror(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,9 @@ CommonCHeaders = '
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
// must be included after <windows.h>
|
// must be included after <windows.h>
|
||||||
|
#ifndef __TINYC__
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <io.h> // _waccess
|
#include <io.h> // _waccess
|
||||||
#include <fcntl.h> // _O_U8TEXT
|
#include <fcntl.h> // _O_U8TEXT
|
||||||
|
@ -54,8 +56,8 @@ CommonCHeaders = '
|
||||||
#define _Atomic volatile
|
#define _Atomic volatile
|
||||||
|
|
||||||
// MSVC cannot parse some things properly
|
// MSVC cannot parse some things properly
|
||||||
#undef EMPTY_STRUCT_DECLARATION
|
//#undef EMPTY_STRUCT_DECLARATION
|
||||||
#define EMPTY_STRUCT_DECLARATION void *____dummy_variable
|
//#define EMPTY_STRUCT_DECLARATION void *____dummy_variable
|
||||||
#undef OPTION_CAST
|
#undef OPTION_CAST
|
||||||
#define OPTION_CAST(x)
|
#define OPTION_CAST(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -171,6 +171,8 @@ fn (p mut Parser) chash() {
|
||||||
p.log('adding flag "$flag"')
|
p.log('adding flag "$flag"')
|
||||||
// `@VROOT/thirdparty/glad/glad.o`, make sure it exists, otherwise build it
|
// `@VROOT/thirdparty/glad/glad.o`, make sure it exists, otherwise build it
|
||||||
if (has_vroot || has_vmod) && flag.contains('.o') {
|
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 {
|
if p.os == .msvc {
|
||||||
build_thirdparty_obj_file_with_msvc(flag)
|
build_thirdparty_obj_file_with_msvc(flag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import os
|
||||||
#flag windows -l shell32
|
#flag windows -l shell32
|
||||||
|
|
||||||
struct MsvcResult {
|
struct MsvcResult {
|
||||||
|
full_cl_exe_path string
|
||||||
exe_path string
|
exe_path string
|
||||||
|
|
||||||
um_lib_path string
|
um_lib_path string
|
||||||
|
@ -187,6 +188,7 @@ fn find_msvc() ?MsvcResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
return MsvcResult {
|
return MsvcResult {
|
||||||
|
full_cl_exe_path: os.realpath( vs.exe_path + os.PathSeparator + 'cl.exe' )
|
||||||
exe_path: vs.exe_path,
|
exe_path: vs.exe_path,
|
||||||
|
|
||||||
um_lib_path: wk.um_lib_path,
|
um_lib_path: wk.um_lib_path,
|
||||||
|
@ -214,13 +216,13 @@ pub fn (v mut V) cc_msvc() {
|
||||||
r := find_msvc() or {
|
r := find_msvc() or {
|
||||||
// TODO: code reuse
|
// TODO: code reuse
|
||||||
if !v.pref.is_debug && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' {
|
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.')
|
cerror('Cannot find MSVC on this OS.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
out_name_obj := v.out_name_c + '.obj'
|
out_name_obj := os.realpath( v.out_name_c + '.obj' )
|
||||||
|
|
||||||
// Default arguments
|
// Default arguments
|
||||||
|
|
||||||
|
@ -228,7 +230,7 @@ pub fn (v mut V) cc_msvc() {
|
||||||
// -w: no warnings
|
// -w: no warnings
|
||||||
// 2 unicode defines
|
// 2 unicode defines
|
||||||
// /Fo sets the object file name - needed so we can clean up after ourselves properly
|
// /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 {
|
if v.pref.is_prod {
|
||||||
a << '/O2'
|
a << '/O2'
|
||||||
|
@ -249,15 +251,18 @@ pub fn (v mut V) cc_msvc() {
|
||||||
v.out_name = v.out_name + '.exe'
|
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 {
|
if v.pref.build_mode == .build {
|
||||||
}
|
}
|
||||||
else if v.pref.build_mode == .embed_vlib {
|
else if v.pref.build_mode == .embed_vlib {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
else if v.pref.build_mode == .default_mode {
|
else if v.pref.build_mode == .default_mode {
|
||||||
libs = '"$ModPath/vlib/builtin.obj"'
|
b := os.realpath( '$ModPath/vlib/builtin.obj' )
|
||||||
if !os.file_exists(libs) {
|
alibs << '"$b"'
|
||||||
|
if !os.file_exists(b) {
|
||||||
println('`builtin.obj` not found')
|
println('`builtin.obj` not found')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
@ -265,7 +270,7 @@ pub fn (v mut V) cc_msvc() {
|
||||||
if imp == 'webview' {
|
if imp == 'webview' {
|
||||||
continue
|
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
|
// The C file we are compiling
|
||||||
//a << '"$TmpPath/$v.out_name_c"'
|
//a << '"$TmpPath/$v.out_name_c"'
|
||||||
a << '"$v.out_name_c"'
|
a << '"' + os.realpath( v.out_name_c ) + '"'
|
||||||
|
|
||||||
// Emily:
|
// Emily:
|
||||||
// Not all of these are needed (but the compiler should discard them if they are not used)
|
// 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',
|
'vcruntime.lib',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
mut inc_paths := []string{}
|
||||||
mut lib_paths := []string{}
|
mut lib_paths := []string{}
|
||||||
mut other_flags := []string{}
|
mut other_flags := []string{}
|
||||||
|
|
||||||
// Emily:
|
// Emily:
|
||||||
// this is a hack to try and support -l -L and object files
|
// this is a hack to try and support -l -L and object files
|
||||||
// passed on the command line
|
// 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 {
|
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)
|
// People like to put multiple flags per line (which really complicates things)
|
||||||
// ...so we need to handle that
|
// ...so we need to handle that
|
||||||
mut rest := f
|
mut rest := f
|
||||||
|
@ -345,7 +354,12 @@ pub fn (v mut V) cc_msvc() {
|
||||||
|
|
||||||
for flag in flags {
|
for flag in flags {
|
||||||
fl := flag.f
|
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
|
// We need to see if the flag contains -l
|
||||||
// -l isnt recognised and these libs will be passed straight to the linker
|
// -l isnt recognised and these libs will be passed straight to the linker
|
||||||
// by the compiler
|
// by the compiler
|
||||||
|
@ -353,14 +367,23 @@ pub fn (v mut V) cc_msvc() {
|
||||||
if arg.ends_with('.dll') {
|
if arg.ends_with('.dll') {
|
||||||
cerror('MSVC cannot link against a dll (`#flag -l $arg`)')
|
cerror('MSVC cannot link against a dll (`#flag -l $arg`)')
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSVC has no method of linking against a .dll
|
// MSVC has no method of linking against a .dll
|
||||||
// TODO: we should look for .defs aswell
|
// TODO: we should look for .defs aswell
|
||||||
lib_lib := arg + '.lib'
|
lib_lib := arg + '.lib'
|
||||||
real_libs << lib_lib
|
real_libs << lib_lib
|
||||||
}
|
}
|
||||||
|
else if fl == '-I' {
|
||||||
|
inc_paths << ' -I "$arg" '
|
||||||
|
}
|
||||||
else if fl == '-L' {
|
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') {
|
else if arg.ends_with('.o') {
|
||||||
// msvc expects .obj not .o
|
// msvc expects .obj not .o
|
||||||
|
@ -374,7 +397,12 @@ pub fn (v mut V) cc_msvc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include the base paths
|
// 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
|
a << other_flags
|
||||||
|
|
||||||
|
@ -383,14 +411,14 @@ pub fn (v mut V) cc_msvc() {
|
||||||
|
|
||||||
a << '/link'
|
a << '/link'
|
||||||
a << '/NOLOGO'
|
a << '/NOLOGO'
|
||||||
a << '/OUT:$v.out_name'
|
a << '/OUT:"$v.out_name"'
|
||||||
a << '/LIBPATH:"$r.ucrt_lib_path"'
|
a << '/LIBPATH:"$r.ucrt_lib_path"'
|
||||||
a << '/LIBPATH:"$r.um_lib_path"'
|
a << '/LIBPATH:"$r.um_lib_path"'
|
||||||
a << '/LIBPATH:"$r.vs_lib_path"'
|
a << '/LIBPATH:"$r.vs_lib_path"'
|
||||||
a << '/INCREMENTAL:NO' // Disable incremental linking
|
a << '/INCREMENTAL:NO' // Disable incremental linking
|
||||||
|
|
||||||
for l in lib_paths {
|
for l in lib_paths {
|
||||||
a << '/LIBPATH:"$l"'
|
a << '/LIBPATH:"' + os.realpath(l) + '"'
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v.pref.is_prod {
|
if !v.pref.is_prod {
|
||||||
|
@ -401,16 +429,13 @@ pub fn (v mut V) cc_msvc() {
|
||||||
|
|
||||||
args := a.join(' ')
|
args := a.join(' ')
|
||||||
|
|
||||||
// println('$args')
|
cmd := '""$r.full_cl_exe_path" $args"'
|
||||||
// println('$exe_path')
|
// It is hard to see it at first, but the quotes above ARE balanced :-| ...
|
||||||
|
// Also the double quotes at the start ARE needed.
|
||||||
escaped_path := r.exe_path
|
|
||||||
|
|
||||||
cmd := '""$escaped_path\\cl.exe" $args"'
|
|
||||||
|
|
||||||
if v.pref.show_c_cmd || v.pref.is_verbose {
|
if v.pref.show_c_cmd || v.pref.is_verbose {
|
||||||
println('\n==========')
|
println('\n========== cl cmd line:')
|
||||||
println(cmd)
|
println(cmd)
|
||||||
|
println('==========\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
// println('$cmd')
|
// println('$cmd')
|
||||||
|
@ -427,11 +452,11 @@ pub fn (v mut V) cc_msvc() {
|
||||||
// println('C OUTPUT:')
|
// println('C OUTPUT:')
|
||||||
|
|
||||||
if !v.pref.is_debug && v.out_name_c != 'v.c' && v.out_name_c != 'v_macos.c' {
|
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
|
// 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) {
|
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) {
|
if os.file_exists(obj_path) {
|
||||||
|
println('$obj_path already build.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
println('$obj_path not found, building it (with msvc)...')
|
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)
|
files := os.ls(parent)
|
||||||
|
|
||||||
mut cfiles := ''
|
mut cfiles := ''
|
||||||
for file in files {
|
for file in files {
|
||||||
if file.ends_with('.c') {
|
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"'
|
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)
|
cerror(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -151,6 +151,7 @@ pub fn (s string) u32() u32 {
|
||||||
|
|
||||||
pub fn (s string) u64() u64 {
|
pub fn (s string) u64() u64 {
|
||||||
return C.strtoull(s.str, 0, 0)
|
return C.strtoull(s.str, 0, 0)
|
||||||
|
//return C.atoll(s.str) // temporary fix for tcc on windows.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==
|
// ==
|
||||||
|
|
Loading…
Reference in New Issue