docs,tests: add project_with_c_code_2 (passing structs from C to V to C)

pull/6656/head
Delyan Angelov 2020-10-20 17:38:29 +03:00
parent 0e55534c6e
commit 5c93f942be
9 changed files with 141 additions and 0 deletions

View File

@ -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.
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).
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.
For example: `-cc gcc-9 -cflags -fsanitize=thread`.

View File

@ -0,0 +1,4 @@
main
main_test
modc/impl.o
modc/impl.obj

View File

@ -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 .

View File

@ -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)
}

View File

@ -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
}

View File

@ -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

View File

@ -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);
}

View File

@ -0,0 +1,5 @@
Module {
name: 'modc',
description: 'Another module, wrapping some C code.',
dependencies: []
}

View File

@ -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)
}