compiler: rework flags & support win path spaces + more
parent
e8068b5e1d
commit
8ac0a2b2dd
|
@ -10,6 +10,9 @@ import (
|
|||
)
|
||||
|
||||
fn (v mut V) cc() {
|
||||
// build any thirdparty obj files
|
||||
v.build_thirdparty_obj_files()
|
||||
|
||||
// Just create a c file and exit
|
||||
if v.out_name.ends_with('.c') {
|
||||
os.mv(v.out_name_c, v.out_name)
|
||||
|
@ -33,15 +36,6 @@ fn (v mut V) cc() {
|
|||
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 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(' ')
|
||||
// Set out name
|
||||
if v.pref.is_so {
|
||||
a << '-shared -fPIC '// -Wl,-z,defs'
|
||||
v.out_name = v.out_name + '.so'
|
||||
|
@ -92,7 +86,7 @@ fn (v mut V) cc() {
|
|||
// -I flags
|
||||
/*
|
||||
mut args := ''
|
||||
for flag in v.table.flags {
|
||||
for flag in v.get_os_cflags() {
|
||||
if !flag.starts_with('-l') {
|
||||
args += flag
|
||||
args += ' '
|
||||
|
@ -133,7 +127,9 @@ mut args := ''
|
|||
if v.os == .mac {
|
||||
a << '-mmacosx-version-min=10.7'
|
||||
}
|
||||
a << flags
|
||||
for flag in v.get_os_cflags() {
|
||||
a << flag.format()
|
||||
}
|
||||
a << libs
|
||||
// macOS code can include objective C TODO remove once objective C is replaced with C
|
||||
// Without these libs compilation will fail on Linux
|
||||
|
@ -224,9 +220,9 @@ fn (c mut V) cc_windows_cross() {
|
|||
}
|
||||
mut args := '-o $c.out_name -w -L. '
|
||||
// -I flags
|
||||
for flag in c.table.flags {
|
||||
if !flag.starts_with('-l') {
|
||||
args += flag
|
||||
for flag in c.get_os_cflags() {
|
||||
if flag.name != '-l' {
|
||||
args += flag.format()
|
||||
args += ' '
|
||||
}
|
||||
}
|
||||
|
@ -243,9 +239,9 @@ fn (c mut V) cc_windows_cross() {
|
|||
}
|
||||
args += ' $c.out_name_c '
|
||||
// -l flags (libs)
|
||||
for flag in c.table.flags {
|
||||
if flag.starts_with('-l') {
|
||||
args += flag
|
||||
for flag in c.get_os_cflags() {
|
||||
if flag.name == '-l' {
|
||||
args += flag.format()
|
||||
args += ' '
|
||||
}
|
||||
}
|
||||
|
@ -289,6 +285,19 @@ fn (c mut V) cc_windows_cross() {
|
|||
println('Done!')
|
||||
}
|
||||
|
||||
fn (c V) build_thirdparty_obj_files() {
|
||||
for flag in c.get_os_cflags() {
|
||||
if flag.value.ends_with('.o') {
|
||||
if c.os == .msvc {
|
||||
build_thirdparty_obj_file_with_msvc(flag.value)
|
||||
}
|
||||
else {
|
||||
build_thirdparty_obj_file(flag.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_c_compiler() string {
|
||||
args := env_vflags_and_os_args().join(' ')
|
||||
defaultcc := find_c_compiler_default()
|
||||
|
@ -306,10 +315,6 @@ fn find_c_compiler_default() string {
|
|||
}
|
||||
|
||||
fn find_c_compiler_thirdparty_options() string {
|
||||
$if windows { return '' }
|
||||
$if windows { return '' }
|
||||
return '-fPIC'
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module main
|
||||
|
||||
import os
|
||||
|
||||
// C flag
|
||||
struct CFlag{
|
||||
os string // eg. windows | darwin | linux
|
||||
name string // eg. -I
|
||||
value string // eg. /path/to/incude
|
||||
}
|
||||
|
||||
// check if cflag is in table
|
||||
fn (table &Table) has_cflag(cflag CFlag) bool {
|
||||
for cf in table.cflags {
|
||||
if cf.os == cflag.os && cf.name == cflag.name && cf.value == cflag.value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// get flags for current os
|
||||
fn (v V) get_os_cflags() []CFlag {
|
||||
mut flags := []CFlag
|
||||
for flag in v.table.cflags {
|
||||
if flag.os == ''
|
||||
|| (flag.os == 'linux' && v.os == .linux)
|
||||
|| (flag.os == 'darwin' && v.os == .mac)
|
||||
|| (flag.os == 'windows' && (v.os == .windows || v.os == .msvc)) {
|
||||
flags << flag
|
||||
}
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
// format flag
|
||||
fn (cf &CFlag) format() string {
|
||||
mut value := cf.value
|
||||
// convert to absolute path
|
||||
if cf.name == '-I' || cf.name == '-L' || value.ends_with('.o') {
|
||||
value = '"'+os.realpath(value)+'"'
|
||||
}
|
||||
return '$cf.name $value'.trim_space()
|
||||
}
|
||||
|
||||
// parse the flags to []CFlag
|
||||
// Note: clean up big time (joe-c)
|
||||
fn (table mut Table) parse_cflag(cflag string) {
|
||||
allowed_flags := [
|
||||
'framework',
|
||||
'library',
|
||||
'I', 'l', 'L',
|
||||
]
|
||||
mut flag := cflag.trim_space()
|
||||
if flag == '' {
|
||||
return
|
||||
}
|
||||
mut fos := ''
|
||||
mut name := ''
|
||||
if flag.starts_with('linux') || flag.starts_with('darwin') || flag.starts_with('windows') {
|
||||
pos := flag.index(' ')
|
||||
fos = flag.left(pos).trim_space()
|
||||
flag = flag.right(pos).trim_space()
|
||||
}
|
||||
for {
|
||||
mut index := -1
|
||||
mut value := ''
|
||||
if flag[0] == `-` {
|
||||
for f in allowed_flags {
|
||||
i := 1+f.len
|
||||
if i < flag.len && f == flag.substr(1,i) {
|
||||
name = flag.left(i).trim_space()
|
||||
flag = flag.right(i).trim_space()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for i in [flag.index(' '), flag.index(',')] {
|
||||
if index == -1 || (i != -1 && i < index) {
|
||||
index = i
|
||||
}
|
||||
} if index != -1 && flag[index] == ` ` && flag[index+1] == `-` {
|
||||
for f in allowed_flags {
|
||||
i := index+f.len
|
||||
if i < flag.len && f == flag.substr(index, i) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
value = flag.left(index).trim_space()
|
||||
flag = flag.right(index).trim_space()
|
||||
} else if index != -1 && index < flag.len-2 && flag[index] == `,` {
|
||||
value = flag.left(index).trim_space()
|
||||
flag = flag.right(index+1).trim_space()
|
||||
} else {
|
||||
value = flag.trim_space()
|
||||
index = -1
|
||||
}
|
||||
cf := CFlag{
|
||||
os: fos,
|
||||
name: name,
|
||||
value: value
|
||||
}
|
||||
if !table.has_cflag(cf) {
|
||||
table.cflags << cf
|
||||
}
|
||||
if index == -1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
|
@ -240,13 +240,13 @@ fn (g mut CGen) add_to_main(s string) {
|
|||
}
|
||||
|
||||
|
||||
fn build_thirdparty_obj_file(flag string) {
|
||||
obj_path := flag.all_after(' ')
|
||||
fn build_thirdparty_obj_file(path string) {
|
||||
obj_path := os.realpath(path)
|
||||
if os.file_exists(obj_path) {
|
||||
return
|
||||
}
|
||||
println('$obj_path not found, building it...')
|
||||
parent := os.dir( obj_path )
|
||||
parent := os.dir(obj_path)
|
||||
files := os.ls(parent)
|
||||
mut cfiles := ''
|
||||
for file in files {
|
||||
|
@ -281,15 +281,15 @@ fn os_name_to_ifdef(name string) string {
|
|||
}
|
||||
|
||||
fn platform_postfix_to_ifdefguard(name string) string {
|
||||
switch name {
|
||||
case '.v': return '' // no guard needed
|
||||
case '_win.v': return '#ifdef _WIN32'
|
||||
case '_nix.v': return '#ifndef _WIN32'
|
||||
case '_lin.v': return '#ifdef __linux__'
|
||||
case '_mac.v': return '#ifdef __APPLE__'
|
||||
}
|
||||
cerror('bad platform_postfix "$name"')
|
||||
return ''
|
||||
switch name {
|
||||
case '.v': return '' // no guard needed
|
||||
case '_win.v': return '#ifdef _WIN32'
|
||||
case '_nix.v': return '#ifndef _WIN32'
|
||||
case '_lin.v': return '#ifdef __linux__'
|
||||
case '_mac.v': return '#ifdef __APPLE__'
|
||||
}
|
||||
cerror('bad platform_postfix "$name"')
|
||||
return ''
|
||||
}
|
||||
|
||||
// C struct definitions, ordered
|
||||
|
@ -383,4 +383,3 @@ fn sort_structs(types []Type) []Type {
|
|||
}
|
||||
return types_sorted
|
||||
}
|
||||
|
||||
|
|
|
@ -141,46 +141,11 @@ fn (p mut Parser) chash() {
|
|||
is_sig := p.is_sig()
|
||||
if hash.starts_with('flag ') {
|
||||
mut flag := hash.right(5)
|
||||
// No the right os? Skip!
|
||||
// mut ok := true
|
||||
if hash.contains('linux') && p.os != .linux {
|
||||
return
|
||||
}
|
||||
else if hash.contains('darwin') && p.os != .mac {
|
||||
return
|
||||
}
|
||||
else if hash.contains('windows') && (p.os != .windows && p.os != .msvc) {
|
||||
return
|
||||
}
|
||||
// Remove "linux" etc from flag
|
||||
if flag.contains('linux') || flag.contains('darwin') || flag.contains('windows') {
|
||||
pos := flag.index(' ')
|
||||
flag = flag.right(pos)
|
||||
}
|
||||
has_vroot := flag.contains('@VROOT')
|
||||
flag = flag.trim_space().replace('@VROOT', p.vroot)
|
||||
if p.table.flags.contains(flag) {
|
||||
return
|
||||
}
|
||||
// expand `@VMOD/pg/pg.o` to absolute path
|
||||
has_vmod := flag.contains('@VMOD')
|
||||
flag = flag.trim_space().replace('@VMOD', ModPath)
|
||||
if p.table.flags.contains(flag) {
|
||||
return
|
||||
}
|
||||
// expand `@VROOT` `@VMOD` to absolute path
|
||||
flag = flag.replace('@VROOT', p.vroot)
|
||||
flag = flag.replace('@VMOD', ModPath)
|
||||
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)
|
||||
}
|
||||
else {
|
||||
build_thirdparty_obj_file(flag)
|
||||
}
|
||||
}
|
||||
p.table.flags << flag
|
||||
p.table.parse_cflag(flag)
|
||||
return
|
||||
}
|
||||
if hash.starts_with('include') {
|
||||
|
|
|
@ -325,7 +325,9 @@ fn (v mut V) compile() {
|
|||
cgen.save()
|
||||
if v.pref.is_verbose {
|
||||
v.log('flags=')
|
||||
println(v.table.flags)
|
||||
for flag in v.get_os_cflags() {
|
||||
println(' * ' + flag.format())
|
||||
}
|
||||
}
|
||||
v.cc()
|
||||
}
|
||||
|
@ -437,7 +439,7 @@ fn (v V) run_compiled_executable_and_exit() {
|
|||
if v.pref.is_verbose {
|
||||
println('============ running $v.out_name ============')
|
||||
}
|
||||
mut cmd := final_target_out_name(v.out_name).replace('.exe','')
|
||||
mut cmd := '"' + final_target_out_name(v.out_name).replace('.exe','') + '"'
|
||||
if os.args.len > 3 {
|
||||
cmd += ' ' + os.args.right(3).join(' ')
|
||||
}
|
||||
|
@ -781,9 +783,7 @@ fn new_v(args[]string) &V {
|
|||
vroot := os.dir(os.executable())
|
||||
//println('VROOT=$vroot')
|
||||
// v.exe's parent directory should contain vlib
|
||||
if os.dir_exists(vroot) && os.dir_exists(vroot + '/vlib/builtin') {
|
||||
|
||||
} else {
|
||||
if !os.dir_exists(vroot) || !os.dir_exists(vroot + '/vlib/builtin') {
|
||||
println('vlib not found. It should be next to the V executable. ')
|
||||
println('Go to https://vlang.io to install V.')
|
||||
exit(1)
|
||||
|
|
139
compiler/msvc.v
139
compiler/msvc.v
|
@ -207,11 +207,6 @@ fn find_msvc() ?MsvcResult {
|
|||
}
|
||||
}
|
||||
|
||||
struct ParsedFlag {
|
||||
f string
|
||||
arg string
|
||||
}
|
||||
|
||||
pub fn (v mut V) cc_msvc() {
|
||||
r := find_msvc() or {
|
||||
// TODO: code reuse
|
||||
|
@ -305,99 +300,41 @@ pub fn (v mut V) cc_msvc() {
|
|||
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
|
||||
for flag in v.get_os_cflags() {
|
||||
mut arg := flag.value
|
||||
//println('fl: $flag.name | flag arg: $arg')
|
||||
|
||||
mut flags := []ParsedFlag{}
|
||||
for {
|
||||
mut base := rest
|
||||
|
||||
fl := if rest.starts_with('-') {
|
||||
base = rest.right(2).trim_space()
|
||||
rest.left(2)
|
||||
} else {
|
||||
''
|
||||
}
|
||||
|
||||
// Which ever one of these is lowest we use
|
||||
// TODO: we really shouldnt support all of these cmon
|
||||
mut lowest := base.index('-')
|
||||
// dont break paths with hyphens
|
||||
if lowest != 0 {
|
||||
lowest = -1
|
||||
}
|
||||
for x in [base.index(' '), base.index(',')] {
|
||||
if (x < lowest && x != -1) || lowest == -1 {
|
||||
lowest = x
|
||||
}
|
||||
}
|
||||
arg := if lowest != -1 {
|
||||
rest = base.right(lowest).trim_space().trim(',')
|
||||
base.left(lowest).trim_space().trim(',')
|
||||
} else {
|
||||
rest = ''
|
||||
base.trim_space()
|
||||
}
|
||||
|
||||
flags << ParsedFlag {
|
||||
fl, arg
|
||||
}
|
||||
|
||||
if rest.len == 0 {
|
||||
break
|
||||
// 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
|
||||
if flag.name == '-l' {
|
||||
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
|
||||
}
|
||||
|
||||
for flag in flags {
|
||||
fl := flag.f
|
||||
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
|
||||
if fl == '-l' {
|
||||
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' {
|
||||
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
|
||||
other_flags << arg + 'bj'
|
||||
}
|
||||
else {
|
||||
other_flags << arg
|
||||
}
|
||||
else if flag.name == '-I' {
|
||||
inc_paths << ' ' + flag.format() + ' '
|
||||
}
|
||||
else if flag.name == '-L' {
|
||||
lpath := flag.value
|
||||
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 flag.value.ends_with('.o') {
|
||||
other_flags << flag.format().replace('.o', '.obj')
|
||||
}
|
||||
else {
|
||||
other_flags << arg
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Include the base paths
|
||||
|
@ -463,18 +400,16 @@ pub fn (v mut V) cc_msvc() {
|
|||
os.rm(out_name_obj)
|
||||
}
|
||||
|
||||
fn build_thirdparty_obj_file_with_msvc(flag string) {
|
||||
fn build_thirdparty_obj_file_with_msvc(path string) {
|
||||
msvc := find_msvc() or {
|
||||
println('Could not find visual studio')
|
||||
return
|
||||
}
|
||||
|
||||
mut obj_path := flag.all_after(' ')
|
||||
// msvc expects .obj not .o
|
||||
mut obj_path := '${path}bj'
|
||||
|
||||
if obj_path.ends_with('.o') {
|
||||
// msvc expects .obj not .o
|
||||
obj_path = obj_path + 'bj'
|
||||
}
|
||||
obj_path = os.realpath(obj_path)
|
||||
|
||||
if os.file_exists(obj_path) {
|
||||
println('$obj_path already build.')
|
||||
|
@ -482,14 +417,14 @@ fn build_thirdparty_obj_file_with_msvc(flag string) {
|
|||
}
|
||||
|
||||
println('$obj_path not found, building it (with msvc)...')
|
||||
parent := os.dir( obj_path )
|
||||
parent := os.dir(obj_path)
|
||||
files := os.ls(parent)
|
||||
|
||||
mut cfiles := ''
|
||||
for file in files {
|
||||
if file.ends_with('.c') {
|
||||
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"'
|
||||
|
|
|
@ -17,7 +17,7 @@ mut:
|
|||
modules []string // List of all modules registered by the application
|
||||
imports []string // List of all imports
|
||||
file_imports []FileImportTable // List of imports for file
|
||||
flags []string // ['-framework Cocoa', '-lglfw3']
|
||||
cflags []CFlag // ['-framework Cocoa', '-lglfw3']
|
||||
fn_cnt int //atomic
|
||||
obfuscate bool
|
||||
}
|
||||
|
@ -78,8 +78,6 @@ mut:
|
|||
scope_level int
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Type {
|
||||
mut:
|
||||
mod string
|
||||
|
@ -106,7 +104,6 @@ struct TypeNode {
|
|||
typ Type
|
||||
}
|
||||
|
||||
|
||||
// For debugging types
|
||||
fn (t Type) str() string {
|
||||
mut s := 'type "$t.name" {'
|
||||
|
|
Loading…
Reference in New Issue