docs,tests: add project_with_c_code_2 (passing structs from C to V to C)
parent
0e55534c6e
commit
5c93f942be
|
@ -2413,6 +2413,8 @@ 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.
|
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 minimal example for using C code in a V wrapper module here:
|
You can see a complete minimal example for using C code in a V wrapper module here:
|
||||||
[project_with_c_code](https://github.com/vlang/v/tree/master/vlib/v/tests/project_with_c_code).
|
[project_with_c_code](https://github.com/vlang/v/tree/master/vlib/v/tests/project_with_c_code).
|
||||||
|
Another example, demonstrating passing structs from C to V and back again:
|
||||||
|
[interoperate between C to V to C](https://github.com/vlang/v/tree/master/vlib/v/tests/project_with_c_code_2).
|
||||||
|
|
||||||
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.
|
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`.
|
For example: `-cc gcc-9 -cflags -fsanitize=thread`.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
main
|
||||||
|
main_test
|
||||||
|
modc/impl.o
|
||||||
|
modc/impl.obj
|
|
@ -0,0 +1,5 @@
|
||||||
|
Do not delete this file.
|
||||||
|
|
||||||
|
It is used by V to stop the lookup for v.mod,
|
||||||
|
so that the top level vlib/v.mod is not found,
|
||||||
|
if you delete modc/v.mod .
|
|
@ -0,0 +1,14 @@
|
||||||
|
module main
|
||||||
|
|
||||||
|
import modc
|
||||||
|
|
||||||
|
// passing array of Vtype to C
|
||||||
|
// Vtype wraps a C type
|
||||||
|
fn main() {
|
||||||
|
a := [1, 2, 3, 4]
|
||||||
|
mut vals := []modc.Vtype{}
|
||||||
|
for v in a {
|
||||||
|
vals << modc.new_vtype(v)
|
||||||
|
}
|
||||||
|
modc.call_with_array_param(vals)
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import modc
|
||||||
|
|
||||||
|
fn test_using_c_code_in_the_same_module_works() {
|
||||||
|
x := modc.new_vtype(123)
|
||||||
|
modc.destroy_vtype(x)
|
||||||
|
assert true
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef CMOD_H
|
||||||
|
#define CMOD_H
|
||||||
|
|
||||||
|
struct Atype {
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void* new_atype(int n);
|
||||||
|
|
||||||
|
void handle_array(void *p, int n);
|
||||||
|
|
||||||
|
void handle_array2(void *p, int n);
|
||||||
|
|
||||||
|
void destroy_atype(void *p);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include "header.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
void* new_atype(int n) {
|
||||||
|
struct Atype *x = malloc(sizeof(struct Atype));
|
||||||
|
x->val = n;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pointer to first element of array
|
||||||
|
void handle_array(void *p, int n) {
|
||||||
|
struct Atype *ptr = (struct Atype *)p;
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
printf("%d - %d\n", i, ptr[i].val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pointer to array
|
||||||
|
void handle_array2(void *p, int n) {
|
||||||
|
struct Atype (*ptr)[];
|
||||||
|
ptr = p;
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
printf("%d - %d\n", i, (*ptr+i)->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_atype(void *p) {
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Module {
|
||||||
|
name: 'modc',
|
||||||
|
description: 'Another module, wrapping some C code.',
|
||||||
|
dependencies: []
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
module modc
|
||||||
|
|
||||||
|
#flag -I @VROOT
|
||||||
|
#flag @VROOT/impl.o
|
||||||
|
#include "header.h"
|
||||||
|
struct C.Atype {
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: [trusted] below, means that the C function, can be safely called outside unsafe{} blocks.
|
||||||
|
//
|
||||||
|
// By default, all C. functions are NOT trusted, and all V functions are by default trusted.
|
||||||
|
//
|
||||||
|
// Relatedly, if you want to mark a V function as unsafe, use [unsafe].
|
||||||
|
//
|
||||||
|
// The V compiler forces all calls of unsafe functions to be wrapped in `unsafe{...}` blocks.
|
||||||
|
struct Vtype {
|
||||||
|
pub mut:
|
||||||
|
p &C.Atype
|
||||||
|
}
|
||||||
|
|
||||||
|
fn C.new_atype(int) voidptr
|
||||||
|
|
||||||
|
[trusted]
|
||||||
|
fn C.handle_array(voidptr, int)
|
||||||
|
|
||||||
|
fn todo_remove_me() {
|
||||||
|
// TODO: remove this dummy function, when the vfmt bug of [trusted] after a void C function is fixed
|
||||||
|
}
|
||||||
|
|
||||||
|
[trusted]
|
||||||
|
fn C.handle_array2(voidptr, int)
|
||||||
|
|
||||||
|
fn C.destroy_atype(voidptr)
|
||||||
|
|
||||||
|
pub fn new_vtype(n int) Vtype {
|
||||||
|
t := C.new_atype(n)
|
||||||
|
return Vtype{t}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_with_array_param(arr []Vtype) {
|
||||||
|
mut carr := []C.Atype{}
|
||||||
|
for t in arr {
|
||||||
|
carr << *t.p
|
||||||
|
}
|
||||||
|
// make it safe
|
||||||
|
a := carr
|
||||||
|
C.handle_array(a.data, a.len)
|
||||||
|
C.handle_array2(a.data, a.len)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy_vtype(t Vtype) {
|
||||||
|
C.destroy_atype(t.p)
|
||||||
|
}
|
Loading…
Reference in New Issue