// 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 compiler import os // parsed cflag struct CFlag{ 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 } fn (c &CFlag) str() string { return 'CFlag{ name: "$c.name" value: "$c.value" mod: "$c.mod" os: "$c.os" }' } // 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 == 'freebsd' && v.os == .freebsd) || (flag.os == 'windows' && v.os == .windows) { flags << flag } } 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 fn (cf &CFlag) format() string { mut value := cf.value if cf.name == '-l' && 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.realpath(value)+'"' } return '$cf.name $value'.trim_space() } // 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 // Note: clean up big time (joe-c) fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { allowed_flags := [ 'framework', 'library', 'I', 'l', 'L', ] flag_orig := cflag.trim_space() mut flag := flag_orig if flag == '' { return true } mut fos := '' mut name := '' if flag.starts_with('linux') || flag.starts_with('darwin') || flag.starts_with('freebsd') || flag.starts_with('windows') { pos := flag.index(' ') fos = flag[..pos].trim_space() flag = flag[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[1..i] { name = flag[..i].trim_space() flag = flag[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[index..i] { index = i break } } value = flag[..index].trim_space() flag = flag[index..].trim_space() } else if index != -1 && index < flag.len-2 && flag[index] == `,` { value = flag[..index].trim_space() flag = flag[index+1..].trim_space() } else { value = flag.trim_space() index = -1 } if (name in ['-I', '-l', '-L']) && value == '' { hint := if name == '-l' { 'library name' } else { 'path' } return error('bad #flag `$flag_orig`: missing $hint after `$name`') } cf := CFlag{ mod: mod, os: fos, name: name, value: value } if !table.has_cflag(cf) { table.cflags << cf } if index == -1 { break } } return true } //TODO: implement msvc specific c_options_before_target and c_options_after_target ... fn (cflags []CFlag) c_options_before_target_msvc() string { return '' } fn (cflags []CFlag) c_options_after_target_msvc() string { return '' } fn (cflags []CFlag) c_options_before_target() string { // -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 { if flag.value.ends_with('.o') || flag.value.ends_with('.obj') { args << flag.format() } } return args.join(' ') }