mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
docs: tips for C/V interoperability
This commit is contained in:
parent
a02e1e0af2
commit
9d8116f895
98
doc/docs.md
98
doc/docs.md
@ -828,8 +828,6 @@ pub fn say_hi() {
|
|||||||
|
|
||||||
You can have as many .v files in `mymodule/` as you want.
|
You can have as many .v files in `mymodule/` as you want.
|
||||||
|
|
||||||
Build it with `v build module ~/code/modules/mymodule`.
|
|
||||||
|
|
||||||
That's it, you can now use it in your code:
|
That's it, you can now use it in your code:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
@ -1067,12 +1065,17 @@ fn test_hello() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`assert` keyword can be used outside of tests as well.
|
||||||
|
|
||||||
All test functions have to be placed in `*_test.v` files and begin with `test_`.
|
All test functions have to be placed in `*_test.v` files and begin with `test_`.
|
||||||
|
|
||||||
To run the tests do `v hello_test.v`. To test an entire module, do
|
To run the tests do `v hello_test.v`.
|
||||||
`v test mymodule`.
|
|
||||||
|
|
||||||
`assert` keyword can be used outside of tests as well.
|
To test an entire module, do `v test mymodule`.
|
||||||
|
|
||||||
|
You can also do `v test .` to test everything inside your curent folder (and underneath it).
|
||||||
|
|
||||||
|
You can pass `-stats` to v test, to see more details about the individual tests in each _test.v file.
|
||||||
|
|
||||||
## Memory management
|
## Memory management
|
||||||
|
|
||||||
@ -1223,14 +1226,19 @@ temporarily disabled).
|
|||||||
struct C.sqlite3
|
struct C.sqlite3
|
||||||
struct C.sqlite3_stmt
|
struct C.sqlite3_stmt
|
||||||
|
|
||||||
|
fn C.sqlite3_open(charptr, C.sqlite3)
|
||||||
fn C.sqlite3_column_int(stmt C.sqlite3_stmt, n int) int
|
fn C.sqlite3_column_int(stmt C.sqlite3_stmt, n int) int
|
||||||
|
// Or just define the type of parameter & leave C. prefix
|
||||||
|
fn C.sqlite3_prepare_v2(sqlite3, charptr, int, sqlite3_stmt, charptr) int
|
||||||
|
fn C.sqlite3_step(sqlite3)
|
||||||
|
fn C.sqlite3_finalize(sqlite3_stmt)
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
path := 'users.db'
|
path := 'users.db'
|
||||||
db := &C.sqlite3{!} // a temporary hack meaning `sqlite3* db = 0`
|
db := &C.sqlite3(0) // a temporary hack meaning `sqlite3* db = 0`
|
||||||
C.sqlite3_open(path.str, &db)
|
C.sqlite3_open(path.str, &db)
|
||||||
query := 'select count(*) from users'
|
query := 'select count(*) from users'
|
||||||
stmt := &C.sqlite3_stmt{!}
|
stmt := &C.sqlite3_stmt(0)
|
||||||
C.sqlite3_prepare_v2(db, query.str, - 1, &stmt, 0)
|
C.sqlite3_prepare_v2(db, query.str, - 1, &stmt, 0)
|
||||||
C.sqlite3_step(stmt)
|
C.sqlite3_step(stmt)
|
||||||
nr_users := C.sqlite3_column_int(stmt, 0)
|
nr_users := C.sqlite3_column_int(stmt, 0)
|
||||||
@ -1239,12 +1247,16 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Add `#flag` directives to the top of your V files to provide C compilation flags like `-l` for
|
Add `#flag` directives to the top of your V files to provide C compilation flags like:
|
||||||
linking, `-I` for adding include files locations, `-D` for setting compile time variables, etc.
|
|
||||||
|
|
||||||
You can use different flags for different targets. Right now, `linux`, `darwin` , and `windows` are supported.
|
- `-I` for adding C include files search paths
|
||||||
|
- `-l` for adding C library names that you want to get linked
|
||||||
|
- `-L` for adding C library files search paths
|
||||||
|
- `-D` for setting compile time variables
|
||||||
|
|
||||||
For now you have to use one flag per line:
|
You can use different flags for different targets. Right now, `linux`, `darwin` , `freebsd`, and `windows` are supported.
|
||||||
|
|
||||||
|
NB: For now you have to use one flag per line:
|
||||||
|
|
||||||
```v
|
```v
|
||||||
#flag linux -lsdl2
|
#flag linux -lsdl2
|
||||||
@ -1254,19 +1266,56 @@ For now you have to use one flag per line:
|
|||||||
#flag linux -DIMGUI_IMPL_API=
|
#flag linux -DIMGUI_IMPL_API=
|
||||||
```
|
```
|
||||||
|
|
||||||
C strings can be converted to V strings with `string(cstring)` or `string(cstring, len)`.
|
You can also add C code, in your V module. For example, lets say that your C code is located in a folder named 'c' inside your module folder. Then:
|
||||||
|
|
||||||
V uses `voidptr` for C's `void*` and `byteptr` for C's `byte*` or `char*`.
|
```v
|
||||||
|
#flag -I @VMODULE/c
|
||||||
|
#flag @VMODULE/c/implementation.o
|
||||||
|
#include "header.h"
|
||||||
|
```
|
||||||
|
|
||||||
To cast `voidptr` to V references use `user := &User(user_void_ptr)`.
|
... will make V look for an compiled .o file in your module folder/c/implementation.o .
|
||||||
|
If V finds it, the .o file will get linked to the main executable, that used the module.
|
||||||
|
If it does not find it, V assumes that there is a `@VMODULE/c/implementation.c` file,
|
||||||
|
and tries to compile it to a .o file, then will use that.
|
||||||
|
This allows you to have C code, that is contained in a V module, so that its distribution is easier.
|
||||||
|
You can see a complete example for using C code in a V wrapper module here:
|
||||||
|
[minimal V project, that has a module, which contains C code](https://github.com/vlang/v/tree/master/vlib/compiler/tests/project_with_c_code)
|
||||||
|
|
||||||
|
You can use `-cflags` to pass custom flags to the backend C compiler. You can also use `-cc` to change the default C backend compiler.
|
||||||
|
For example: `-cc gcc-9 -cflags -fsanitize=thread`.
|
||||||
|
|
||||||
|
Ordinary zero terminated C strings can be converted to V strings with `string(cstring)` or `string(cstring, len)`.
|
||||||
|
|
||||||
|
NB: `string/1` and `string/2` do NOT create a copy of the `cstring`, so you should NOT free it after calling `string()`. If you need to make a copy of the C string (some libc APIs like `getenv/1` pretty much require that, since they
|
||||||
|
return pointers to internal libc memory), you can use: `cstring_to_vstring(cstring)`
|
||||||
|
|
||||||
|
On Windows, C APIs often return so called `wide` strings (utf16 encoding).
|
||||||
|
These can be converted to V strings with `string_from_wide(&u16(cwidestring))` .
|
||||||
|
|
||||||
|
V has these types for easier interoperability with C:
|
||||||
|
|
||||||
|
- `voidptr` for C's `void*`,
|
||||||
|
- `byteptr` for C's `byte*` and
|
||||||
|
- `charptr` for C's `char*`.
|
||||||
|
- `&charptr` for C's `char**`
|
||||||
|
|
||||||
|
To cast `voidptr` to V references, use `user := &User(user_void_ptr)`.
|
||||||
|
|
||||||
`voidptr` can also be dereferenced to V structs by casting: `user := User(user_void_ptr)`.
|
`voidptr` can also be dereferenced to V structs by casting: `user := User(user_void_ptr)`.
|
||||||
|
|
||||||
Check out socket.v for an example of calling C code from V:
|
Check out [socket.v for an example of calling C code from V](https://github.com/vlang/v/blob/master/vlib/net/socket.v) .
|
||||||
[https://github.com/vlang/v/blob/master/vlib/net/socket.v](https://github.com/vlang/v/blob/master/vlib/net/socket.v)
|
|
||||||
|
|
||||||
To debug issues with the C code, `v -show_c_cmd .` is useful. It prints the
|
To debug issues with the generated C code, you can pass these flags:
|
||||||
C command that is used to build the program.
|
|
||||||
|
- `-cg` - produces a less optimized executable with more debug information in it.
|
||||||
|
- `-keep_c` - keep the generated C file, so your debugger can also use it.
|
||||||
|
- `-pretty_c` - run clang-format over the generated C file, so it looks nicer and is easier to read.
|
||||||
|
- `-show_c_cmd` - prints the C command that is used to build the program.
|
||||||
|
|
||||||
|
For best debugging experience, you can pass all of them at the same time: `v -cg -keep_c -pretty_c -show_c_cmd yourprogram.v` , then just run your debugger (gdb/lldb) or IDE with the produced executable `yourprogram`.
|
||||||
|
|
||||||
|
If you just want to inspect the generated C code, without compiling it further, you can also use: `-o file.c`. This will make V produce the `file.c` then stop.
|
||||||
|
|
||||||
## Compile time if
|
## Compile time if
|
||||||
|
|
||||||
@ -1359,13 +1408,10 @@ in order to improve readability:
|
|||||||
|
|
||||||
To improve safety and maintainability, operator overloading has several limitations:
|
To improve safety and maintainability, operator overloading has several limitations:
|
||||||
|
|
||||||
-It's only possible to overload `+, -, *, /` operators.
|
- It's only possible to overload `+, -, *, /` operators.
|
||||||
|
- Calling other functions inside operator functions is not allowed.
|
||||||
- Calling other functions inside operator functions is not allowed.
|
- Operator functions can't modify their arguments.
|
||||||
|
- Both arguments must have the same type (just like with all operators in V).
|
||||||
- Operator functions can't modify their arguments.
|
|
||||||
|
|
||||||
- Both arguments must have the same type (just like with all operators in V).
|
|
||||||
|
|
||||||
## Inline assembly
|
## Inline assembly
|
||||||
|
|
||||||
@ -1423,9 +1469,7 @@ If you have well-written, well-tested C code, then of course you can always simp
|
|||||||
Translating it to V gives you several advantages:
|
Translating it to V gives you several advantages:
|
||||||
|
|
||||||
- If you plan to develop that code base, you now have everything in one language, which is much safer and easier to develop in than C.
|
- If you plan to develop that code base, you now have everything in one language, which is much safer and easier to develop in than C.
|
||||||
|
|
||||||
- Cross-compilation becomes a lot easier. You don't have to worry about it at all.
|
- Cross-compilation becomes a lot easier. You don't have to worry about it at all.
|
||||||
|
|
||||||
- No more build flags and include files either.
|
- No more build flags and include files either.
|
||||||
|
|
||||||
## Hot code reloading
|
## Hot code reloading
|
||||||
|
Loading…
Reference in New Issue
Block a user