Conditional compilation

Compile time code

$ is used as a prefix for compile-time operations.

$if condition

  1. fn main() {
  2. // Support for multiple conditions in one branch
  3. $if ios || android {
  4. println('Running on a mobile device!')
  5. }
  6. $if linux && x64 {
  7. println('64-bit Linux.')
  8. }
  9. // Usage as expression
  10. os := $if windows { 'Windows' } $else { 'UNIX' }
  11. println('Using $os')
  12. // $else-$if branches
  13. $if tinyc {
  14. println('tinyc')
  15. } $else $if clang {
  16. println('clang')
  17. } $else $if gcc {
  18. println('gcc')
  19. } $else {
  20. println('different compiler')
  21. }
  22. $if test {
  23. println('testing')
  24. }
  25. // v -cg ...
  26. $if debug {
  27. println('debugging')
  28. }
  29. // v -prod ...
  30. $if prod {
  31. println('production build')
  32. }
  33. // v -d option ...
  34. $if option ? {
  35. println('custom option')
  36. }
  37. }

If you want an if to be evaluated at compile time it must be prefixed with a $ sign. Right now it can be used to detect an OS, compiler, platform or compilation options. $if debug is a special option like $if windows or $if x32. If you’re using a custom ifdef, then you do need $if option ? {} and compile withv -d option. Full list of builtin options: | OS | Compilers | Platforms | Other | | —- | —- | —- | —- | | windows, linux, macos | gcc, tinyc | amd64, arm64 | debug, prod, test | | mac, darwin, ios, | clang, mingw | x64, x32 | js, glibc, prealloc | | android,mach, dragonfly | msvc | little_endian | no_bounds_checking, freestanding | | gnu, hpux, haiku, qnx | cplusplus | big_endian | no_segfault_handler, no_backtrace, no_main | | solaris | | | |

$embed_file

  1. // ignore
  2. import os
  3. fn main() {
  4. embedded_file := $embed_file('v.png')
  5. os.write_file('exported.png', embedded_file.to_string())?
  6. }

V can embed arbitrary files into the executable with the $embed_file(<path>) compile time call. Paths can be absolute or relative to the source file.

When you do not use -prod, the file will not be embedded. Instead, it will be loaded the first time your program calls embedded_file.data() at runtime, making it easier to change in external editor programs, without needing to recompile your executable.

When you compile with -prod, the file will be embedded inside your executable, increasing your binary size, but making it more self contained and thus easier to distribute. In this case, embedded_file.data() will cause no IO, and it will always return the same data.

$embed_file supports compression of the embedded file when compiling with -prod. Currently only one compression type is supported: zlib

  1. // ignore
  2. import os
  3. fn main() {
  4. embedded_file := $embed_file('v.png', .zlib) // compressed using zlib
  5. os.write_file('exported.png', embedded_file.to_string())?
  6. }

$tmpl for embedding and parsing V template files

V has a simple template language for text and html templates, and they can easily be embedded via $tmpl('path/to/template.txt'):

  1. // ignore
  2. fn build() string {
  3. name := 'Peter'
  4. age := 25
  5. numbers := [1, 2, 3]
  6. return $tmpl('1.txt')
  7. }
  8. fn main() {
  9. println(build())
  10. }

1.txt:

  1. name: @name
  2. age: @age
  3. numbers: @numbers
  4. @for number in numbers
  5. @number
  6. @end

output:

  1. name: Peter
  2. age: 25
  3. numbers: [1, 2, 3]
  4. 1
  5. 2
  6. 3

$env

  1. module main
  2. fn main() {
  3. compile_time_env := $env('ENV_VAR')
  4. println(compile_time_env)
  5. }

V can bring in values at compile time from environment variables. $env('ENV_VAR') can also be used in top-level #flag and #include statements: #flag linux -I $env('JAVA_HOME')/include.

$compile_error and $compile_warn

These two comptime functions are very useful for displaying custom errors/warnings during compile time.

Both receive as their only argument a string literal that contains the message to display:

  1. // failcompile nofmt
  2. // x.v
  3. module main
  4. $if linux {
  5. $compile_error('Linux is not supported')
  6. }
  7. fn main() {
  8. }
  9. $ v run x.v
  10. x.v:4:5: error: Linux is not supported
  11. 2 |
  12. 3 | $if linux {
  13. 4 | $compile_error('Linux is not supported')
  14. | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  15. 5 | }
  16. 6 |

Environment specific files

If a file has an environment-specific suffix, it will only be compiled for that environment.

  • .js.v => will be used only by the JS backend. These files can contain JS. code.
  • .c.v => will be used only by the C backend. These files can contain C. code.
  • .native.v => will be used only by V’s native backend.
  • _nix.c.v => will be used only on Unix systems (non Windows).
  • _${os}.c.v => will be used only on the specific os system. For example, _windows.c.v will be used only when compiling on Windows, or with -os windows.
  • _default.c.v => will be used only if there is NOT a more specific platform file. For example, if you have both file_linux.c.v and file_default.c.v, and you are compiling for linux, then only file_linux.c.v will be used, and file_default.c.v will be ignored.

Here is a more complete example: main.v:

  1. // ignore
  2. module main
  3. fn main() { println(message) }

main_default.c.v:

  1. // ignore
  2. module main
  3. const ( message = 'Hello world' )

main_linux.c.v:

  1. // ignore
  2. module main
  3. const ( message = 'Hello linux' )

main_windows.c.v:

  1. // ignore
  2. module main
  3. const ( message = 'Hello windows' )

With the example above:

  • when you compile for windows, you will get ‘Hello windows’
  • when you compile for linux, you will get ‘Hello linux’
  • when you compile for any other platform, you will get the non specific ‘Hello world’ message.

  • _d_customflag.v => will be used only if you pass -d customflag to V. That corresponds to $if customflag ? {}, but for a whole file, not just a single block. customflag should be a snakecase identifier, it can not contain arbitrary characters (only lower case latin letters + numbers + `). NB: a combinatorial_d_customflag_linux.c.vpostfix will not work. If you do need a custom flag file, that has platform dependent code, use the postfix_d_customflag.v, and then use plaftorm dependent compile time conditional blocks inside it, i.e.$if linux {}` etc.

  • _notd_customflag.v => similar to _d_customflag.v, but will be used only if you do NOT pass -d customflag to V.