Files

363 lines
7.7 KiB
V

module pref
import os
pub struct Preferences {
pub mut:
verbose bool
output_file string
target_os string = os.user_os()
user_defines []string
backend string = 'c'
vroot string = detect_vroot()
}
pub fn new_preferences() &Preferences {
return &Preferences{}
}
fn detect_vroot() string {
baked_root := @VMODROOT
if baked_root.len > 0 {
return baked_root
}
if os.args.len > 0 && os.args[0].len > 0 {
vroot := detect_vroot_from(os.args[0])
if vroot.len > 0 {
return vroot
}
}
return detect_vroot_from(os.getwd())
}
fn detect_vroot_from(start string) string {
if start.len == 0 {
return ''
}
mut dir := start
if !os.is_abs_path(dir) {
cwd := os.getwd()
if cwd.len > 0 {
dir = os.join_path_single(cwd, dir)
}
}
if !os.is_dir(dir) {
dir = os.dir(dir)
}
for _ in 0 .. 8 {
if os.is_dir(os.join_path_single(os.join_path_single(dir, 'vlib'), 'builtin')) {
return dir
}
parent := os.dir(dir)
if parent == dir {
break
}
dir = parent
}
return ''
}
pub fn (p &Preferences) get_vlib_module_path(mod string) string {
mod_path := mod.replace('.', os.path_separator)
return os.join_path_single(os.join_path_single(p.vroot, 'vlib'), mod_path)
}
pub fn (p &Preferences) get_module_path(mod string, importing_file_path string) string {
mod_path := mod.replace('.', os.path_separator)
relative_path := os.join_path_single(os.dir(importing_file_path), mod_path)
if os.is_dir(relative_path) {
return relative_path
}
vlib_path := os.join_path_single(os.join_path_single(p.vroot, 'vlib'), mod_path)
if os.is_dir(vlib_path) {
return vlib_path
}
return ''
}
pub fn file_has_incompatible_os_suffix(file string, current_os string) bool {
os_name := normalized_os(current_os)
if os_name == 'windows' && file.contains('_nix.') {
return true
}
if os_name != 'windows' && file.contains('_windows.') {
return true
}
if os_name != 'linux' && file.contains('_linux.') {
return true
}
if os_name != 'macos' && (file.contains('_macos.') || file.contains('_darwin.')) {
return true
}
if os_name != 'macos' && os_name != 'freebsd' && os_name != 'openbsd' && os_name != 'netbsd'
&& os_name != 'dragonfly' && file.contains('_bsd.') {
return true
}
if os_name != 'android' && file.contains('_android') {
return true
}
if os_name != 'ios' && file.contains('_ios.') {
return true
}
if os_name != 'freebsd' && file.contains('_freebsd.') {
return true
}
if os_name != 'openbsd' && file.contains('_openbsd.') {
return true
}
if os_name != 'netbsd' && file.contains('_netbsd.') {
return true
}
if os_name != 'dragonfly' && file.contains('_dragonfly.') {
return true
}
if os_name != 'solaris' && file.contains('_solaris.') {
return true
}
if file.contains('.amd64.') || file.contains('_amd64.') || file.contains('.arm64.')
|| file.contains('_arm64.') {
return true
}
return false
}
pub fn get_v_files_from_dir(dir string, user_defines []string, target_os string) []string {
if dir == '' || !os.is_dir(dir) {
return []string{}
}
all_files := os.ls(dir) or { return []string{} }
mut has_os_specific := map[string]bool{}
for file in all_files {
if !file.ends_with('.v') || file.ends_with('.js.v') || file.contains('_test.') {
continue
}
if file_has_incompatible_os_suffix(file, target_os) {
continue
}
if base := os_specific_base(file, target_os) {
has_os_specific[base] = true
}
}
mut v_files := []string{}
for file in all_files {
if !file.ends_with('.v') || file.ends_with('.js.v') || file.contains('_test.') {
continue
}
if file_has_incompatible_os_suffix(file, target_os) {
continue
}
if base := default_file_base(file) {
if has_os_specific[base] {
continue
}
}
if file.contains('_notd_') {
feature := extract_define_feature(file, '_notd_')
if feature.len > 0 && feature in user_defines {
continue
}
} else if file.contains('_d_') {
feature := extract_define_feature(file, '_d_')
if feature.len == 0 || feature !in user_defines {
continue
}
}
v_files << os.join_path_single(dir, file)
}
return v_files
}
fn default_file_base(file string) ?string {
for marker in ['_default.c.v', '_default.v'] {
if file.ends_with(marker) {
return file[..file.len - marker.len]
}
}
return none
}
fn os_specific_base(file string, target_os string) ?string {
if _ := default_file_base(file) {
return none
}
mut suffixes := []string{}
os_name := normalized_os(target_os)
if os_name != 'windows' {
suffixes << '_nix'
}
match os_name {
'windows' {
suffixes << '_windows'
}
'macos' {
suffixes << '_macos'
suffixes << '_darwin'
}
'linux' {
suffixes << '_linux'
}
'android' {
suffixes << '_android'
}
'ios' {
suffixes << '_ios'
}
'freebsd' {
suffixes << '_freebsd'
suffixes << '_bsd'
}
'openbsd' {
suffixes << '_openbsd'
suffixes << '_bsd'
}
'netbsd' {
suffixes << '_netbsd'
suffixes << '_bsd'
}
'dragonfly' {
suffixes << '_dragonfly'
suffixes << '_bsd'
}
'solaris' {
suffixes << '_solaris'
}
else {}
}
for suffix in suffixes {
for ext in ['.c.v', '.v'] {
marker := suffix + ext
if file.ends_with(marker) {
return file[..file.len - marker.len]
}
}
}
return none
}
fn extract_define_feature(file string, marker string) string {
idx := file.index(marker) or { return '' }
rest := file[idx + marker.len..]
if rest.ends_with('.c.v') {
return rest[..rest.len - 4]
}
if rest.ends_with('.v') {
return rest[..rest.len - 2]
}
return rest
}
pub fn normalized_os(target_os string) string {
return match target_os {
'darwin' { 'macos' }
'mac' { 'macos' }
else { target_os }
}
}
pub fn (p &Preferences) normalized_target_os() string {
return normalized_os(p.target_os)
}
pub fn (p &Preferences) is_cross_target() bool {
return p.normalized_target_os() != normalized_os(os.user_os())
}
pub fn comptime_flag_value(p &Preferences, name string) bool {
match name {
'macos', 'darwin', 'mac' {
return p.normalized_target_os() == 'macos'
}
'linux' {
return p.normalized_target_os() == 'linux'
}
'windows' {
return p.normalized_target_os() == 'windows'
}
'freebsd' {
return p.normalized_target_os() == 'freebsd'
}
'openbsd' {
return p.normalized_target_os() == 'openbsd'
}
'netbsd' {
return p.normalized_target_os() == 'netbsd'
}
'dragonfly' {
return p.normalized_target_os() == 'dragonfly'
}
'android' {
return p.normalized_target_os() == 'android'
}
'posix', 'unix' {
return p.normalized_target_os() != 'windows'
}
'bsd' {
tos := p.normalized_target_os()
return tos == 'macos' || tos == 'freebsd' || tos == 'openbsd' || tos == 'netbsd'
|| tos == 'dragonfly'
}
'x64', 'amd64' {
$if amd64 {
return true
}
return false
}
'arm64', 'aarch64' {
$if arm64 {
return true
}
return false
}
'little_endian' {
$if little_endian {
return true
}
return false
}
'big_endian' {
$if big_endian {
return true
}
return false
}
'debug' {
$if debug {
return true
}
return false
}
'native' {
return p.backend == 'arm64'
}
'builtin_write_buf_to_fd_should_use_c_write' {
return p.backend == 'arm64'
}
'tinyc' {
return p.backend == 'arm64'
}
'no_backtrace' {
return p.backend == 'arm64' || name in p.user_defines
}
'gcboehm', 'gcboehm_opt', 'prealloc', 'autofree', 'no_bounds_checking', 'freestanding',
'nofloat' {
return name in p.user_defines
}
else {
return name in p.user_defines
}
}
}
pub fn comptime_optional_flag_value(p &Preferences, name string) bool {
if name in p.user_defines {
return true
}
return comptime_flag_value(p, name)
}
pub fn comptime_pkgconfig_value(name string) bool {
result := os.execute('pkg-config --exists ${name}')
return result.exit_code == 0
}