From 5c93f942be81a0cbb4fcd76b241d754caccbfb8e Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 20 Oct 2020 17:38:29 +0300 Subject: [PATCH] docs,tests: add project_with_c_code_2 (passing structs from C to V to C) --- doc/docs.md | 2 + vlib/v/tests/project_with_c_code_2/.gitignore | 4 ++ .../v/tests/project_with_c_code_2/.v.mod.stop | 5 ++ vlib/v/tests/project_with_c_code_2/main.v | 14 +++++ .../tests/project_with_c_code_2/main2_test.v | 7 +++ .../tests/project_with_c_code_2/modc/header.h | 19 +++++++ .../v/tests/project_with_c_code_2/modc/impl.c | 32 +++++++++++ vlib/v/tests/project_with_c_code_2/modc/v.mod | 5 ++ .../project_with_c_code_2/modc/wrapper.v | 53 +++++++++++++++++++ 9 files changed, 141 insertions(+) create mode 100644 vlib/v/tests/project_with_c_code_2/.gitignore create mode 100644 vlib/v/tests/project_with_c_code_2/.v.mod.stop create mode 100644 vlib/v/tests/project_with_c_code_2/main.v create mode 100644 vlib/v/tests/project_with_c_code_2/main2_test.v create mode 100644 vlib/v/tests/project_with_c_code_2/modc/header.h create mode 100644 vlib/v/tests/project_with_c_code_2/modc/impl.c create mode 100644 vlib/v/tests/project_with_c_code_2/modc/v.mod create mode 100644 vlib/v/tests/project_with_c_code_2/modc/wrapper.v diff --git a/doc/docs.md b/doc/docs.md index 3ecc69bfc4..499d71be7d 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -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`. diff --git a/vlib/v/tests/project_with_c_code_2/.gitignore b/vlib/v/tests/project_with_c_code_2/.gitignore new file mode 100644 index 0000000000..11e5317789 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/.gitignore @@ -0,0 +1,4 @@ +main +main_test +modc/impl.o +modc/impl.obj diff --git a/vlib/v/tests/project_with_c_code_2/.v.mod.stop b/vlib/v/tests/project_with_c_code_2/.v.mod.stop new file mode 100644 index 0000000000..415b54b581 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/.v.mod.stop @@ -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 . diff --git a/vlib/v/tests/project_with_c_code_2/main.v b/vlib/v/tests/project_with_c_code_2/main.v new file mode 100644 index 0000000000..926f56a0ee --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/main.v @@ -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) +} diff --git a/vlib/v/tests/project_with_c_code_2/main2_test.v b/vlib/v/tests/project_with_c_code_2/main2_test.v new file mode 100644 index 0000000000..6281cb7f81 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/main2_test.v @@ -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 +} diff --git a/vlib/v/tests/project_with_c_code_2/modc/header.h b/vlib/v/tests/project_with_c_code_2/modc/header.h new file mode 100644 index 0000000000..b6975356ba --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/modc/header.h @@ -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 + diff --git a/vlib/v/tests/project_with_c_code_2/modc/impl.c b/vlib/v/tests/project_with_c_code_2/modc/impl.c new file mode 100644 index 0000000000..be015a5c94 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/modc/impl.c @@ -0,0 +1,32 @@ +#include "header.h" +#include +#include + + +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; ival); + } +} + +void destroy_atype(void *p) { + free(p); +} + diff --git a/vlib/v/tests/project_with_c_code_2/modc/v.mod b/vlib/v/tests/project_with_c_code_2/modc/v.mod new file mode 100644 index 0000000000..b696153145 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/modc/v.mod @@ -0,0 +1,5 @@ +Module { + name: 'modc', + description: 'Another module, wrapping some C code.', + dependencies: [] +} diff --git a/vlib/v/tests/project_with_c_code_2/modc/wrapper.v b/vlib/v/tests/project_with_c_code_2/modc/wrapper.v new file mode 100644 index 0000000000..f9c3283ac9 --- /dev/null +++ b/vlib/v/tests/project_with_c_code_2/modc/wrapper.v @@ -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) +}