Commit ea54158d authored by Kenton Varda's avatar Kenton Varda

Install schema.capnp and c++.capnp to $PREFIX/include/capnp. Make sure…

Install schema.capnp and c++.capnp to $PREFIX/include/capnp.  Make sure /usr/include and /usr/local/include are in the capnpc search path.  Fix Makefile bug related to ridiculous gmake implicit rules.  And update the docs a bit.
parent 452c84b2
......@@ -40,6 +40,15 @@ MAINTAINERCLEANFILES = \
maintainer-clean-local:
-rm -rf build-aux
# gmake defines an implicit rule building n from n.o. Unfortunately, this triggers on our .capnp
# files because they generate .capnp.c++ which is compiled to .capnp.o. In addition to being
# nonsense, this leads to cyclic dependency issues and could even cause the .capnp files to be
# unexpectedly overwritten! We need to cancel the implicit rule by declaring an explicit one.
#
# I want the hours of my life back that I spent figuring this out.
$(capnpc_inputs) $(test_capnpc_inputs):
:
capnpc_inputs = \
src/capnp/c++.capnp \
src/capnp/schema.capnp
......@@ -50,11 +59,7 @@ capnpc_outputs = \
src/capnp/schema.capnp.c++ \
src/capnp/schema.capnp.h
# This should depend on $(capnpc_inputs), but then make mysteriously complains
# about a cyclic dependency. I don't know where it is coming from. I rummaged
# around in the generated Makefile a bit but couldn't figure it out. I give
# up. Automake is terrible.
capnpc_middleman:
capnpc_middleman: $(capnpc_inputs)
$(CAPNPC) -oc++ $(capnpc_inputs)
touch capnpc_middleman
......@@ -63,6 +68,10 @@ $(capnpc_outputs): capnpc_middleman
includecapnpdir = $(includedir)/capnp
includekjdir = $(includedir)/kj
dist_includecapnp_DATA = \
src/capnp/c++.capnp \
src/capnp/schema.capnp
includekj_HEADERS = \
src/kj/common.h \
src/kj/units.h \
......@@ -119,7 +128,8 @@ libcapnp_a_SOURCES= \
src/capnp/serialize.c++ \
src/capnp/serialize-packed.c++
nodist_libcapnp_a_SOURCES = \
src/capnp/schema.capnp.c++
src/capnp/schema.capnp.c++ \
src/capnp/c++.capnp.c++
# Source files intentionally not included in the dist at this time:
# src/capnp/serialize-snappy*
......@@ -138,11 +148,7 @@ test_capnpc_outputs = \
src/capnp/test-import.capnp.c++ \
src/capnp/test-import.capnp.h
# This should depend on $(test_capnpc_inputs), but then make mysteriously complains
# about a cyclic dependency. I don't know where it is coming from. I rummaged
# around in the generated Makefile a bit but couldn't figure it out. I give
# up. Automake is terrible.
test_capnpc_middleman:
test_capnpc_middleman: $(test_capnpc_inputs)
$(CAPNPC) -oc++ $(test_capnpc_inputs)
touch test_capnpc_middleman
......
......@@ -108,7 +108,12 @@ main = do
let isVerbose = not $ null [opt | opt@VerboseOpt <- options]
let outputs = [(fn, dir) | OutputOpt _ fn dir <- options]
let searchPath = [dir | SearchPathOpt dir <- options]
-- TODO(someday): We should perhaps determine the compiler binary's location and search its
-- ../include as well. Also, there should perhaps be a way to tell the compiler not to search
-- these hard-coded default paths.
let searchPath = ["/usr/local/include", "/usr/include"] ++
[dir | SearchPathOpt dir <- options]
let verifyDirectoryExists dir = do
exists <- doesDirectoryExist dir
......
......@@ -169,7 +169,28 @@ To generate C++ code from your `.capnp` [interface definition](language.html), r
This will create `myproto.capnp.h` and `myproto.capnp.c++` in the same directory as `myproto.capnp`.
## Primitive Types
### Setting a Namespace
You probably want your generated types to live in a C++ namespace. You will need to import
`/capnp/c++.capnp` and use the `namespace` annotation it defines:
{% highlight capnp %}
using Cxx = import "/capnp/c++.capnp";
$Cxx.namespace("foo::bar::baz");
{% endhighlight %}
Note that for this to work, `capnp/c++.capnp` must be located in the search path specified with
`-I` options. This file is found in the Cap'n Proto source repo, so you could invoke `capnpc` like
so:
capnpc -I$CAPNPROTO_GIT_ROOT/c++/src -oc++ myproto.capnp
As of this writing, the file is not automatically installed anywhere, but in the future it will
be.
## Types
### Primitive Types
Primitive types map to the obvious C++ types:
......@@ -180,7 +201,7 @@ Primitive types map to the obvious C++ types:
* `Float64` -> `double`
* `Void` -> `::capnp::Void` (An enum with one value: `::capnp::Void::VOID`)
## Structs
### Structs
For each struct `Foo` in your interface, a C++ type named `Foo` generated. This type itself is
really just a namespace; it contains two important inner classes: `Reader` and `Builder`.
......@@ -253,7 +274,7 @@ void setMyListField(::capnp::List<double>::Reader value);
::capnp::List<double>::Builder initMyListField(size_t size);
{% endhighlight %}
## Unions
### Unions
For each union `foo` declared in the struct, the struct's reader and builder have a method
`getFoo()` which returns a reader/builder for the union. The union reader/builder has accessors
......@@ -264,7 +285,7 @@ crashes in debug mode or returns garbage when `NDEBUG` is defined.
See the [example](#example_usage) at the top of the page for an example of unions.
## Lists
### Lists
Lists are represented by the type `capnp::List<T>`, where `T` is any of the primitive types,
any Cap'n Proto user-defined type, `capnp::Text`, `capnp::Data`, or `capnp::List<U>`
......@@ -289,7 +310,7 @@ the element at the given index to a newly-allocated value with the given size an
for it. Struct lists do not have an `init` method because all elements are initialized to empty
values when the list is created.
## Enums
### Enums
Cap'n Proto enums become C++11 "enum classes". That means they behave like any other enum, but
the enum's values are scoped within the type. E.g. for an enum `Foo` with value `bar`, you must
......@@ -304,7 +325,7 @@ version of the protocol, or if the message is corrupt or malicious. In C++11, e
to have any value that is within the range of their base type, which for Cap'n Proto enums is
`uint16_t`.
## Blobs (Text and Data)
### Blobs (Text and Data)
Blobs are manipulated using the classes `capnp::Text` and `capnp::Data`. These classes are,
again, just containers for inner classes `Reader` and `Builder`. These classes are iterable and
......@@ -312,7 +333,7 @@ implement `size()` and `operator[]` methods. `Builder::operator[]` even returns
(unlike with `List<T>`). `Text::Reader` additionally has a method `cStr()` which returns a
NUL-terminated `const char*`.
## Interfaces
### Interfaces
Interfaces (RPC) are not yet implemented at this time.
......@@ -337,25 +358,6 @@ details.
There is an [example](#example_usage) of all this at the beginning of this page.
## Setting a Namespace
You probably want your generated types to live in a C++ namespace. You will need to import
`/capnp/c++.capnp` and use the `namespace` annotation it defines:
{% highlight capnp %}
Cxx = import "/capnp/c++.capnp";
$Cxx.namespace("foo::bar::baz");
{% endhighlight %}
Note that for this to work, `capnp/c++.capnp` must be located in the search path specified with
`-I` options. This file is found in the Cap'n Proto source repo, so you could invoke `capnpc` like
so:
capnpc -I$CAPNPROTO_GIT_ROOT/c++/src -oc++ myproto.capnp
As of this writing, the file is not automatically installed anywhere, but in the future it will
be.
## Dynamic Reflection
Sometimes you want to write generic code that operates on arbitrary types, iterating over the
......@@ -572,9 +574,9 @@ learned the hard way:
class. This actually poses a significant problem in practice -- there exist server binaries
containing literally hundreds of megabytes of compiled protobuf code. Cap'n Proto generated code,
on the other hand, is almost entirely inlined accessors. The only things that go into `.capnp.o`
files are default values for pointer fields, and only if they have non-empty defaults (which are
unusual). (Eventually, the object files may also contain type descriptors, but those should also
be small.)
files are default values for pointer fields (if needed, which is rare) and the encoded schema
(just the raw bytes of a Cap'n-Proto-encoded schema structure). The latter could even be removed
if you don't use dynamic reflection.
* The C++ Protobuf implementation used lots of dynamic initialization code (that runs before
`main()`) to do things like register types in global tables. This proved problematic for
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment