使用cmake构建proto时找不到成员

时间:2015-04-18 17:17:45

标签: cmake protocol-buffers

我希望使用proto并由cmake管理。

假设文件如下

.
├── app1
│   ├── app1.cpp
│   └── app1.proto
├── CMakeLists.txt
├── common
│   ├── bar
│   │   ├── bar.proto
│   │   └── CMakeLists.txt
│   └── foo
│       ├── CMakeLists.txt
│       └── foo.proto
└── README.md

如果我想生成一些cpp文件,我可以使用命令

$ protoc --cpp_out=build common/bar/bar.proto
$ protoc --cpp_out=build common/foo/foo.proto

可以生成所需的文件。

但是,如果我使用CMake,它将报告错误如下:

[ 14%] Running C++ protocol buffer compiler on foo.proto
Scanning dependencies of target FooLib
[ 28%] Building CXX object common/foo/CMakeFiles/FooLib.dir/foo.pb.cc.o
Linking CXX static library libFooLib.a
[ 28%] Built target FooLib
[ 42%] Running C++ protocol buffer compiler on bar.proto
Scanning dependencies of target BarLib
[ 57%] Building CXX object common/bar/CMakeFiles/BarLib.dir/bar.pb.cc.o
/Users/yu/Workspace/res/proto/project/build/common/bar/bar.pb.cc:79:5: error: no member named 'protobuf_AddDesc_common_2ffoo_2ffoo_2eproto' in the global namespace
  ::protobuf_AddDesc_common_2ffoo_2ffoo_2eproto();
  ~~^
1 error generated.
make[2]: *** [common/bar/CMakeFiles/BarLib.dir/bar.pb.cc.o] Error 1
make[1]: *** [common/bar/CMakeFiles/BarLib.dir/all] Error 2
make: *** [all] Error 2

感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

我对cmake不太熟悉,所以我可能会遗漏一些东西,但在我看来,在原型文件跨越多个目录的情况下,cmake的PROTOBUF_GENERATE_CPP会被破坏。

PROTOBUF_GENERATE_CPP放入common/foo/CMakeLists.txt时,cmake会执行以下命令来生成foo.pb.*

cd /home/kenton/test/cmake-proto/common/foo &&
    /usr/bin/protoc --cpp_out /<project-dir>/common/foo \
        -I /<project-dir>/common/foo -I /<project-dir> \
        /<project-dir>/common/foo/foo.proto

PROTOBUF_GENERATE_CPP放置在顶级CMakeLists.txt时,cmake会执行以下命令来生成foo.pb.*

/usr/bin/protoc --cpp_out /<project-dir> \
    -I /<project-dir>/common/foo -I /<project-dir> \
    /<project-dir>/common/foo/foo.proto

这两个都是错的。具体而言,标志-I /<project-dir>/common/foo不应该在那里。 -I 用于指定源树的 root 。只有-I /<project-dir>是正确的。同样,这似乎是cmake中的一个错误,因为AFAICT没有记录的方法来使它做正确的事情。

这使Protobuf编译器感到困惑,因为它使用文件相对于根目录的路径来决定其规范名称。在您的情况下,foo.proto的规范名称应为common/foo/foo.proto,因为这是所有其他文件用于导入它的名称。符号protobuf_AddDesc_common_2ffoo_2ffoo_2eproto是根据此规范名称构建的(您可以使用_xx作为/.个字符的转义符来查看规范名称。不幸的是,因为cmake正在将-I /<project-dir>/common/foo传递给protoc,所以protobuf编译器断定foo.proto的规范名称只是foo.proto,没有前缀(因为它认为由于/<project-dir>/common/foo标志不正确,-I是源根目录。当其他文件导入foo.proto时,这会导致问题,因为在其他文件中,协议编译器认为规范名称为common/foo/foo.proto。因此,它会生成不匹配的代码。

Here is the documentation for FindProtobuf.它不包含对此问题的任何讨论,这使我怀疑作者不知道它已被破坏。然而,这似乎非常令人惊讶,因为cmake被广泛使用,而且这段代码已有数年之久。也许文档不完整?我建议提交一个错误。

答案 1 :(得分:0)

感谢CMake的邮件列表提供的帮助,我明白了一点。

我们可能会准备一个关注代码作为解决方法。

.

,可以在-I标志后添加更多数据。