Example usage in unit test.
This commit is contained in:
parent
362173091d
commit
29a1342d00
7 changed files with 274 additions and 35 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -17,6 +17,8 @@ test-driver
|
||||||
*.log
|
*.log
|
||||||
*.trs
|
*.trs
|
||||||
|
|
||||||
|
tests/*.out
|
||||||
|
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
*.so
|
*.so
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ check_PROGRAMS += \
|
||||||
capn_test_SOURCES = \
|
capn_test_SOURCES = \
|
||||||
tests/capn-test.cpp \
|
tests/capn-test.cpp \
|
||||||
tests/capn-stream-test.cpp \
|
tests/capn-stream-test.cpp \
|
||||||
|
tests/example-test.cpp \
|
||||||
|
tests/example.capnp.c \
|
||||||
compiler/test.capnp.c \
|
compiler/test.capnp.c \
|
||||||
compiler/schema-test.cpp \
|
compiler/schema-test.cpp \
|
||||||
compiler/schema.capnp.c
|
compiler/schema.capnp.c
|
||||||
|
|
|
||||||
103
README.md
103
README.md
|
|
@ -4,15 +4,78 @@ capnpc-c
|
||||||
This is a C plugin for [Cap'n Proto](http://kentonv.github.io/capnproto), an
|
This is a C plugin for [Cap'n Proto](http://kentonv.github.io/capnproto), an
|
||||||
efficient protocol for sharing data and capabilities.
|
efficient protocol for sharing data and capabilities.
|
||||||
|
|
||||||
This is only the plugin, to properly make use of it you need to download, build
|
This is only the code generator plugin, to properly make use of it you
|
||||||
and install capnpc and then build and install this project and then you can
|
need to download, build and install capnpc and then build and install
|
||||||
utilize it as:
|
this project and then you can utilize it as:
|
||||||
|
|
||||||
capnpc compiler/test.capnp -oc
|
```sh
|
||||||
|
capnpc compiler/test.capnp -oc
|
||||||
|
```
|
||||||
|
|
||||||
[](https://travis-ci.org/opensourcerouting/c-capnproto)
|
[](https://travis-ci.org/opensourcerouting/c-capnproto)
|
||||||
|
|
||||||
## status
|
## Building on Linux
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/opensourcerouting/c-capnproto
|
||||||
|
cd c-capnproto
|
||||||
|
git submodule update --init --recursive
|
||||||
|
autoreconf -f -i -s
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
make check
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Generating C code from a `.capnp` schema file
|
||||||
|
|
||||||
|
The `compiler` directory contains the C language plugin (`capnpc-c`) for use with the `capnp` tool: https://capnproto.org/capnp-tool.html.
|
||||||
|
|
||||||
|
`capnp` will by default search `$PATH` for `capnpc-c` - if it's on your PATH, you can generate code for your schema as follows:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
capnp compile -o c myschema.capnp
|
||||||
|
```
|
||||||
|
|
||||||
|
Otherwise, you can specify the path to the c plugin:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
capnp compile -o ./capnpc-c myschema.capnp
|
||||||
|
```
|
||||||
|
|
||||||
|
`capnp` generates a C struct that corresponds to each capn proto struct, along with read/write functions that convert to/from capn proto form.
|
||||||
|
|
||||||
|
If you want accessor functions for struct members, use attribute `fieldgetset` in your `.capnp` file as follows:
|
||||||
|
|
||||||
|
```capnp
|
||||||
|
using C = import "${c-capnproto}/compiler/c.capnp";
|
||||||
|
|
||||||
|
$C.fieldgetset;
|
||||||
|
|
||||||
|
struct MyStruct {}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example C code
|
||||||
|
|
||||||
|
See the unit tests in [`tests/example-test.cpp`](tests/example-test.cpp). The example schema file is [`tests/example.capnp`](tests/example.capnp). The tests are written in C++, but only use C features.
|
||||||
|
|
||||||
|
You need to compile these runtime library files and link them into your own project's binaries:
|
||||||
|
|
||||||
|
* [`lib/capn.c`](lib/capn.c)
|
||||||
|
* [`lib/capn-malloc.c`](lib/capn-malloc.c)
|
||||||
|
* [`lib/capn-stream.c`](lib/capn-stream.c)
|
||||||
|
|
||||||
|
Your include path must contain the runtime library directory [`lib`](lib). Header file [`lib/capnp_c.h`](lib/capnp_c.h) contains the public interfaces of the library.
|
||||||
|
|
||||||
|
For further reference, please see the other unit tests in [`tests`](tests), and header file [`lib/capnp_c.h`](lib/capnp_c.h).
|
||||||
|
|
||||||
|
The project [`quagga-capnproto`](https://github.com/opensourcerouting/quagga-capnproto) uses `c-capnproto` and contains some good examples, as found with [this github repository search](https://github.com/opensourcerouting/quagga-capnproto/search?utf8=%E2%9C%93&q=capn&type=):
|
||||||
|
|
||||||
|
* Serialization in function [`bgp_notify_send()`](https://github.com/opensourcerouting/quagga-capnproto/blob/27061648f3418fac0d217b16a46add534343e841/bgpd/bgp_zmq.c#L81-L96) in file `quagga-capnproto/bgpd/bgp_zmq.c`
|
||||||
|
* Deserialization in function [`qzc_callback()`](https://github.com/opensourcerouting/quagga-capnproto/blob/27061648f3418fac0d217b16a46add534343e841/lib/qzc.c#L249-L257) in file `quagga-capnproto/lib/qzc.c`
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
This is a merge of 3 forks of [James McKaskill's great
|
This is a merge of 3 forks of [James McKaskill's great
|
||||||
work](https://github.com/jmckaskill/c-capnproto), which has been untouched for
|
work](https://github.com/jmckaskill/c-capnproto), which has been untouched for
|
||||||
|
|
@ -21,33 +84,3 @@ a while:
|
||||||
- [liamstask's fork](https://github.com/liamstask/c-capnproto)
|
- [liamstask's fork](https://github.com/liamstask/c-capnproto)
|
||||||
- [baruch's fork](https://github.com/baruch/c-capnproto)
|
- [baruch's fork](https://github.com/baruch/c-capnproto)
|
||||||
- [kylemanna's fork](https://github.com/kylemanna/c-capnproto)
|
- [kylemanna's fork](https://github.com/kylemanna/c-capnproto)
|
||||||
|
|
||||||
|
|
||||||
## usage
|
|
||||||
|
|
||||||
The `compiler` directory contains the C language plugin (`capnpc-c`) for use with the `capnp` tool: https://capnproto.org/capnp-tool.html.
|
|
||||||
|
|
||||||
`capnp` will by default search `$PATH` for `capnpc-c` - if it's on your PATH, you can generate code for your schema as follows:
|
|
||||||
|
|
||||||
$ capnp compile -o c myschema.capnp
|
|
||||||
|
|
||||||
Otherwise, you can specify the path to the c plugin:
|
|
||||||
|
|
||||||
$ capnp compile -o ./capnpc-c myschema.capnp
|
|
||||||
|
|
||||||
`capnp` generates a C struct that corresponds to each capn proto struct, along with read/write functions that convert to/from capn proto form.
|
|
||||||
|
|
||||||
TBD whether it will make sense in the future to provide accessor functions for struct members, rather than converting entire structs.
|
|
||||||
|
|
||||||
## building on linux
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://github.com/opensourcerouting/c-capnproto
|
|
||||||
cd c-capnproto
|
|
||||||
git submodule update --init --recursive
|
|
||||||
autoreconf -f -i -s
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make check
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
||||||
72
tests/example-test.cpp
Normal file
72
tests/example-test.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* example-test.cpp
|
||||||
|
*
|
||||||
|
* Some simple examples using c-capnproto
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Alex Helfet
|
||||||
|
*
|
||||||
|
* This software may be modified and distributed under the terms
|
||||||
|
* of the MIT license. See the LICENSE file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "capnp_c.h"
|
||||||
|
#include "example.capnp.h"
|
||||||
|
|
||||||
|
TEST(Examples, RoundTrip) {
|
||||||
|
uint8_t buf[4096];
|
||||||
|
ssize_t sz = 0;
|
||||||
|
|
||||||
|
const char *s = "Hello.";
|
||||||
|
|
||||||
|
{
|
||||||
|
// Set initial object in `g`.
|
||||||
|
const capn_text capn_val0 = {
|
||||||
|
.len = strlen(s),
|
||||||
|
.str = s,
|
||||||
|
.seg = NULL
|
||||||
|
};
|
||||||
|
struct Greeting g = {
|
||||||
|
.text = capn_val0,
|
||||||
|
.timesToSay = 17,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Serialize `g` to `buf[0..sz-1]`.
|
||||||
|
struct capn c;
|
||||||
|
capn_init_malloc(&c);
|
||||||
|
capn_ptr cr = capn_root(&c);
|
||||||
|
struct capn_segment *cs = cr.seg;
|
||||||
|
Greeting_ptr gp = new_Greeting(cs);
|
||||||
|
write_Greeting(&g, gp);
|
||||||
|
int setp_ret = capn_setp(capn_root(&c), 0, gp.p);
|
||||||
|
ASSERT_EQ(0, setp_ret);
|
||||||
|
sz = capn_write_mem(&c, buf, sizeof(buf), 0 /* packed */);
|
||||||
|
capn_free(&c);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Write serialized object to file system.
|
||||||
|
FILE *f = fopen("tests/example-test.cpp.Greeting.out", "wb");
|
||||||
|
ASSERT_NE(f, (void*)0);
|
||||||
|
fwrite(buf, 1 /* size */, sz /* count */, f);
|
||||||
|
int close_ret = fclose(f);
|
||||||
|
ASSERT_EQ(0, close_ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Deserialize `buf[0..sz-1]` to `rg`.
|
||||||
|
struct capn rc;
|
||||||
|
int init_mem_ret = capn_init_mem(&rc, buf, sz, 0 /* packed */);
|
||||||
|
ASSERT_EQ(0, init_mem_ret);
|
||||||
|
Greeting_ptr rroot;
|
||||||
|
struct Greeting rg;
|
||||||
|
rroot.p = capn_getp(capn_root(&rc), 0 /* off */, 1 /* resolve */);
|
||||||
|
read_Greeting(&rg, rroot);
|
||||||
|
|
||||||
|
// Assert deserialized values in `rg`
|
||||||
|
EXPECT_EQ(rg.timesToSay, 17);
|
||||||
|
EXPECT_EQ(strlen(s), (uint32_t) rg.text.len);
|
||||||
|
EXPECT_EQ(0, strncmp(s, rg.text.str, strlen(s)));
|
||||||
|
}
|
||||||
|
}
|
||||||
10
tests/example.capnp
Normal file
10
tests/example.capnp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
@0xd120e9a4c43868ab;
|
||||||
|
|
||||||
|
using C = import "../compiler/c.capnp";
|
||||||
|
|
||||||
|
$C.fieldgetset;
|
||||||
|
|
||||||
|
struct Greeting {
|
||||||
|
text @0 :Text = "Default greeting: hello world!";
|
||||||
|
timesToSay @1 :UInt32;
|
||||||
|
}
|
||||||
66
tests/example.capnp.c
Normal file
66
tests/example.capnp.c
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include "example.capnp.h"
|
||||||
|
/* AUTO GENERATED - DO NOT EDIT */
|
||||||
|
static const capn_text capn_val0 = {0,"",0};
|
||||||
|
static const uint8_t capn_buf[32] = {
|
||||||
|
68,101,102,97,117,108,116,32,
|
||||||
|
103,114,101,101,116,105,110,103,
|
||||||
|
58,32,104,101,108,108,111,32,
|
||||||
|
119,111,114,108,100,33,0,0
|
||||||
|
};
|
||||||
|
static const struct capn_segment capn_seg = {{0},0,0,0,(char*)&capn_buf[0],32,32,0};
|
||||||
|
static capn_text capn_val1 = {30,(char*)&capn_buf[0],(struct capn_segment*)&capn_seg};
|
||||||
|
|
||||||
|
Greeting_ptr new_Greeting(struct capn_segment *s) {
|
||||||
|
Greeting_ptr p;
|
||||||
|
p.p = capn_new_struct(s, 8, 1);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
Greeting_list new_Greeting_list(struct capn_segment *s, int len) {
|
||||||
|
Greeting_list p;
|
||||||
|
p.p = capn_new_list(s, len, 8, 1);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
void read_Greeting(struct Greeting *s, Greeting_ptr p) {
|
||||||
|
capn_resolve(&p.p);
|
||||||
|
s->text = capn_get_text(p.p, 0, capn_val1);
|
||||||
|
s->timesToSay = capn_read32(p.p, 0);
|
||||||
|
}
|
||||||
|
void write_Greeting(const struct Greeting *s, Greeting_ptr p) {
|
||||||
|
capn_resolve(&p.p);
|
||||||
|
capn_set_text(p.p, 0, (s->text.str != capn_val1.str) ? s->text : capn_val0);
|
||||||
|
capn_write32(p.p, 0, s->timesToSay);
|
||||||
|
}
|
||||||
|
void get_Greeting(struct Greeting *s, Greeting_list l, int i) {
|
||||||
|
Greeting_ptr p;
|
||||||
|
p.p = capn_getp(l.p, i, 0);
|
||||||
|
read_Greeting(s, p);
|
||||||
|
}
|
||||||
|
void set_Greeting(const struct Greeting *s, Greeting_list l, int i) {
|
||||||
|
Greeting_ptr p;
|
||||||
|
p.p = capn_getp(l.p, i, 0);
|
||||||
|
write_Greeting(s, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
capn_text Greeting_get_text(Greeting_ptr p)
|
||||||
|
{
|
||||||
|
capn_text text;
|
||||||
|
text = capn_get_text(p.p, 0, capn_val1);
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Greeting_get_timesToSay(Greeting_ptr p)
|
||||||
|
{
|
||||||
|
uint32_t timesToSay;
|
||||||
|
timesToSay = capn_read32(p.p, 0);
|
||||||
|
return timesToSay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Greeting_set_text(Greeting_ptr p, capn_text text)
|
||||||
|
{
|
||||||
|
capn_set_text(p.p, 0, (text.str != capn_val1.str) ? text : capn_val0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Greeting_set_timesToSay(Greeting_ptr p, uint32_t timesToSay)
|
||||||
|
{
|
||||||
|
capn_write32(p.p, 0, timesToSay);
|
||||||
|
}
|
||||||
54
tests/example.capnp.h
Normal file
54
tests/example.capnp.h
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef CAPN_D120E9A4C43868AB
|
||||||
|
#define CAPN_D120E9A4C43868AB
|
||||||
|
/* AUTO GENERATED - DO NOT EDIT */
|
||||||
|
#include <capnp_c.h>
|
||||||
|
|
||||||
|
#if CAPN_VERSION != 1
|
||||||
|
#error "version mismatch between capnp_c.h and generated code"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Greeting;
|
||||||
|
|
||||||
|
typedef struct {capn_ptr p;} Greeting_ptr;
|
||||||
|
|
||||||
|
typedef struct {capn_ptr p;} Greeting_list;
|
||||||
|
|
||||||
|
struct Greeting {
|
||||||
|
capn_text text;
|
||||||
|
uint32_t timesToSay;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t Greeting_word_count = 1;
|
||||||
|
|
||||||
|
static const size_t Greeting_pointer_count = 1;
|
||||||
|
|
||||||
|
static const size_t Greeting_struct_bytes_count = 16;
|
||||||
|
|
||||||
|
capn_text Greeting_get_text(Greeting_ptr p);
|
||||||
|
|
||||||
|
uint32_t Greeting_get_timesToSay(Greeting_ptr p);
|
||||||
|
|
||||||
|
void Greeting_set_text(Greeting_ptr p, capn_text text);
|
||||||
|
|
||||||
|
void Greeting_set_timesToSay(Greeting_ptr p, uint32_t timesToSay);
|
||||||
|
|
||||||
|
Greeting_ptr new_Greeting(struct capn_segment*);
|
||||||
|
|
||||||
|
Greeting_list new_Greeting_list(struct capn_segment*, int len);
|
||||||
|
|
||||||
|
void read_Greeting(struct Greeting*, Greeting_ptr);
|
||||||
|
|
||||||
|
void write_Greeting(const struct Greeting*, Greeting_ptr);
|
||||||
|
|
||||||
|
void get_Greeting(struct Greeting*, Greeting_list, int i);
|
||||||
|
|
||||||
|
void set_Greeting(const struct Greeting*, Greeting_list, int i);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue