编译时代码
按照V语言作者的说法,为了保持V语言的简单,不会加入像C语言那样的预处理器,而是通过编译时代码来实现类似的功能。
编译时就是在编译阶段,根据编译时代码,动态生成代码。编译时代码使用最多的场景就是动态生成指定平台的代码,其他平台的代码不会生成。
V语言中编译时代码以$开头。
条件编译
条件编译是编译时代码最主要的应用场景:根据编译时条件,动态生成指定平台的代码,其他平台的代码不会生成,在C语言中使用了预处理器来实现。
目前的条件编译有2种主要方式:
1.根据源文件名后缀来实现条件编译
2.根据代码中的$if来实现条件编译
按源文件后缀名进行条件编译
源文件后缀包含了2个维度的条件编译:
通用源文件
后缀名编译条件只有 .v
所有操作系统,所有后端都参与编译
操作系统(os)
后缀名编译条件_default
默认的,表示所有操作系统都参与编译,比如file_default.c.v.同个目录中,如果同时存在默认的和平台特有的,平台特有的文件会参与编译,默认的被忽略
_nix
linux,unix,darwin,solaris下才会参与编译,或者说是非windows
_macos或 _darwin
mac下才会参与编译
_linux
linux下才会参与编译
_solaris
solaris下才会参与编译
_plan9
plan9下才会参与编译
_windows
windows下才会参与编译
_android
android平台下才会参与编译
_ios
ios平台下才会参与编译
_bare
编译成裸机(metal)环境运行代码,才会参与编译,不进行排列组合
编译器后端(backend)
后缀名编译器后端.c
C语言为编译器后端时才会参与编译
.js
js语言为编译器后端时才会参与编译
.native
直接生成x64机器码时才会参与编译
以上2个维度排列组合:
file.v #所有操作系统,所有编译后端都参与编译 file.c.v #所有操作系统,C编译后端才参与编译,不会被特定平台覆盖,而是都编译 file.js.v #所有操作系统,js编译后端才参与编译,不会被特定平台覆盖,而是都编译 file.native.v #所有操作系统,native编译后端才参与编译 file_default.c.v #同目录如果存在特定平台的C后端文件,此文件会被忽略,不参与编译 file_linux.c.v file_macos.c.v file_windows.c.v file_windows.js.v file_windows.x64.v ...正常情况下,在同一个模块中函数是不允许重复定义的,但是可以在.c.v或.js.v重复定义.v已经定义过的函数,.c.v或.js.v的同名函数会优先被执行,也就是覆盖了.v定义的函数。
这样的好处是可以在.v定义通用版本的函数,在.c.v定义针对C后端的函数,在.js.v定义针对js后端的函数。
mymodule/wrapper.v
module mymodule pub fn value() int { return 666 }mymodule/wrapper.c.v
module mymodule pub fn value() int { return 123 }mymodule/wrapper.js.v
module mymodule pub fn value() int { return 456 }主模块的main.v
module main import mymodule fn main() { println(mymodule.value()) //C编译器后端输出123 }
条件编译选项
内置条件编译选项
以下内置的条件编译选项,可以在代码中使用:
windows, linux, macos,plan9
gcc, tinyc
amd64, aarch64
debug, prod, test
mac, darwin, ios,
clang, mingw
x64, x32
js, glibc, prealloc
android,mach, dragonfly,termux
msvc
little_endian
no_bounds_checking
gnu, hpux, haiku, qnx
cplusplus
big_endian
freestanding
solaris, linux_or_macos
判断是否使用了-cg,进入调试模式
判断是否在测试代码中执行
判断平台是32位还是64位
判断平台使用的字节序是小字节序,还是大字节序
判断是否-prod生产编译
自定义编译选项
除了内置的条件编译选项,也可以识别自定义条件编译选项。
使用-d或-define来自定义编译选项,并且可以在代码中接收选项的传入值。
要特别注意的是:自定义条件编译选项名后面一定要加一个问号。
编译时,传递自定义条件编译变量:
同时使用多个自定义编译选项:
编译时反射
$for用来实现反射的效果,目前只实现了结构体的反射,可以在运行时获得某一个结构体所有字段和方法的信息。
遍历结构体字段,返回字段信息数组:[]FieldData
遍历结构体方法,返回方法信息数组:[]FunctionData
编译时动态字段赋值
编译时获取结构体字段信息
可以在$for循环中获取结构体字段的信息:
可获取的字段的信息,查看vlib/builtin.v源文件中的FieldData结构体:
获取结构体选项类型字段值
编译时动态调用方法
编译时判断泛型类型
可以使用编译时判断泛型的具体类型:
编译时全局变量
内置了开发和测试时需要的几个编译时全局变量,方便编译和测试使用:
编译时获取环境变量
可以使用$env()编译时函数获取环境变量。运行时代码中os.get_env()函数也可以实现相同的效果。
比较特别的是$env()也可以在#flay和#include等C宏中使用,让C宏定义更灵活。
编译时获取pkgconfig配置文件
可以使用$pkgconfig()编译时函数,来判断配置文件是否存在。
具体代码参考:集成C代码库章节。
编译时嵌入静态文件
可以使用$embed_file()编译时函数,把各种类型的文件在编译时嵌入到二进制文件中,更方便编译打包成单一可执行文件,方便部署,目前vweb框架中有使用到。
$embed_file()函数返回的类型为EmbedFileData,详细的使用可参考:vlib/v/embed_file/embed_file.v源文件。
如果没有特别指定,使用-prod进行生产编译时,$embed_file()函数会使用zlib对嵌入二进制的静态文件进行压缩。
编译时模板渲染
V语言内置了一个简单的txt和html模板,可以通过$tmpl编译时函数,进行渲染。
a.txt 模板文件内容
编译时解析v.mod文件
在编译阶段,如果需要解析v.mod的文件内容,可以导入v.mod模块,解析v.mod文件的内容。
编译时错误与警告
V语言内置2个编译时函数:compile_error和compile_warn,专门用来抛出编译时的错误和警告。
最后更新于
这有帮助吗?