compiler: compile thirdparty object files using module specific flags
parent
7aaf4012e4
commit
a585c8c22c
|
@ -147,15 +147,10 @@ fn (v mut V) cc() {
|
||||||
cflags := v.get_os_cflags()
|
cflags := v.get_os_cflags()
|
||||||
|
|
||||||
// add .o files
|
// add .o files
|
||||||
for flag in cflags {
|
a << cflags.c_options_only_object_files()
|
||||||
if !flag.value.ends_with('.o') { continue }
|
|
||||||
a << flag.format()
|
|
||||||
}
|
|
||||||
// add all flags (-I -l -L etc) not .o files
|
// add all flags (-I -l -L etc) not .o files
|
||||||
for flag in cflags {
|
a << cflags.c_options_without_object_files()
|
||||||
if flag.value.ends_with('.o') { continue }
|
|
||||||
a << flag.format()
|
|
||||||
}
|
|
||||||
|
|
||||||
a << libs
|
a << libs
|
||||||
// Without these libs compilation will fail on Linux
|
// Without these libs compilation will fail on Linux
|
||||||
|
@ -274,12 +269,7 @@ fn (c mut V) cc_windows_cross() {
|
||||||
mut args := '-o $c.out_name -w -L. '
|
mut args := '-o $c.out_name -w -L. '
|
||||||
cflags := c.get_os_cflags()
|
cflags := c.get_os_cflags()
|
||||||
// -I flags
|
// -I flags
|
||||||
for flag in cflags {
|
args += cflags.c_options_before_target()
|
||||||
if flag.name != '-l' {
|
|
||||||
args += flag.format()
|
|
||||||
args += ' '
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mut libs := ''
|
mut libs := ''
|
||||||
if c.pref.build_mode == .default_mode {
|
if c.pref.build_mode == .default_mode {
|
||||||
libs = '"$ModPath/vlib/builtin.o"'
|
libs = '"$ModPath/vlib/builtin.o"'
|
||||||
|
@ -292,13 +282,7 @@ fn (c mut V) cc_windows_cross() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args += ' $c.out_name_c '
|
args += ' $c.out_name_c '
|
||||||
// -l flags (libs)
|
args += cflags.c_options_after_target()
|
||||||
for flag in cflags {
|
|
||||||
if flag.name == '-l' {
|
|
||||||
args += flag.format()
|
|
||||||
args += ' '
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println('Cross compiling for Windows...')
|
println('Cross compiling for Windows...')
|
||||||
winroot := '$ModPath/winroot'
|
winroot := '$ModPath/winroot'
|
||||||
if !os.dir_exists(winroot) {
|
if !os.dir_exists(winroot) {
|
||||||
|
@ -339,14 +323,15 @@ fn (c mut V) cc_windows_cross() {
|
||||||
println('Done!')
|
println('Done!')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (c V) build_thirdparty_obj_files() {
|
fn (c &V) build_thirdparty_obj_files() {
|
||||||
for flag in c.get_os_cflags() {
|
for flag in c.get_os_cflags() {
|
||||||
if flag.value.ends_with('.o') {
|
if flag.value.ends_with('.o') {
|
||||||
|
rest_of_module_flags := c.get_rest_of_module_cflags( flag )
|
||||||
if c.os == .msvc {
|
if c.os == .msvc {
|
||||||
build_thirdparty_obj_file_with_msvc(flag.value)
|
build_thirdparty_obj_file_with_msvc(flag.value, rest_of_module_flags)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
build_thirdparty_obj_file(flag.value)
|
build_thirdparty_obj_file(flag.value, rest_of_module_flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,18 @@ import os
|
||||||
|
|
||||||
// parsed cflag
|
// parsed cflag
|
||||||
struct CFlag{
|
struct CFlag{
|
||||||
|
mod string // the module in which the flag was given
|
||||||
os string // eg. windows | darwin | linux
|
os string // eg. windows | darwin | linux
|
||||||
name string // eg. -I
|
name string // eg. -I
|
||||||
value string // eg. /path/to/include
|
value string // eg. /path/to/include
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (c &CFlag) str() string {
|
||||||
|
return 'CFlag{ name: "$c.name" value: "$c.value" mod: "$c.mod" os: "$c.os" }'
|
||||||
|
}
|
||||||
|
|
||||||
// get flags for current os
|
// get flags for current os
|
||||||
fn (v V) get_os_cflags() []CFlag {
|
fn (v &V) get_os_cflags() []CFlag {
|
||||||
mut flags := []CFlag
|
mut flags := []CFlag
|
||||||
for flag in v.table.cflags {
|
for flag in v.table.cflags {
|
||||||
if flag.os == ''
|
if flag.os == ''
|
||||||
|
@ -27,6 +32,18 @@ fn (v V) get_os_cflags() []CFlag {
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (v &V) get_rest_of_module_cflags(c &CFlag) []CFlag {
|
||||||
|
mut flags := []CFlag
|
||||||
|
cflags := v.get_os_cflags()
|
||||||
|
for flag in cflags {
|
||||||
|
if c.mod == flag.mod {
|
||||||
|
if c.name == flag.name && c.value == flag.value && c.os == flag.os { continue }
|
||||||
|
flags << flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
// format flag
|
// format flag
|
||||||
fn (cf &CFlag) format() string {
|
fn (cf &CFlag) format() string {
|
||||||
mut value := cf.value
|
mut value := cf.value
|
||||||
|
@ -52,7 +69,7 @@ fn (table &Table) has_cflag(cflag CFlag) bool {
|
||||||
|
|
||||||
// parse the flags to (table.cflags) []CFlag
|
// parse the flags to (table.cflags) []CFlag
|
||||||
// Note: clean up big time (joe-c)
|
// Note: clean up big time (joe-c)
|
||||||
fn (table mut Table) parse_cflag(cflag string) {
|
fn (table mut Table) parse_cflag(cflag string, mod string) {
|
||||||
allowed_flags := [
|
allowed_flags := [
|
||||||
'framework',
|
'framework',
|
||||||
'library',
|
'library',
|
||||||
|
@ -107,6 +124,7 @@ fn (table mut Table) parse_cflag(cflag string) {
|
||||||
index = -1
|
index = -1
|
||||||
}
|
}
|
||||||
cf := CFlag{
|
cf := CFlag{
|
||||||
|
mod: mod,
|
||||||
os: fos,
|
os: fos,
|
||||||
name: name,
|
name: name,
|
||||||
value: value
|
value: value
|
||||||
|
@ -119,3 +137,53 @@ fn (table mut Table) parse_cflag(cflag string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: implement msvc specific c_options_before_target and c_options_after_target ...
|
||||||
|
fn (cflags []CFlag) c_options_before_target() string {
|
||||||
|
$if msvc {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
// -I flags, optimization flags and so on
|
||||||
|
mut args:=[]string
|
||||||
|
for flag in cflags {
|
||||||
|
if flag.name != '-l' {
|
||||||
|
args << flag.format()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (cflags []CFlag) c_options_after_target() string {
|
||||||
|
$if msvc {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
// -l flags (libs)
|
||||||
|
mut args:=[]string
|
||||||
|
for flag in cflags {
|
||||||
|
if flag.name == '-l' {
|
||||||
|
args << flag.format()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (cflags []CFlag) c_options_without_object_files() string {
|
||||||
|
mut args:=[]string
|
||||||
|
for flag in cflags {
|
||||||
|
if flag.value.ends_with('.o') || flag.value.ends_with('.obj') {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
args << flag.format()
|
||||||
|
}
|
||||||
|
return args.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (cflags []CFlag) c_options_only_object_files() string {
|
||||||
|
mut args:=[]string
|
||||||
|
for flag in cflags {
|
||||||
|
if flag.value.ends_with('.o') || flag.value.ends_with('.obj') {
|
||||||
|
args << flag.format()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args.join(' ')
|
||||||
|
}
|
||||||
|
|
|
@ -239,7 +239,7 @@ fn (g mut CGen) add_to_main(s string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn build_thirdparty_obj_file(path string) {
|
fn build_thirdparty_obj_file(path string, moduleflags []CFlag) {
|
||||||
obj_path := os.realpath(path)
|
obj_path := os.realpath(path)
|
||||||
if os.file_exists(obj_path) {
|
if os.file_exists(obj_path) {
|
||||||
return
|
return
|
||||||
|
@ -255,7 +255,9 @@ fn build_thirdparty_obj_file(path string) {
|
||||||
}
|
}
|
||||||
cc := find_c_compiler()
|
cc := find_c_compiler()
|
||||||
cc_thirdparty_options := find_c_compiler_thirdparty_options()
|
cc_thirdparty_options := find_c_compiler_thirdparty_options()
|
||||||
cmd := '$cc $cc_thirdparty_options -c -o "$obj_path" $cfiles'
|
btarget := moduleflags.c_options_before_target()
|
||||||
|
atarget := moduleflags.c_options_after_target()
|
||||||
|
cmd := '$cc $cc_thirdparty_options $btarget -c -o "$obj_path" $cfiles $atarget '
|
||||||
res := os.exec(cmd) or {
|
res := os.exec(cmd) or {
|
||||||
println('failed thirdparty object build cmd: $cmd')
|
println('failed thirdparty object build cmd: $cmd')
|
||||||
cerror(err)
|
cerror(err)
|
||||||
|
|
|
@ -151,7 +151,7 @@ fn (p mut Parser) chash() {
|
||||||
flag = flag.replace('@VROOT', p.vroot)
|
flag = flag.replace('@VROOT', p.vroot)
|
||||||
flag = flag.replace('@VMOD', ModPath)
|
flag = flag.replace('@VMOD', ModPath)
|
||||||
p.log('adding flag "$flag"')
|
p.log('adding flag "$flag"')
|
||||||
p.table.parse_cflag(flag)
|
p.table.parse_cflag(flag, p.mod)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if hash.starts_with('include') {
|
if hash.starts_with('include') {
|
||||||
|
|
231
compiler/msvc.v
231
compiler/msvc.v
|
@ -295,13 +295,131 @@ pub fn (v mut V) cc_msvc() {
|
||||||
'odbccp32.lib'
|
'odbccp32.lib'
|
||||||
]
|
]
|
||||||
|
|
||||||
mut inc_paths := []string{}
|
sflags := v.get_os_cflags().msvc_string_flags()
|
||||||
mut lib_paths := []string{}
|
real_libs << sflags.real_libs
|
||||||
mut other_flags := []string{}
|
inc_paths := sflags.inc_paths
|
||||||
|
lib_paths := sflags.lib_paths
|
||||||
|
other_flags := sflags.other_flags
|
||||||
|
|
||||||
for flag in v.get_os_cflags() {
|
// Include the base paths
|
||||||
//println('fl: $flag.name | flag arg: $flag.value')
|
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
|
||||||
|
|
||||||
|
// Libs are passed to cl.exe which passes them to the linker
|
||||||
|
a << real_libs.join(' ')
|
||||||
|
|
||||||
|
a << '/link'
|
||||||
|
a << '/NOLOGO'
|
||||||
|
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
|
||||||
|
|
||||||
|
if !v.pref.is_prod {
|
||||||
|
a << '/DEBUG:FULL'
|
||||||
|
} else {
|
||||||
|
a << '/DEBUG:NONE'
|
||||||
|
}
|
||||||
|
|
||||||
|
a << lib_paths
|
||||||
|
|
||||||
|
args := a.join(' ')
|
||||||
|
|
||||||
|
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========== cl cmd line:')
|
||||||
|
println(cmd)
|
||||||
|
println('==========\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// println('$cmd')
|
||||||
|
|
||||||
|
res := os.exec(cmd) or {
|
||||||
|
println(err)
|
||||||
|
cerror('msvc error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if res.exit_code != 0 {
|
||||||
|
cerror(res.output)
|
||||||
|
}
|
||||||
|
// println(res)
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always remove the object file - it is completely unnecessary
|
||||||
|
os.rm(out_name_obj)
|
||||||
|
}
|
||||||
|
fn build_thirdparty_obj_file_with_msvc(path string, moduleflags []CFlag) {
|
||||||
|
msvc := find_msvc() or {
|
||||||
|
println('Could not find visual studio')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// msvc expects .obj not .o
|
||||||
|
mut obj_path := '${path}bj'
|
||||||
|
|
||||||
|
obj_path = os.realpath(obj_path)
|
||||||
|
|
||||||
|
if os.file_exists(obj_path) {
|
||||||
|
println('$obj_path already build.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
println('$obj_path not found, building it (with msvc)...')
|
||||||
|
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"'
|
||||||
|
|
||||||
|
//println('cfiles: $cfiles')
|
||||||
|
|
||||||
|
btarget := moduleflags.c_options_before_target()
|
||||||
|
atarget := moduleflags.c_options_after_target()
|
||||||
|
cmd := '""$msvc.full_cl_exe_path" /volatile:ms /Z7 $include_string /c $btarget $cfiles $atarget /Fo"$obj_path""'
|
||||||
|
//NB: the quotes above ARE balanced.
|
||||||
|
println('thirdparty cmd line: $cmd')
|
||||||
|
res := os.exec(cmd) or {
|
||||||
|
cerror(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println(res.output)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct MsvcStringFlags {
|
||||||
|
mut:
|
||||||
|
real_libs []string
|
||||||
|
inc_paths []string
|
||||||
|
lib_paths []string
|
||||||
|
other_flags []string
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (cflags []CFlag) msvc_string_flags() MsvcStringFlags {
|
||||||
|
mut real_libs := []string
|
||||||
|
mut inc_paths := []string
|
||||||
|
mut lib_paths := []string
|
||||||
|
mut other_flags := []string
|
||||||
|
for flag in cflags {
|
||||||
|
//println('fl: $flag.name | flag arg: $flag.value')
|
||||||
// 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
|
||||||
|
@ -335,107 +453,10 @@ pub fn (v mut V) cc_msvc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include the base paths
|
mut lpaths := []string
|
||||||
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
|
|
||||||
|
|
||||||
// Libs are passed to cl.exe which passes them to the linker
|
|
||||||
a << real_libs.join(' ')
|
|
||||||
|
|
||||||
a << '/link'
|
|
||||||
a << '/NOLOGO'
|
|
||||||
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 {
|
for l in lib_paths {
|
||||||
a << '/LIBPATH:"' + os.realpath(l) + '"'
|
lpaths << '/LIBPATH:"' + os.realpath(l) + '"'
|
||||||
}
|
}
|
||||||
|
|
||||||
if !v.pref.is_prod {
|
return MsvcStringFlags{ real_libs, inc_paths, lpaths, other_flags }
|
||||||
a << '/DEBUG:FULL'
|
|
||||||
} else {
|
|
||||||
a << '/DEBUG:NONE'
|
|
||||||
}
|
|
||||||
|
|
||||||
args := a.join(' ')
|
|
||||||
|
|
||||||
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========== cl cmd line:')
|
|
||||||
println(cmd)
|
|
||||||
println('==========\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
// println('$cmd')
|
|
||||||
|
|
||||||
res := os.exec(cmd) or {
|
|
||||||
println(err)
|
|
||||||
cerror('msvc error')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if res.exit_code != 0 {
|
|
||||||
cerror(res.output)
|
|
||||||
}
|
|
||||||
// println(res)
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always remove the object file - it is completely unnecessary
|
|
||||||
os.rm(out_name_obj)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_thirdparty_obj_file_with_msvc(path string) {
|
|
||||||
msvc := find_msvc() or {
|
|
||||||
println('Could not find visual studio')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// msvc expects .obj not .o
|
|
||||||
mut obj_path := '${path}bj'
|
|
||||||
|
|
||||||
obj_path = os.realpath(obj_path)
|
|
||||||
|
|
||||||
if os.file_exists(obj_path) {
|
|
||||||
println('$obj_path already build.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
println('$obj_path not found, building it (with msvc)...')
|
|
||||||
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"'
|
|
||||||
|
|
||||||
//println('cfiles: $cfiles')
|
|
||||||
|
|
||||||
cmd := '""$msvc.full_cl_exe_path" /volatile:ms /Z7 $include_string /c $cfiles /Fo"$obj_path""'
|
|
||||||
//NB: the quotes above ARE balanced.
|
|
||||||
println('thirdparty cmd line: $cmd')
|
|
||||||
res := os.exec(cmd) or {
|
|
||||||
cerror(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println(res.output)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue