From 6e130cd446ec17fe0c0ba16a282f13320693c609 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 23 Dec 2019 12:09:00 +0200 Subject: [PATCH] compiler: support for custom flags [if custom]fn..{} , #flag custom, $if custom {} --- vlib/compiler/cc.v | 41 +++++++++++++++++++++++++++++-------- vlib/compiler/cflags.v | 15 ++++++++++++-- vlib/compiler/cgen.v | 6 +++++- vlib/compiler/comptime.v | 6 +++++- vlib/compiler/fn.v | 2 +- vlib/compiler/main.v | 44 ++++++++++++++++++++++++++++++++++------ vlib/compiler/parser.v | 14 ++++++++++++- 7 files changed, 107 insertions(+), 21 deletions(-) diff --git a/vlib/compiler/cc.v b/vlib/compiler/cc.v index b9eebf0224..d17d19b490 100644 --- a/vlib/compiler/cc.v +++ b/vlib/compiler/cc.v @@ -486,24 +486,47 @@ fn find_c_compiler_default() string { fn find_c_compiler_thirdparty_options() string { fullargs := env_vflags_and_os_args() - mut cflags := get_cmdline_cflags(fullargs) + mut cflags := get_cmdline_multiple_values(fullargs,'-cflags') $if !windows { - cflags += ' -fPIC' + cflags << '-fPIC' } if '-m32' in fullargs { - cflags += ' -m32' + cflags << '-m32' } - return cflags + return cflags.join(' ') } -fn get_cmdline_cflags(args []string) string { - mut cflags := '' +fn get_cmdline_multiple_values(args []string, optname string) []string { + mut flags := []string for ci, cv in args { - if cv == '-cflags' { - cflags += args[ci + 1] + ' ' + if cv == optname { + flags << args[ci + 1] } } - return cflags + return flags +} + +fn parse_defines(defines []string) ([]string,[]string) { + // '-d abc -d xyz=1 -d qwe=0' should produce: + // compile_defines: ['abc','xyz'] + // compile_defines_all ['abc','xyz','qwe'] + mut compile_defines := []string + mut compile_defines_all := []string + for dfn in defines { + dfn_parts := dfn.split('=') + if dfn_parts.len == 1 { + compile_defines << dfn + compile_defines_all << dfn + continue + } + if dfn_parts.len == 2 { + compile_defines_all << dfn_parts[0] + if dfn_parts[1] == '1' { + compile_defines << dfn_parts[0] + } + } + } + return compile_defines, compile_defines_all } fn missing_compiler_info() string { diff --git a/vlib/compiler/cflags.v b/vlib/compiler/cflags.v index 8648e803bf..ce51e4e186 100644 --- a/vlib/compiler/cflags.v +++ b/vlib/compiler/cflags.v @@ -19,10 +19,18 @@ pub fn (c &CFlag) str() string { // get flags for current os fn (v &V) get_os_cflags() []CFlag { mut flags := []CFlag + mut ctimedefines := []string + if v.compile_defines.len > 0 { + ctimedefines << v.compile_defines + } + 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 } + if flag.os in ctimedefines { + flags << flag + } } return flags } @@ -66,7 +74,7 @@ fn (table &Table) has_cflag(cflag CFlag) bool { // 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 { +fn (table mut Table) parse_cflag(cflag string, mod string, ctimedefines []string) ?bool { allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L', ] flag_orig := cflag.trim_space() mut flag := flag_orig @@ -74,7 +82,10 @@ fn (table mut Table) parse_cflag(cflag string, mod string) ?bool { return true } mut fos := '' - if flag.starts_with('linux') || flag.starts_with('darwin') || flag.starts_with('freebsd') || flag.starts_with('windows') { + mut allowed_os_overrides := ['linux','darwin','freebsd','windows'] + allowed_os_overrides << ctimedefines + for os_override in allowed_os_overrides { + if !flag.starts_with( os_override ) { continue } pos := flag.index(' ') or { return none } diff --git a/vlib/compiler/cgen.v b/vlib/compiler/cgen.v index e0d53579f2..be15bc386d 100644 --- a/vlib/compiler/cgen.v +++ b/vlib/compiler/cgen.v @@ -351,7 +351,11 @@ fn os_name_to_ifdef(name string) string { return '' } -fn platform_postfix_to_ifdefguard(name string) string { +fn (v &V) platform_postfix_to_ifdefguard(name string) string { + if name.starts_with('custom '){ + cdefine := name.replace('custom ','') + return '#ifdef CUSTOM_DEFINE_${cdefine}' + } s := match name { '.v'{ '' diff --git a/vlib/compiler/comptime.v b/vlib/compiler/comptime.v index b8c8377c6f..a1d66bcc6a 100644 --- a/vlib/compiler/comptime.v +++ b/vlib/compiler/comptime.v @@ -20,6 +20,7 @@ fn (p mut Parser) comp_time() { } name := p.check_name() p.fspace() + if name in supported_platforms { ifdef_name := os_name_to_ifdef(name) if name == 'mac' { @@ -99,6 +100,9 @@ fn (p mut Parser) comp_time() { else if name == 'clang' { p.comptime_if_block('__clang__') } + else if p.v.compile_defines_all.len > 0 && name in p.v.compile_defines_all { + p.comptime_if_block('CUSTOM_DEFINE_${name}') + } else { println('Supported platforms:') println(supported_platforms) @@ -209,7 +213,7 @@ fn (p mut Parser) chash() { flag = flag.replace('@VLIB_PATH', p.pref.vlib_path) flag = flag.replace('@VMOD', v_modules_path) // p.log('adding flag "$flag"') - _ = p.table.parse_cflag(flag, p.mod) or { + _ = p.table.parse_cflag(flag, p.mod, p.v.compile_defines_all ) or { p.error_with_token_index(err, p.cur_tok_index() - 1) return } diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index d16cb9f781..abf32dc210 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -749,7 +749,7 @@ fn (p mut Parser) verify_fn_before_call(f &Fn) { // p.tok == fn_name fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type string) { p.verify_fn_before_call(f) - is_comptime_define := f.comptime_define != '' && f.comptime_define != p.pref.comptime_define + is_comptime_define := f.comptime_define != '' && !(f.comptime_define in p.v.compile_defines ) if is_comptime_define { p.cgen.nogen = true } diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 96c8ef9b1f..76d2e959dd 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -76,6 +76,10 @@ pub mut: gen_parser_idx map[string]int cached_mods []string module_lookup_paths []string + + // -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another { will NOT get here }` + compile_defines []string // just ['vfmt'] + compile_defines_all []string // contains both: ['vfmt','another'] } struct Preferences { @@ -117,7 +121,6 @@ pub mut: // This is on by default, since a vast majority of users do not // work on the builtin module itself. // generating_vh bool - comptime_define string // -D vfmt for `if $vfmt {` fast bool // use tcc/x64 codegen enable_globals bool // allow __global for low level code // is_fmt bool @@ -251,7 +254,20 @@ pub fn (v mut V) compile() { else { cgen.genln('#include ') } + + if v.compile_defines_all.len > 0 { + cgen.genln('') + cgen.genln('// All custom defines : ' + v.compile_defines_all.join(',')) + cgen.genln('// Turned ON custom defines: ' + v.compile_defines.join(',')) + for cdefine in v.compile_defines { + cgen.genln('#define CUSTOM_DEFINE_${cdefine}') + } + cgen.genln('//') + cgen.genln('') + } + cgen.genln(c_builtin_types) + if !v.pref.is_bare { cgen.genln(c_headers) } @@ -638,6 +654,19 @@ pub fn (v &V) v_files_from_dir(dir string) []string { if file.ends_with('_c.v') && v.os == .js { continue } + if v.compile_defines_all.len > 0 && file.contains('_d_') { + mut allowed := false + for cdefine in v.compile_defines { + file_postfix := '_d_${cdefine}.v' + if file.ends_with(file_postfix) { + allowed = true + break + } + } + if !allowed { + continue + } + } res << filepath.join(dir,file) } return res @@ -905,8 +934,6 @@ pub fn new_v(args []string) &V { vgen_buf.writeln('module vgen\nimport strings') joined_args := args.join(' ') target_os := get_arg(joined_args, 'os', '') - comptime_define := get_arg(joined_args, 'd', '') - // println('comptimedefine=$comptime_define') mut out_name := get_arg(joined_args, 'o', 'a.out') mut dir := args.last() if 'run' in args { @@ -1031,7 +1058,11 @@ pub fn new_v(args []string) &V { exit(1) } mut out_name_c := get_vtmp_filename(out_name, '.tmp.c') - cflags := get_cmdline_cflags(args) + cflags := get_cmdline_multiple_values(args, '-cflags').join(' ') + + defines := get_cmdline_multiple_values(args, '-d') + compile_defines, compile_defines_all := parse_defines( defines ) + rdir := os.realpath(dir) rdir_name := os.filename(rdir) if '-bare' in args { @@ -1073,7 +1104,6 @@ pub fn new_v(args []string) &V { cflags: cflags ccompiler: find_c_compiler() building_v: !is_repl && (rdir_name == 'compiler' || rdir_name == 'v.v' || dir.contains('vlib')) - comptime_define: comptime_define // is_fmt: comptime_define == 'vfmt' user_mod_path: user_mod_path @@ -1104,7 +1134,9 @@ pub fn new_v(args []string) &V { vroot: vroot pref: pref mod: mod - vgen_buf: vgen_buf + vgen_buf: vgen_buf + compile_defines: compile_defines + compile_defines_all: compile_defines_all } } diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 638018eb5e..760de61058 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -155,10 +155,22 @@ fn (v mut V) new_parser_from_file(path string) Parser { println('warning: use "$p" file name instead of "$path"') } path_platform = path_ending - path_pcguard = platform_postfix_to_ifdefguard(path_ending) + path_pcguard = v.platform_postfix_to_ifdefguard(path_ending) break } } + + if v.compile_defines.len > 0 { + for cdefine in v.compile_defines { + custom_path_ending := '_d_${cdefine}.v' + if path.ends_with(custom_path_ending){ + path_platform = custom_path_ending + path_pcguard = v.platform_postfix_to_ifdefguard('custom $cdefine') + break + } + } + } + mut p := v.new_parser(new_scanner_file(path)) p = { p |