条件编译

目前主要针对不同平台,实现条件编译

按照作者的说法,为了保持V的简单,不会加入预处理,但是支持条件编译

目前的条件编译有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下才会参与编译 | | _windows | windows下才会参与编译 | | _android | android平台下才会参与编译 | | _ios | ios平台下才会参与编译 | | _bare | 编译成裸机(metal)环境运行代码,才会参与编译,不进行排列组合 |

  • 编译器后端(backend)

    | 后缀名 | 编译器后端 | | ——— | ———————————————— | | .c | C语言为编译器后端时才会参与编译 | | .js | js语言为编译器后端时才会参与编译 | | .x64 | 直接生成x64机器码时才会参与编译 |

    以上2个维度排列组合:

    1. file.v //所有操作系统,所有编译后端都参与编译
    2. file.c.v //所有操作系统,C编译后端才参与编译,不会被特定平台覆盖,而是都编译
    3. file.js.v //所有操作系统,js编译后端才参与编译,不会被特定平台覆盖,而是都编译
    4. file_default.c.v //同目录如果存在特定平台的C后端文件,此文件会被忽略,不参与编译
    5. file_linux.c.v
    6. file_macos.c.v
    7. file_windows.c.v
    8. file_windows.js.v
    9. file_windows.x64.v
    10. ...

$if条件编译

以下表格是所有可以在编译时进行条件判断的变量:

OS Compilers Platforms Other
windows, linux, macos gcc, tinyc amd64, aarch64 debug, prod, test
mac, darwin, ios, clang, mingw x64, x32 js, glibc, prealloc
android,mach, dragonfly msvc little_endian no_bounds_checking
gnu, hpux, haiku, qnx cplusplus big_endian
solaris, linux_or_macos
  1. fn main() {
  2. $if windows {
  3. println('windows')
  4. $if msvc { // 可以在windows平台中,进一步判断是msvc还是mingw
  5. }
  6. $if mingw { // 可以在windows平台中,进一步判断是msvc还是mingw
  7. }
  8. }
  9. $if linux {
  10. println('linux')
  11. }
  12. $if macos { // 或者mac
  13. println('mac')
  14. }
  15. $if windows {
  16. } $else $if macos { // else if分支
  17. println('macos')
  18. } $else $if linux { // else if分支
  19. println('linux')
  20. } $else { // else分支
  21. println('others')
  22. }
  23. $if !windows { // 使用非运算
  24. }
  25. $if linux || macos { // 使用或运算符
  26. }
  27. $if linux && x64 { // 使用且运算符
  28. }
  29. // 其他条件编译的选项有:
  30. // freebsd,openbsd,netbsd,bsd,dragonfly,android,solaris
  31. // js,tinyc,clang,msvc,mingw
  32. }

识别自定义编译选项

  1. $if abc ? { //abc是自定义的编译选项,在条件编译时可以判断是否时候了自定义选项
  2. println('自定义选项abc存在')
  3. }
  4. //执行 v -d abc
  5. //或者 v -define abc

判断是否使用了-cg,进入调试模式

  1. $if debug {
  2. println('from debug')
  3. }
  4. //执行:
  5. //v run main.v -cg

判断是否在测试代码中执行

  1. fn test_comptime_if_test() {
  2. mut i := 0
  3. $if test { //如果在测试函数中,则执行
  4. i++
  5. }
  6. $if !test { //非测试函数中
  7. i--
  8. }
  9. assert i == 1
  10. }

判断平台是32位还是64位

  1. fn main() {
  2. mut x := 0
  3. $if x32 {
  4. println('system is 32 bit')
  5. x = 1
  6. }
  7. $if x64 {
  8. println('system is 64 bit')
  9. x = 2
  10. }
  11. }

判断平台使用的字节序是小字节序,还是大字节序

  1. fn main() {
  2. mut x := 0
  3. $if little_endian { //小字节序
  4. println('system is little endian')
  5. x = 1
  6. }
  7. $if big_endian { //大字节序
  8. println('system is big endian')
  9. x = 2
  10. }
  11. }

判断是否-prod生产编译

  1. fn main() {
  2. $if prod {
  3. println('prod')
  4. } $else {
  5. println('not prod')
  6. }
  7. }

跨平台交叉编译

编译器有一个选项-os用来编译生成指定平台的可执行文件

目前可以是:linux, mac, windows, msvc

  1. v -os linux ./main.v

内置全局变量

编译器中内置了开发和测试时需要的几个全局变量,方便编译,测试使用:

  1. module main
  2. fn main() {
  3. println('module: ${@MOD}') //当前模块
  4. println('fn: ${@FN}') //当前函数
  5. println('sturct: ${@STRUCT}') //当前结构体
  6. println('method: ${@METHOD}') //当前方法
  7. println('vexe: ${@VEXE}') //当前V编译器命令行可执行文件
  8. println('vexeroot: ${@VEXEROOT}') //当前V编译器命令行所在的目录
  9. println('file: ${@FILE}') //当前源代码文件名
  10. println('line: ${@LINE}') //当前代码所在的行
  11. println('column: ${@COLUMN}') //当前代码在当前行中的列数
  12. println('vhash: ${@VHASH}') //当前V命令行编译时的hash
  13. println('vmod_file: ${@VMOD_FILE}') //当前文件所处项目的v.mod文件内容
  14. println('vmodroot: ${@VMODROOT}') //当前文件所处项目的v.mod文件所在的目录
  15. }

另外,如果需要进一步解析v.mod的文件内容,可以导入v.mod模块,这个模块就是用来解析v.mod的

  1. import v.vmod
  2. vm := vmod.decode( @VMOD_FILE ) or { panic(err) }
  3. eprintln('$vm.name $vm.version\n $vm.description')