Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,148 @@
|
||||
> [!NOTE]
|
||||
> an important detail to remember, is that in V, the type always follows
|
||||
> the identifier in declarations, i.e. you use `x int` in V in function parameters,
|
||||
> and in struct declarations, not `int x`, like you would in C.
|
||||
|
||||
## Number types in C and V:
|
||||
|
||||
* A V `i8` is equivalent to C `signed char`, or `int8_t`.
|
||||
* A V `i16` is equivalent to C `short`, or `int16_t`.
|
||||
* A V `i32` is equivalent to C `int`, or `int32_t`.
|
||||
* A V `i64` is equivalent to C `long`, or `int64_t`.
|
||||
|
||||
* A V `u8` is equivalent to C `unsigned char`, or `uint8_t`.
|
||||
* A V `u16` is equivalent to C `unsigned short`, or `uint16_t`.
|
||||
* A V `u32` is equivalent to C `unsigned int`, or `uint32_t`.
|
||||
* A V `u64` is equivalent to C `unsigned long`, or `uint64_t`.
|
||||
|
||||
* A V `f32` is equivalent to C `float`.
|
||||
* A V `f64` is equivalent to C `double`.
|
||||
|
||||
`char` in C is a distinct type with implementation-defined signedness, so use
|
||||
V `char`, `&char`, or `charptr` when you need to match C `char`, `char*`,
|
||||
or `char**`.
|
||||
|
||||
* A V `isize` is equivalent to C `ssize_t`.
|
||||
It is a signed integer, and `isize` is guaranteed to be at least 16 bits.
|
||||
It is 32 bit on 32 bit platforms, and 64 bits on 64 bit ones.
|
||||
|
||||
* A V `usize` is equivalent to C `size_t`.
|
||||
It is an unsigned integer, and `usize` is guaranteed to be at least 16 bits.
|
||||
It is 32 bit on 32 bit platforms, and 64 bits on 64 bit ones.
|
||||
|
||||
* A V `int` is currently equivalent to C `int`, or `int64_t`.
|
||||
There are plans to make it equivalent to `isize`, so if you want to write C
|
||||
library wrappers, it is better to describe your `fn C.` parameters using `i32`
|
||||
instead of using `int`.
|
||||
|
||||
|
||||
## Representing pointers in C and V:
|
||||
Pointers in V are equivalent to pointers in C in usage.
|
||||
One difference in their declarations, is that the order of placing the pointer
|
||||
sign is swapped. For example, you use `long *` in C, which is equivalent to `&i64` in V.
|
||||
|
||||
If you have a C function `func_name`, that accepts a `int *`, and an `int` index,
|
||||
and returns an `unsigned char`:
|
||||
```c ignore
|
||||
unsigned char func_name(int * p, index int);
|
||||
```
|
||||
... then you can represent its function signature in V like this:
|
||||
|
||||
```v ignore
|
||||
fn C.func_name(p &int, index i32) u8
|
||||
```
|
||||
|
||||
|
||||
## Representing compound types in C and V:
|
||||
A V struct is the same as a C struct, with the same field names and
|
||||
types, but the order of declaring field names and their types in C structs
|
||||
and V structs is different - in C you use: `short field_name;`, but in V,
|
||||
that would be: `field_name i16`.
|
||||
|
||||
## Passing V strings to C functions:
|
||||
The V string type, is currently defined like this:
|
||||
```c
|
||||
struct string {
|
||||
u8* str;
|
||||
int len;
|
||||
int is_lit;
|
||||
};
|
||||
```
|
||||
|
||||
If you have a string `s` in V, and you also have a C function which
|
||||
accepts `unsigned char *` in C, you can pass `s.str` to that function.
|
||||
Do *not* pass `&s`, since that will be the address of the `s` struct
|
||||
itself, and not the address of the characters in it (which is pointed
|
||||
by `s.str`).
|
||||
|
||||
|
||||
## Passing V dynamic array elements to C functions:
|
||||
All V array types currently share the same C type, currently defined like this:
|
||||
```c
|
||||
struct array {
|
||||
void * data;
|
||||
// For arrays, the following `offset` field is 0.
|
||||
// For slices, the `offset` field contains the offset (in elements) from
|
||||
// the start of the original array.
|
||||
int offset;
|
||||
int len;
|
||||
int cap;
|
||||
int flags;
|
||||
int element_size;
|
||||
};
|
||||
```
|
||||
|
||||
If you want to pass a pointer to the elements of a V array `a`, to a C function,
|
||||
use `a.data`. NOTE: do *not* use `&a` for that purpose. That will result in the address
|
||||
of the `array` itself, getting passed to the C function, and *not* the address of the
|
||||
elements of the V array.
|
||||
|
||||
|
||||
## Passing V fixed array elements to C functions:
|
||||
Unlike dynamic arrays, fixed arrays are the same in both V and C.
|
||||
The address of the first element of the V fixed array of integers `fa` with
|
||||
type `[5]i32`, is `&fa[0]` . That address can be directly used a parameter to
|
||||
C functions, that accept `int * p` or `int arr[]` parameters.
|
||||
|
||||
|
||||
## Functions in V and C:
|
||||
The type of a V function, with no receiver, is equivalent to a C function,
|
||||
given that the types of the parameters are equivalent.
|
||||
|
||||
When a V function returns more than one value, the C function returns a struct.
|
||||
For example, these functions have equivalent types:
|
||||
```v ignore
|
||||
fn v_function(a u64, b i8) (i32, f32)
|
||||
```
|
||||
```c ignore
|
||||
struct { int i; float f; } c_function(unsigned long a, signed char b);
|
||||
````
|
||||
|
||||
A pointer to a V function is equivalent to a pointer to a C function, when the
|
||||
functions have equivalent types.
|
||||
|
||||
|
||||
## Other V types, that are currently not supported/documented for use with C:
|
||||
Other V types like interface, thread, chan, and map types are represented
|
||||
as C structs, but they are deliberately not yet completely documented for the
|
||||
purposes of C interoperability, since their implementations can still change.
|
||||
|
||||
C struct types containing bitfields, currently have no corresponding V types.
|
||||
|
||||
C++ class types have no corresponding V types.
|
||||
|
||||
|
||||
## Memory allocation in V and C
|
||||
Keep in mind, that V uses the Boehm's garbage collector by default. You can pass
|
||||
a pointer to allocated memory from C to V, just remember that the responsibility
|
||||
of freeing the pointer will remain with the C side, and if the C side frees the
|
||||
pointer while the V side still has a copy, your program will fail.
|
||||
|
||||
When passing a pointer from V to C, the V function must retain a visible copy
|
||||
of it in some V variable. Otherwise the V garbage collector may free the
|
||||
corresponding memory, while the C function is still using it. You can use the
|
||||
attribute `@[keep_args_alive]` to tag your `fn C.` declarations, that accept
|
||||
pointers, to keep them from being freed, while the call to your `C.fname()`
|
||||
function has not returned.
|
||||
For more details, see also this
|
||||
[test for keep_args_alive](vlib/v/slow_tests/keep_args_alive_test.c.v) .
|
||||
@@ -0,0 +1,94 @@
|
||||
# CodeLite Setup
|
||||
|
||||
CodeLite works well with V when you open the code as a
|
||||
[File System Workspace](https://docs.codelite.org/workspaces/file_system/)
|
||||
and define custom build targets with
|
||||
[CodeLite macros](https://docs.codelite.org/settings/macros/).
|
||||
|
||||
This guide uses POSIX shell commands, which match Linux and macOS. On Windows,
|
||||
use `.exe` outputs and replace `rm -f` with `del`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Put `v` on your `PATH`. If it is not on your `PATH`, replace `v` below
|
||||
with the absolute path to your V compiler.
|
||||
- Create a CodeLite workspace from your existing source tree:
|
||||
1. Open `File` -> `New` -> `New workspace`
|
||||
2. Choose `File System Workspace`
|
||||
3. Select the folder containing your V sources
|
||||
|
||||
Open the workspace settings by right-clicking the top-level folder and choosing
|
||||
`Settings...`.
|
||||
|
||||
## General Settings
|
||||
|
||||
Set these fields first:
|
||||
|
||||
- `Tool chain`: `gcc` or `clang`
|
||||
- `File extensions`: add `v`, `vsh`, and `vv`
|
||||
|
||||
CodeLite uses the selected tool chain mainly to parse build output, so any
|
||||
GNU-like tool chain is fine here.
|
||||
|
||||
For single-file programs, use:
|
||||
|
||||
- `Executable`: `$(CurrentFilePath)/$(CurrentFileName)`
|
||||
- `Working directory`: `$(CurrentFilePath)`
|
||||
|
||||
For a project rooted at the workspace folder, use:
|
||||
|
||||
- `Executable`: `$(WorkspacePath)/$(WorkspaceName)`
|
||||
- `Working directory`: `$(WorkspacePath)`
|
||||
|
||||
## Build Targets
|
||||
|
||||
The default `build` and `clean` targets can not be removed. Add `run` and
|
||||
`test` targets if you want them in the `Build` menu.
|
||||
|
||||
### Build the current file
|
||||
|
||||
This is the simplest setup for scripts, examples, and small programs:
|
||||
|
||||
- `build`:
|
||||
`v -g -o "$(CurrentFilePath)/$(CurrentFileName)" "$(CurrentFileFullPath)"`
|
||||
- `clean`: `rm -f "$(CurrentFilePath)/$(CurrentFileName)"`
|
||||
- `run`: `v run "$(CurrentFileFullPath)"`
|
||||
- `test`: `v test "$(CurrentFileFullPath)"`
|
||||
|
||||
### Build the whole workspace
|
||||
|
||||
If the workspace root is a V project with `v.mod`, or the workspace folder is
|
||||
your app entry point, use:
|
||||
|
||||
- `build`: `v -g -o "$(WorkspacePath)/$(WorkspaceName)" "$(WorkspacePath)"`
|
||||
- `clean`: `rm -f "$(WorkspacePath)/$(WorkspaceName)"`
|
||||
|
||||
If your app starts from a specific file such as `src/main.v`, replace
|
||||
`"$(WorkspacePath)"` with that file path in the `build` target.
|
||||
|
||||
## Running and Debugging
|
||||
|
||||
- Press `F7` to run the `build` target.
|
||||
- Use `Run` or `Debug` after `Executable` points to the file produced by the
|
||||
build target.
|
||||
- Keep `-g` in the build command so `gdb` or `lldb` can show V source
|
||||
locations.
|
||||
|
||||
## Better Compiler Errors in the IDE
|
||||
|
||||
If CodeLite opens the wrong file from compiler errors, add this workspace
|
||||
environment variable:
|
||||
|
||||
- `VERROR_PATHS=absolute`
|
||||
|
||||
That makes `v` print absolute file paths, which is often better for IDE
|
||||
launchers.
|
||||
|
||||
## Formatting and Language Features
|
||||
|
||||
For manual formatting, or for a formatter command inside CodeLite, use:
|
||||
|
||||
- `v fmt -w "$(CurrentFileFullPath)"`
|
||||
|
||||
For completion, go-to-definition, hover information, and related IDE features,
|
||||
use [v-analyzer](https://github.com/vlang/v-analyzer) alongside CodeLite.
|
||||
+9185
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -0,0 +1,217 @@
|
||||
# Ownership
|
||||
|
||||
V has an optional ownership system inspired by Rust that tracks owned values and prevents
|
||||
use-after-move bugs at compile time. It is currently focused on strings and is enabled
|
||||
with the `-ownership` flag.
|
||||
|
||||
## Quick start
|
||||
|
||||
```v okfmt
|
||||
fn main() {
|
||||
s1 := 'hello'.to_owned()
|
||||
s2 := s1 // s1 is moved to s2
|
||||
println(s1) // error: use of moved value: `s1`
|
||||
}
|
||||
```
|
||||
|
||||
Compile with ownership checking:
|
||||
|
||||
```
|
||||
v2 -ownership -o out main.v
|
||||
```
|
||||
|
||||
## Creating owned values
|
||||
|
||||
Call `.to_owned()` on a string to create an owned copy. Only strings created with
|
||||
`.to_owned()` participate in ownership tracking — regular string literals and primitive
|
||||
types (int, f64, bool, ...) are unaffected.
|
||||
|
||||
```v okfmt
|
||||
s := 'hello'.to_owned() // s is owned
|
||||
t := 'world' // t is a normal string, no ownership tracking
|
||||
```
|
||||
|
||||
## Move semantics
|
||||
|
||||
Assigning an owned value to another variable **moves** it. The original variable
|
||||
becomes unusable:
|
||||
|
||||
```v okfmt
|
||||
s1 := 'hello'.to_owned()
|
||||
s2 := s1 // move
|
||||
println(s1) // error: use of moved value: `s1`
|
||||
```
|
||||
|
||||
Passing an owned value to a function also moves it:
|
||||
|
||||
```v okfmt
|
||||
fn takes_ownership(s string) {
|
||||
println(s)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
s := 'hello'.to_owned()
|
||||
takes_ownership(s)
|
||||
println(s) // error: use of moved value: `s`
|
||||
}
|
||||
```
|
||||
|
||||
### Preventing moves with `.clone()`
|
||||
|
||||
Use `.clone()` to make an independent copy instead of moving:
|
||||
|
||||
```v okfmt
|
||||
s1 := 'hello'.to_owned()
|
||||
s2 := s1.clone() // s1 is NOT moved
|
||||
println(s1) // ok
|
||||
println(s2) // ok
|
||||
```
|
||||
|
||||
```v okfmt
|
||||
takes_ownership(s.clone()) // s is NOT moved
|
||||
println(s) // ok
|
||||
```
|
||||
|
||||
## Borrowing
|
||||
|
||||
Pass `&variable` to borrow without moving. The original stays usable:
|
||||
|
||||
```v okfmt
|
||||
fn calculate_length(s &string) int {
|
||||
return s.len
|
||||
}
|
||||
|
||||
fn main() {
|
||||
s := 'hello'.to_owned()
|
||||
len := calculate_length(&s)
|
||||
println(s) // ok — s was borrowed, not moved
|
||||
}
|
||||
```
|
||||
|
||||
### Explicit lifetimes
|
||||
|
||||
Ownership mode also supports explicit named lifetimes with `^name`.
|
||||
|
||||
Use `&^a T` for a borrowed reference with an explicit lifetime and `[^a]`
|
||||
in generic parameter and argument lists:
|
||||
|
||||
```v ignore
|
||||
struct Ignore {}
|
||||
|
||||
struct IgnoreMatch[^a] {}
|
||||
|
||||
fn matched_dir_entry[^a](self &^a Ignore) IgnoreMatch[^a] {
|
||||
return IgnoreMatch[^a]{}
|
||||
}
|
||||
```
|
||||
|
||||
`^` is used instead of Rust's `'` because `'` is already used for string and
|
||||
character literals in V.
|
||||
|
||||
Multiple immutable borrows are allowed:
|
||||
|
||||
```v okfmt
|
||||
s := 'hello'.to_owned()
|
||||
r1 := &s
|
||||
r2 := &s // ok
|
||||
```
|
||||
|
||||
Mutable borrows via `mut` parameters work too — the variable is usable after the
|
||||
call returns:
|
||||
|
||||
```v ignore
|
||||
fn append_world(mut s string) {
|
||||
s = s + ' world'
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut s := 'hello'.to_owned()
|
||||
append_world(mut s)
|
||||
println(s) // ok — prints "hello world"
|
||||
}
|
||||
```
|
||||
|
||||
### Borrow restrictions
|
||||
|
||||
A borrowed variable cannot be moved or reassigned while the borrow is active:
|
||||
|
||||
```v okfmt
|
||||
s := 'hello'.to_owned()
|
||||
r := &s
|
||||
s2 := s // error: cannot move `s` because it is borrowed
|
||||
```
|
||||
|
||||
```v okfmt
|
||||
mut s := 'hello'.to_owned()
|
||||
r := &s
|
||||
s = 'world'.to_owned() // error: cannot assign to `s` because it is borrowed
|
||||
```
|
||||
|
||||
## Return value ownership
|
||||
|
||||
Functions that create and return owned values transfer ownership to the caller:
|
||||
|
||||
```v okfmt
|
||||
fn gives_ownership() string {
|
||||
return 'hello'.to_owned()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
s1 := gives_ownership() // s1 is owned
|
||||
s2 := s1 // move
|
||||
println(s1) // error: use of moved value
|
||||
}
|
||||
```
|
||||
|
||||
Functions that return a parameter pass ownership through:
|
||||
|
||||
```v okfmt
|
||||
fn takes_and_gives_back(s string) string {
|
||||
return s
|
||||
}
|
||||
|
||||
fn main() {
|
||||
s1 := 'hello'.to_owned()
|
||||
s2 := takes_and_gives_back(s1) // s1 moved in, ownership comes back as s2
|
||||
println(s1) // error: s1 was moved
|
||||
println(s2) // ok
|
||||
}
|
||||
```
|
||||
|
||||
## Full example
|
||||
|
||||
From the Rust book, translated to V:
|
||||
|
||||
```v okfmt
|
||||
fn gives_ownership() string {
|
||||
s := 'hello'.to_owned()
|
||||
return s
|
||||
}
|
||||
|
||||
fn takes_and_gives_back(a_string string) string {
|
||||
return a_string
|
||||
}
|
||||
|
||||
fn main() {
|
||||
s1 := gives_ownership()
|
||||
s2 := 'hello'.to_owned()
|
||||
s3 := takes_and_gives_back(s2)
|
||||
println(s1) // ok
|
||||
println(s3) // ok
|
||||
}
|
||||
```
|
||||
|
||||
## Enabling ownership checking
|
||||
|
||||
Ownership checking is compiled into a separate `v2_ownership` binary using V's
|
||||
compile-time defines so there is zero overhead in the normal `v2` binary.
|
||||
|
||||
```
|
||||
v2 -ownership file.v # check and compile
|
||||
```
|
||||
|
||||
To build the ownership-enabled compiler manually:
|
||||
|
||||
```
|
||||
v -d ownership -o v2_ownership cmd/v2/v2.v
|
||||
```
|
||||
@@ -0,0 +1,133 @@
|
||||
Packaging V
|
||||
=============
|
||||
|
||||
Thank you for supporting V and its users, and for creating, *and maintaining* a package for it.
|
||||
|
||||
V is still changing, and installing it from source, is still the *recommended way*, to
|
||||
distribute it to most V users.
|
||||
|
||||
However, we understand that sooner or later people will want to adapt the
|
||||
upstream source to their favorite distro/platform, and that usually involves preparing a package
|
||||
that will be installed and updated (using a standardized package manager) just like all other
|
||||
programs in the distribution.
|
||||
|
||||
This document is for the brave people that want to prepare and
|
||||
*maintain* such a package.
|
||||
|
||||
Good luck.
|
||||
|
||||
Details
|
||||
=============
|
||||
|
||||
Preparing a package of the current version of V for distribution, has some peculiarities
|
||||
that must be understood, and taken into account, for the best experience of the users of
|
||||
your package, for your sanity, and for easier troubleshooting of problems when they happen.
|
||||
|
||||
1) V builds many of its commands on demand, to save both time and space. The source of the
|
||||
entry points of those commands is stored in the folder cmd/tools/ . If you are preparing a
|
||||
prebuilt V package, that needs to ensure that the final package after installation will be
|
||||
read only, that will be a problem, since V will try to write to its cmd/tools/ folder.
|
||||
To prevent that, you need to build *all* the commands/executables in that folder *ahead of time*.
|
||||
This can be done by the command `v build-tools`.
|
||||
|
||||
2) Tell V to not try to recompile its tools anymore. To do that, V supports checking for the
|
||||
presence of a file named `cmd/tools/.disable_autorecompilation` (that file is missing by default
|
||||
in the cloned version of V).
|
||||
Note: the content of this file does not matter, *only its presence does*.
|
||||
|
||||
3) V has a tool/command, that enables rapid updating from the latest master branch in its main
|
||||
repository. That tool is `v up`. Most distros however, have the policy of not allowing packages
|
||||
to make modifications to themselves. Instead, they require the user to use their package manager,
|
||||
provided by the distro/platform.
|
||||
|
||||
To facilitate that, it is usually best for all involved if you, as a package maintainer, remove
|
||||
or replace cmd/tools/vup.v, with a short v program, that advises the final V user to use the
|
||||
package manager tool, or to use a V installed from source instead.
|
||||
|
||||
4) Another V feature/command that can interfere with read only packaging is `v self`. We
|
||||
recommend that you disable this command as well, by replacing cmd/tools/vself.v with a small
|
||||
V program that informs the user that `v self` is not recommended when used with a packaged
|
||||
version of V, and then advises the user to install V from source if he wants to use `v self`.
|
||||
|
||||
5) The V source repo contains sizable folders like `.git/` and `thirdparty/tcc/.git/` which will
|
||||
not be needed by users of packages (they are not useful if `v up` is disabled,
|
||||
as recommended previously). Some other files, such as `Makefile`, `makev.bat`, and `GNUmakefile`
|
||||
will not be used either, so they can also be safely removed.
|
||||
|
||||
Depending on how stripped you want your package, you can remove the examples/ folder as well.
|
||||
It is usually good to have examples, but they could be in a separate package.
|
||||
|
||||
If a user attempts to compile the examples in that folder, it
|
||||
will not work in a read-only package (because the executables are put right next to the
|
||||
source `.v` files by default, unless `-o path_to_executable_name` is used).
|
||||
|
||||
6) Location of vlib/ . V expects, that its vlib/ folder, will be located right next to its
|
||||
executable, and that is currently hard to customize. It will be changed, if there is enough
|
||||
interest from package maintainers, expressed on the V issue tracker:
|
||||
https://github.com/vlang/v/issues
|
||||
|
||||
*However, you can* leave the executable in say /opt/vlang/v, with vlib/ in /opt/vlang/vlib/ ,
|
||||
then put a symlink from `/opt/vlang/v` to whatever folder that is on the user's PATH on your
|
||||
distro, i.e.: `sudo ln -s /opt/vlang/v /usr/bin/v` or `sudo ln -s /opt/vlang/v /bin/v` .
|
||||
|
||||
7) Location of the V executable can be controlled by setting the env variable VEXE.
|
||||
It defaults to the absolute path of the V executable.
|
||||
|
||||
8) Location of the modules folder for `v install` can be controlled by setting the env variable
|
||||
named `VMODULES`. By default, modules are installed to `~/.vmodules`,
|
||||
(`C:\Users\<user id>\.vmodules` on Windows).
|
||||
|
||||
9) Location of the folder used by V for its temporary files can be controlled by setting the env
|
||||
variable `VTMP`. By default, the system TEMP folder is used.
|
||||
|
||||
10) Setting additional V flags for each compilation can be done by setting the env variable
|
||||
`VFLAGS`.
|
||||
|
||||
Note: points 7, 8, 9, 10 above, allow you to create a small launcher shell script, named `v`,
|
||||
that sets those variables dynamically, according to the current user. You can then put
|
||||
*this shell script* inside your package bin folder, i.e. inside /usr/bin/v, or /bin/v etc,
|
||||
*instead of* the main V executable, or a symlink to it.
|
||||
|
||||
|
||||
Example script to prepare the V source folder for packaging:
|
||||
-----------------------------------------------------------
|
||||
|
||||
Combining all of the above, here is a small script, that can be used as a base for your packaging
|
||||
efforts:
|
||||
|
||||
```sh
|
||||
echo "println('use your package manager to update V," > cmd/tools/vup.v
|
||||
echo "or if you want more recent V versions, just clone V from source," >> cmd/tools/vup.v
|
||||
echo "see https://github.com/vlang/v#installing-v-from-source')" >> cmd/tools/vup.v
|
||||
|
||||
echo "println('v self is disabled for packaged versions of V." > cmd/tools/vself.v
|
||||
echo "Use your package manager, to update your V package instead." >> cmd/tools/vself.v
|
||||
echo "Alternatively, if you do want a more recent V version, just clone V from source," >> cmd/tools/vself.v
|
||||
echo "then follow the instructions here: https://github.com/vlang/v#installing-v-from-source')" >> cmd/tools/vself.v
|
||||
|
||||
v -prod -o v cmd/v ## build V itself with -prod
|
||||
./v -prod build-tools ## build all tools with -prod too
|
||||
touch ./cmd/tools/.disable_autorecompilation ## tell V to not try to recompile any tool anymore
|
||||
|
||||
### Cleanup folders that would not be needed inside a package,
|
||||
### that is distributed separately from the V source repository:
|
||||
rm -rf .git/
|
||||
rm -rf thirdparty/tcc/.git/
|
||||
```
|
||||
|
||||
Example `v` script for your bin folder:
|
||||
--------------------------------------------------
|
||||
|
||||
```sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
export VEXE="/opt/vlang/v"
|
||||
export VFLAGS="-cc /usr/bin/custom_cc"
|
||||
export VCACHE="/var/cache/custom_vcache_folder" ## ~/.vmodules/cache by default
|
||||
export VTMP="/var/cache/custom_tmp"
|
||||
export VMODULES="$HOME/.vmodules"
|
||||
|
||||
/opt/vlang/v $@
|
||||
```
|
||||
|
||||
Note: do not forget to also do this in your post install script: `chmod +x /usr/bin/v`
|
||||
@@ -0,0 +1,208 @@
|
||||
# V Work In Progress
|
||||
|
||||
***This document describes features that are not implemented, yet.
|
||||
Please refer to [docs.md](https://github.com/vlang/v/blob/master/doc/docs.md)
|
||||
for the current state of V***
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Concurrency](#concurrency)
|
||||
* [Variable Declarations](#variable-declarations)
|
||||
* [Strengths](#strengths)
|
||||
* [Weaknesses](#weaknesses)
|
||||
* [Compatibility](#compatibility)
|
||||
* [Automatic Lock](#automatic-lock)
|
||||
* [Channels](#channels)
|
||||
|
||||
## Concurrency
|
||||
|
||||
### Variable Declarations
|
||||
|
||||
Objects that are supposed to be used to exchange data between
|
||||
coroutines have to be declared with special care. Exactly one of the following
|
||||
4 kinds of declaration has to be chosen:
|
||||
|
||||
```v ignore
|
||||
a := ...
|
||||
mut b := ...
|
||||
shared c := ...
|
||||
atomic d := ...
|
||||
```
|
||||
|
||||
- `a` is declared as *constant* that can be passed to
|
||||
other coroutines and read without limitations. However
|
||||
it cannot be changed.
|
||||
- `b` can be accessed reading and writing but only from one
|
||||
coroutine. That coroutine *owns* the object. A `mut` variable can
|
||||
be passed to another coroutine (as receiver or function argument in
|
||||
the `go` statement or via a channel) but then ownership is passed,
|
||||
too, and only the other coroutine can access the object.<sup>1</sup>
|
||||
- `c` can be passed to coroutines an accessed
|
||||
*concurrently*.<sup>2</sup> In order to avoid data races it has to
|
||||
be locked before access can occur and unlocked to allow access to
|
||||
other coroutines. This is done by one the following block structures:
|
||||
```v ignore
|
||||
lock c {
|
||||
// read, modify, write c
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
```v ignore
|
||||
rlock c {
|
||||
// read c
|
||||
...
|
||||
}
|
||||
```
|
||||
Several variables may be specified: `lock x, y, z { ... }`.
|
||||
They are unlocked in the opposite order.
|
||||
- `d` can be passed to coroutines and accessed *concurrently*,
|
||||
too.<sup>3</sup> No lock is needed in this case, however
|
||||
`atomic` variables can only be 32/64 bit integers (or pointers)
|
||||
and access is limited to a small set of predefined idioms that have
|
||||
native hardware support.
|
||||
|
||||
To help making the correct decision the following table summarizes the
|
||||
different capabilities:
|
||||
|
||||
| | *default* | `mut` | `shared` | `atomic` |
|
||||
|:-------------------------|:---------:|:-----:|:--------:|:--------:|
|
||||
| write access | | + | + | + |
|
||||
| concurrent access | + | | + | + |
|
||||
| performance | ++ | ++ | | + |
|
||||
| sophisticated operations | + | + | + | |
|
||||
| structured data types | + | + | + | |
|
||||
|
||||
### Strengths
|
||||
|
||||
**default**
|
||||
|
||||
- very fast
|
||||
- unlimited access from different coroutines
|
||||
- easy to handle
|
||||
|
||||
**`mut`**
|
||||
|
||||
- very fast
|
||||
- easy to handle
|
||||
|
||||
**`shared`**
|
||||
|
||||
- concurrent access from different coroutines
|
||||
- data type may be complex structure
|
||||
- sophisticated access possible (several statements within one `lock`
|
||||
block)
|
||||
|
||||
**`atomic`**
|
||||
|
||||
- concurrent access from different coroutines
|
||||
- reasonably fast
|
||||
|
||||
### Weaknesses
|
||||
|
||||
**default**
|
||||
|
||||
- read only
|
||||
|
||||
**`mut`**
|
||||
|
||||
- access only from one coroutine at a time
|
||||
|
||||
**`shared`**
|
||||
|
||||
- lock/unlock are slow
|
||||
- moderately difficult to handle (needs `lock` block)
|
||||
|
||||
**`atomic`**
|
||||
|
||||
- limited to single (max. 64 bit) integers (and pointers)
|
||||
- only a small set of predefined operations possible
|
||||
- very difficult to handle correctly
|
||||
|
||||
<sup>1</sup> The owning coroutine will also free the memory space used
|
||||
for the object when it is no longer needed.
|
||||
<sup>2</sup> For `shared` objects the compiler adds code for reference
|
||||
counting. Once the counter reaches 0 the object is automatically freed.
|
||||
<sup>3</sup> Since an `atomic` variable is only a few bytes in size
|
||||
allocation would be an unnecessary overhead. Instead the compiler
|
||||
creates a global.
|
||||
|
||||
### Compatibility
|
||||
|
||||
Outside of `lock`/`rlock` blocks function arguments must in general
|
||||
match - with the familiar exception that objects declared `mut` can be
|
||||
used to call functions expecting immutable arguments:
|
||||
|
||||
```v ignore
|
||||
fn f(x St) {...}
|
||||
fn g(mut x St) {...}
|
||||
fn h(shared x St) {...}
|
||||
fn i(atomic x u64) {...}
|
||||
|
||||
a := St{...}
|
||||
f(a)
|
||||
|
||||
mut b := St{...}
|
||||
f(b)
|
||||
go g(mut b)
|
||||
// `b` should not be accessed here anymore
|
||||
|
||||
shared c := St{...}
|
||||
h(shared c)
|
||||
|
||||
atomic d &u64
|
||||
i(atomic d)
|
||||
```
|
||||
|
||||
Inside a `lock c {...}` block `c` behaves like a `mut`,
|
||||
inside an `rlock c {...}` block like an immutable:
|
||||
|
||||
```v ignore
|
||||
shared c := St{...}
|
||||
lock c {
|
||||
g(mut c)
|
||||
f(c)
|
||||
// call to h() not allowed inside `lock` block
|
||||
// since h() will lock `c` itself
|
||||
}
|
||||
rlock c {
|
||||
f(c)
|
||||
// call to g() or h() not allowed
|
||||
}
|
||||
```
|
||||
|
||||
### Automatic Lock
|
||||
|
||||
In general the compiler will generate an error message when a `shared`
|
||||
object is accessed outside of any corresponding `lock`/`rlock`
|
||||
block. However in simple and obvious cases the necessary lock/unlock
|
||||
can be generated automatically for `array`/`map` operations:
|
||||
|
||||
```v ignore
|
||||
shared a := []int{cap: 5}
|
||||
go h2(shared a)
|
||||
a << 3
|
||||
// keep in mind that `h2()` could change `a` between these statements
|
||||
a << 4
|
||||
x := a[1] // not necessarily `4`
|
||||
|
||||
shared b := map[string]int{}
|
||||
go h3(shared b)
|
||||
b['apple'] = 3
|
||||
c['plume'] = 7
|
||||
y := b['apple'] // not necessarily `3`
|
||||
|
||||
// iteration over elements
|
||||
for k, v in b {
|
||||
// concurrently changed k/v pairs may or may not be included
|
||||
}
|
||||
```
|
||||
|
||||
This is handy, but since other coroutines might access the `array`/`map`
|
||||
concurrently between the automatically locked statements, the results
|
||||
are sometimes surprising. Each statement should be seen as a single
|
||||
transaction that is unrelated to the previous or following
|
||||
statement. Therefore - but also for performance reasons - it's often
|
||||
better to group consecutive coherent statements in an explicit `lock` block.
|
||||
|
||||
### Channels
|
||||
@@ -0,0 +1,160 @@
|
||||
# Visual Studio Code Setup
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [V language support](#v-language-support)
|
||||
* [Visual Debugging](#visual-debugging)
|
||||
|
||||
## V language support
|
||||
|
||||
The [V VS Code Extension](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang)
|
||||
provides V language support for Visual Studio Code.
|
||||
|
||||

|
||||
|
||||
**Features:**
|
||||
|
||||
* Syntax Highlighting.
|
||||
* Code Snippets for quick coding.
|
||||
* Format code on file save as well as format manually (using v fmt).
|
||||
* Linter (Workspace files only).
|
||||
[more](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang)
|
||||
|
||||
**Hint:** This extension will not add the V compiler! Information on how to
|
||||
[install V compiler](https://github.com/vlang/v/blob/master/doc/docs.md#install-from-source)
|
||||
on your operating system.
|
||||
|
||||
### Setup Extension
|
||||
|
||||
Install [V VS Code Extension](https://marketplace.visualstudio.com/items?itemName=vlanguage.vscode-vlang).
|
||||
|
||||
## Visual Debugging
|
||||
|
||||

|
||||
|
||||
The [C/C++ Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
|
||||
for Visual Studio Code provides visual conditional debugging.
|
||||
|
||||
**Features:**
|
||||
|
||||
* Conditional breakpoints
|
||||
* Function breakpoints
|
||||
* Expression evaluation
|
||||
* Change Values
|
||||
[more Features & Documentation](https://code.visualstudio.com/docs/cpp/cpp-debug)
|
||||
|
||||
**Hint:** Not all types (e.g. Array) in V currently create the required
|
||||
[DWARF](https://en.wikipedia.org/wiki/DWARF) information to show and
|
||||
edit the variable.
|
||||
|
||||
### Setup Debugging
|
||||
|
||||
#### Step1: Configure the launch.json file
|
||||
|
||||
1. Install the
|
||||
[C/C++ Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
|
||||
2. Open `RUN AND DEBUG` panel (Debug Icon in left panel).
|
||||
3. Click on `Show` all automatic debug configurations.
|
||||
4. Select `Add config`.
|
||||
5. Select environment `C++ (GDB/LLDB)`.
|
||||
6. Change the line `"program": "Enter the program name, e.g. \"${workspaceFolder}/a.out\"",`
|
||||
to point to your compiled application e.g. `"program": "${workspaceFolder}/hello",`
|
||||
or a more flexible one `"program": "${fileDirname}/${fileBasenameNoExtension}",`
|
||||
when you want to debug the current opened file.
|
||||
|
||||
This will add a block to your `.workspace` file,
|
||||
or create the file `.vscode/launch.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit:
|
||||
// https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(lldb) Start",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "Enter the program name, e.g. \"${workspaceFolder}/a.out\"",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${fileDirname}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "lldb",
|
||||
"preLaunchTask": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Optional:** use `"program": "${fileDirname}/${fileBasenameNoExtension}"` to debug
|
||||
any current open source file with an existing binary with the same name but without any extension.
|
||||
|
||||
#### Step2: Configure the tasks.json file
|
||||
|
||||
Generally, you can manually compile the application with: `v -b c -g hello.v -o hello`,
|
||||
or for short: `v -g hello.v`, and then call the debugger.
|
||||
|
||||
The `-g` option will add the needed debugging information.
|
||||
You can find more debugging options in the [docs](docs.md#debugging).
|
||||
|
||||
VS Code provides a hook called `preLaunchTask`, which can be used to compile
|
||||
the application automatically every time you call the debugger.
|
||||
[preLaunchTask](https://code.visualstudio.com/docs/editor/debugging#_launchjson-attributes) launches
|
||||
a task before the start of a debug session, set this attribute to the label of a task specified
|
||||
in [task.json](https://code.visualstudio.com/docs/editor/tasks) (in the workspace's .vscode folder).
|
||||
Or, this can be set to `${defaultBuildTask}`, to use your default build task.
|
||||
|
||||
As explained, the `"preLaunchTask": "build"` needs to work with a `.vscode/tasks.json`
|
||||
with a label named `build`.
|
||||
|
||||
```json
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "v",
|
||||
"args": [
|
||||
"-g", // add more compiler options here if necessary
|
||||
"${relativeFile}" // or modify it according to your requirements
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"problemMatcher": {
|
||||
"owner": "v",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"],
|
||||
"pattern": {
|
||||
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
To allow your compiled application to be debugged.
|
||||
The application needs to include additional debugging information
|
||||
([DWARF](https://en.wikipedia.org/wiki/DWARF)).
|
||||
|
||||
1. Open your source code and set the required break points
|
||||
2. Click on the Debug Icon in the left Icon panel and click
|
||||
`> (lldb) Start`, or use `F5` to launch your application in debug mode.
|
||||
|
||||
For all options look at the official
|
||||
[C/C++ Extension documentation](https://code.visualstudio.com/docs/cpp/cpp-debug).
|
||||
Reference in new issue
Block a user