v/vlib/v/cflag/cflags.v

132 lines
3.3 KiB
V

// Copyright (c) 2019-2022 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 cflag
import os
// parsed cflag
pub struct CFlag {
pub:
mod string // the module in which the flag was given
os string // eg. windows | darwin | linux
name string // eg. -I
value string // eg. /path/to/include
pub mut:
cached string // eg. ~/.vmodules/cache/ea/ea9878886727367672163.o (for .o files)
}
pub fn (c &CFlag) str() string {
return 'CFlag{ name: "$c.name" value: "$c.value" mod: "$c.mod" os: "$c.os" cached: "$c.cached" }'
}
const fexisting_literal = r'$first_existing'
// expand the flag value
pub fn (cf &CFlag) eval() string {
mut value := ''
cflag_eval_outer_loop: for i := 0; i < cf.value.len; i++ {
x := cf.value[i]
if x == `$` {
remainder := cf.value[i..]
if remainder.starts_with(cflag.fexisting_literal) {
sparams := remainder[cflag.fexisting_literal.len + 1..].all_before(')')
i += sparams.len + cflag.fexisting_literal.len + 1
svalues := sparams.replace(',', '\n').split_into_lines().map(it.trim(' \'"'))
// mut found_spath := ''
for spath in svalues {
if os.exists(spath) {
// found_spath = spath
value += spath
continue cflag_eval_outer_loop
}
}
panic('>> error: none of the paths $svalues exist')
continue
}
}
value += x.ascii_str()
}
return value
}
// format flag
pub fn (cf &CFlag) format() string {
mut value := ''
if cf.cached != '' {
value = cf.cached
} else {
value = cf.eval()
}
if cf.name in ['-l', '-Wa', '-Wl', '-Wp'] && value.len > 0 {
return '$cf.name$value'.trim_space()
}
// convert to absolute path
if cf.name == '-I' || cf.name == '-L' || value.ends_with('.o') {
value = '"' + os.real_path(value) + '"'
}
return '$cf.name $value'.trim_space()
}
// TODO: implement msvc specific c_options_before_target and c_options_after_target ...
pub fn (cflags []CFlag) c_options_before_target_msvc() []string {
return []
}
pub fn (cflags []CFlag) c_options_after_target_msvc() []string {
return []
}
pub fn (cflags []CFlag) c_options_before_target() []string {
defines, others, _ := cflags.defines_others_libs()
mut args := []string{}
args << defines
args << others
return args
}
pub fn (cflags []CFlag) c_options_after_target() []string {
_, _, libs := cflags.defines_others_libs()
return libs
}
pub 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
}
pub 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
}
pub fn (cflags []CFlag) defines_others_libs() ([]string, []string, []string) {
copts_without_obj_files := cflags.c_options_without_object_files()
mut defines := []string{}
mut others := []string{}
mut libs := []string{}
for copt in copts_without_obj_files {
if copt.starts_with('-l') || copt.ends_with('.a') {
libs << copt
continue
}
if copt.starts_with('-D') {
defines << copt
continue
}
others << copt
}
return defines, others, libs
}