Other Languages
Cap’n Proto’s reference implementation is in C++. Implementations in other languages are maintained by respective authors and have not been reviewed by me (@kentonv). Below are the implementations I’m aware of. Some of these projects are more “ready” than others; please consult each project’s documentation for details.
Serialization + RPC
- C++ by @kentonv
- C# by @c80k
- Erlang by @kaos
- Go currently maintained by @zenhack and @lthibault
- Haskell by @zenhack
- JavaScript (Node.js only) by @kentonv
- OCaml by @pelzlpj with RPC by @talex5
- Python by @jparyani
- Rust by @dwrensha
Serialization only
- C by OpenSourceRouting / @eqvinox (originally by @jmckaskill) (no longer maintained)
- D by @ThomasBrixLarsen
- Java by @dwrensha
- JavaScript by @popham
- JavaScript (older, abandoned) by @jscheid
- Lua by CloudFlare / @calio
- Nim by @zielmicha
- Ruby by @cstrahan
- Scala by @katis
Tools
These are other misc projects related to Cap’n Proto that are not actually implementations in new languages.
- Common Test Framework by @kaos
- Sublime Syntax Highlighting by @joshuawarner32
- Vim Syntax Highlighting by @cstrahan
- Wireshark Dissector Plugin by @kaos
- VS Code Syntax Highlighter by @xmonader
- IntelliJ Syntax Highlighter by @xmonader
- RPC Tracer by @t-kondo-tmc
- Flow-IPC (shared memory IPC transport in C++) by Akamai / @ygoldfeld
Contribute Your Own!
We’d like to support many more languages in the future!
If you’d like to own the implementation of Cap’n Proto in some particular language, let us know!
You should e-mail the list before you start hacking. We don’t bite, and we’ll probably have useful tips that will save you time. :)
Do not implement your own schema parser. The schema language is more complicated than it looks, and the algorithm to determine offsets of fields is subtle. If you reuse the official parser, you won’t risk getting these wrong, and you won’t have to spend time keeping your parser up-to-date. In fact, you can still write your code generator in any language you want, using compiler plugins!
How to Write Compiler Plugins
The Cap’n Proto tool, capnp
, does not actually know how to generate code. It only parses schemas,
then hands the parse tree off to another binary – known as a “plugin” – which generates the code.
Plugins are independent executables (written in any language) which read a description of the
schema from standard input and then generate the necessary code. The description is itself a
Cap’n Proto message, defined by
schema.capnp.
Specifically, the plugin receives a CodeGeneratorRequest
, using
standard serialization
(not packed). (Note that installing the C++ runtime causes schema.capnp to be placed in
$PREFIX/include/capnp
– /usr/local/include/capnp
by default).
Of course, because the input to a plugin is itself in Cap’n Proto format, if you write your
plugin directly in the language you wish to support, you may have a bootstrapping problem: you
somehow need to generate code for schema.capnp
before you write your code generator. Luckily,
because of the simplicity of the Cap’n Proto format, it is generally not too hard to do this by
hand. Remember that you can use capnp compile -ocapnp schema.capnp
to get a dump of the sizes
and offsets of all structs and fields defined in the file.
capnp compile
normally looks for plugins in $PATH
with the name capnpc-[language]
, e.g.
capnpc-c++
or capnpc-capnp
. However, if the language name given on the command line contains
a slash character, capnp
assumes that it is an exact path to the plugin executable, and does not
search $PATH
. Examples:
# Searches $PATH for executable "capnpc-mylang".
capnp compile -o mylang addressbook.capnp
# Uses plugin executable "myplugin" from the current directory.
capnp compile -o ./myplugin addressbook.capnp
If the user specifies an output directory, the compiler will run the plugin with that directory as the working directory, so you do not need to worry about this.
For examples of plugins, take a look at capnpc-capnp or capnpc-c++.
Supporting Dynamic Languages
Dynamic languages have no compile step. This makes it difficult to work capnp compile
into the
workflow for such languages. Additionally, dynamic languages are often scripting languages that do
not support pointer arithmetic or any reasonably-performant alternative.
Fortunately, dynamic languages usually have facilities for calling native code. The best way to support Cap’n Proto in a dynamic language, then, is to wrap the C++ library, in particular the C++ dynamic API. This way you get reasonable performance while still avoiding the need to generate any code specific to each schema.
To parse the schema files, use the capnp::SchemaParser
class (defined in capnp/schema-parser.h
).
This way, schemas are loaded at the same time as all the rest of the program’s code – at startup.
An advanced implementation might consider caching the compiled schemas in binary format, then
loading the cached version using capnp::SchemaLoader
, similar to the way e.g. Python caches
compiled source files as .pyc
bytecode, but that’s up to you.
Testing Your Implementation
The easiest way to test that you’ve implemented the spec correctly is to use the capnp
tool
to encode test inputs and
decode outputs.