2019-09-06 15:12:04 +03:00
|
|
|
// 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.
|
|
|
|
|
2019-10-13 16:37:43 +03:00
|
|
|
module compiler
|
2019-09-06 15:12:04 +03:00
|
|
|
|
|
|
|
import os
|
|
|
|
|
2019-09-06 15:43:03 +03:00
|
|
|
// parsed cflag
|
2019-09-06 15:12:04 +03:00
|
|
|
struct CFlag{
|
2019-09-23 00:51:59 +03:00
|
|
|
mod string // the module in which the flag was given
|
2019-09-06 15:12:04 +03:00
|
|
|
os string // eg. windows | darwin | linux
|
|
|
|
name string // eg. -I
|
2019-09-06 15:43:03 +03:00
|
|
|
value string // eg. /path/to/include
|
2019-09-06 15:12:04 +03:00
|
|
|
}
|
|
|
|
|
2019-09-23 00:51:59 +03:00
|
|
|
fn (c &CFlag) str() string {
|
|
|
|
return 'CFlag{ name: "$c.name" value: "$c.value" mod: "$c.mod" os: "$c.os" }'
|
|
|
|
}
|
|
|
|
|
2019-09-06 15:12:04 +03:00
|
|
|
// get flags for current os
|
2019-09-23 00:51:59 +03:00
|
|
|
fn (v &V) get_os_cflags() []CFlag {
|
2019-09-06 15:12:04 +03:00
|
|
|
mut flags := []CFlag
|
|
|
|
for flag in v.table.cflags {
|
|
|
|
if flag.os == ''
|
|
|
|
|| (flag.os == 'linux' && v.os == .linux)
|
|
|
|
|| (flag.os == 'darwin' && v.os == .mac)
|
2019-09-28 14:18:04 +03:00
|
|
|
|| (flag.os == 'freebsd' && v.os == .freebsd)
|
2019-10-14 08:41:46 +03:00
|
|
|
|| (flag.os == 'windows' && v.os == .windows) {
|
2019-09-06 15:12:04 +03:00
|
|
|
flags << flag
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return flags
|
|
|
|
}
|
|
|
|
|
2019-09-23 00:51:59 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-09-06 15:12:04 +03:00
|
|
|
// format flag
|
|
|
|
fn (cf &CFlag) format() string {
|
|
|
|
mut value := cf.value
|
2019-09-16 00:41:12 +03:00
|
|
|
if cf.name == '-l' && value.len>0 {
|
|
|
|
return '${cf.name}${value}'.trim_space()
|
|
|
|
}
|
2019-09-06 15:12:04 +03:00
|
|
|
// 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()
|
|
|
|
}
|
|
|
|
|
2019-09-06 15:43:03 +03:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
|
|
|
// parse the flags to (table.cflags) []CFlag
|
2019-09-06 15:12:04 +03:00
|
|
|
// Note: clean up big time (joe-c)
|
2019-10-19 00:18:08 +03:00
|
|
|
fn (table mut Table) parse_cflag(cflag string, mod string) ?bool {
|
2019-09-06 15:12:04 +03:00
|
|
|
allowed_flags := [
|
|
|
|
'framework',
|
|
|
|
'library',
|
2019-09-08 12:02:03 +03:00
|
|
|
'I', 'l', 'L',
|
2019-09-06 15:12:04 +03:00
|
|
|
]
|
2019-10-19 00:18:08 +03:00
|
|
|
flag_orig := cflag.trim_space()
|
|
|
|
mut flag := flag_orig
|
2019-09-06 15:12:04 +03:00
|
|
|
if flag == '' {
|
2019-10-19 00:18:08 +03:00
|
|
|
return true
|
2019-09-06 15:12:04 +03:00
|
|
|
}
|
|
|
|
mut fos := ''
|
|
|
|
mut name := ''
|
2019-09-28 14:18:04 +03:00
|
|
|
if flag.starts_with('linux') || flag.starts_with('darwin') || flag.starts_with('freebsd') || flag.starts_with('windows') {
|
2019-11-30 13:09:05 +03:00
|
|
|
pos := flag.index(' ') or { return none }
|
2019-10-27 10:03:15 +03:00
|
|
|
fos = flag[..pos].trim_space()
|
|
|
|
flag = flag[pos..].trim_space()
|
2019-09-06 15:12:04 +03:00
|
|
|
}
|
|
|
|
for {
|
|
|
|
mut index := -1
|
|
|
|
mut value := ''
|
|
|
|
if flag[0] == `-` {
|
|
|
|
for f in allowed_flags {
|
|
|
|
i := 1+f.len
|
2019-10-27 10:03:15 +03:00
|
|
|
if i <= flag.len && f == flag[1..i] {
|
|
|
|
name = flag[..i].trim_space()
|
|
|
|
flag = flag[i..].trim_space()
|
2019-09-06 15:12:04 +03:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-30 13:09:05 +03:00
|
|
|
if i := flag.index(' ') {
|
|
|
|
if index == -1 || i < index {
|
|
|
|
index = i
|
|
|
|
}
|
|
|
|
}
|
2019-12-08 00:45:42 +03:00
|
|
|
if i := flag.index(',') {
|
|
|
|
if index == -1 || i < index {
|
|
|
|
index = i
|
2019-09-06 15:12:04 +03:00
|
|
|
}
|
2019-09-07 19:19:17 +03:00
|
|
|
}
|
|
|
|
if index != -1 && flag[index] == ` ` && flag[index+1] == `-` {
|
2019-09-06 15:12:04 +03:00
|
|
|
for f in allowed_flags {
|
2019-11-30 13:09:05 +03:00
|
|
|
j := index+f.len
|
|
|
|
if j < flag.len && f == flag[index..j] {
|
|
|
|
index = j
|
2019-09-06 15:12:04 +03:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2019-10-27 10:03:15 +03:00
|
|
|
value = flag[..index].trim_space()
|
|
|
|
flag = flag[index..].trim_space()
|
2019-09-07 19:19:17 +03:00
|
|
|
}
|
|
|
|
else if index != -1 && index < flag.len-2 && flag[index] == `,` {
|
2019-10-27 10:03:15 +03:00
|
|
|
value = flag[..index].trim_space()
|
|
|
|
flag = flag[index+1..].trim_space()
|
2019-09-07 19:19:17 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-09-06 15:12:04 +03:00
|
|
|
value = flag.trim_space()
|
|
|
|
index = -1
|
|
|
|
}
|
2019-10-19 00:18:08 +03:00
|
|
|
if (name in ['-I', '-l', '-L']) && value == '' {
|
2019-10-19 03:38:02 +03:00
|
|
|
hint := if name == '-l' { 'library name' } else { 'path' }
|
|
|
|
return error('bad #flag `$flag_orig`: missing $hint after `$name`')
|
|
|
|
}
|
2019-09-06 15:12:04 +03:00
|
|
|
cf := CFlag{
|
2019-09-23 00:51:59 +03:00
|
|
|
mod: mod,
|
2019-09-06 15:12:04 +03:00
|
|
|
os: fos,
|
|
|
|
name: name,
|
|
|
|
value: value
|
|
|
|
}
|
|
|
|
if !table.has_cflag(cf) {
|
|
|
|
table.cflags << cf
|
|
|
|
}
|
|
|
|
if index == -1 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2019-10-19 00:18:08 +03:00
|
|
|
return true
|
2019-09-06 15:12:04 +03:00
|
|
|
}
|
2019-09-23 00:51:59 +03:00
|
|
|
|
|
|
|
//TODO: implement msvc specific c_options_before_target and c_options_after_target ...
|
2019-10-14 08:41:46 +03:00
|
|
|
fn (cflags []CFlag) c_options_before_target_msvc() string { return '' }
|
|
|
|
fn (cflags []CFlag) c_options_after_target_msvc() string { return '' }
|
|
|
|
|
2019-11-30 13:09:05 +03:00
|
|
|
fn (cflags []CFlag) c_options_before_target() string {
|
2019-09-23 00:51:59 +03:00
|
|
|
// -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 {
|
|
|
|
// -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 {
|
2019-11-30 13:09:05 +03:00
|
|
|
if flag.value.ends_with('.o') || flag.value.ends_with('.obj') {
|
2019-09-23 00:51:59 +03:00
|
|
|
args << flag.format()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return args.join(' ')
|
|
|
|
}
|