2015-04-18 24 views
1

我希望使用原型并由cmake管理。使用cmake构建原型时找不到成员

的样例项目可显示here

的文件如下

. 
├── 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 

任何帮助表示赞赏。

回答

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应该只有用于指定源树的。只有-I /<project-dir>是正确的。再一次,这似乎是cmake中的一个错误,因为AFAICT没有书面的方法来使它做正确的事情。

这是混淆的Protobuf编译器,因为它使用的文件的路径相对于根目录来决定它的规范名称。在你的情况下,foo.proto的规范名称应该是common/foo/foo.proto,因为这是所有其他文件用来导入它的名称。符号protobuf_AddDesc_common_2ffoo_2ffoo_2eproto从该规范名称构造(你可以看到的规范名称被编码在里面,使用_xx作为转义为/.字符)。不幸的是,因为cmake传递-I /<project-dir>/common/fooprotoc,protobuf编译器得出结论认为foo.proto的规范名称只是foo.proto,没有前缀(因为它认为/<project-dir>/common/foo是源根目录,因为-I标志不正确)。这会导致问题,当其他文件导入foo.proto,因为在那些其他文件的协议编译器认为,规范名称是common/foo/foo.proto。所以,它会产生不匹配的代码。

Here is the documentation for FindProtobuf.它不包含这个问题,这使我怀疑,作者不知道它是破碎的任何讨论。然而,这看起来非常令人惊讶,因为cmake被广泛使用,并且这个代码已经有几年了。也许文件不完整?我会建议提交一个错误。

+0

非常感谢您的解释,我也混淆了路径。我可以知道你是如何处理案件的.proto需要导入另一个?我认为这对我的工作非常必要。 –

+0

@YuJing我个人?那么,我不使用cmake。大多数情况下,我使用了已经写好的Makefile规则(您可以检查protobuf自己的Makefiles)或[我自己的自定义构建系统](https://github.com/sandstorm-io/ekam)(可能不是您想要的) 。一旦[Bazel](http://bazel.io)(Google的开源内部构建系统)添加了对proto_library的支持([见本期内容](https://github.com/google/bazel/issues/52 )),这可能是一个不错的选择。 –

0

感谢您通过cmake的邮递员的帮助,我得到了一些意见。

。读的源代码,我们可以找到一些线路如下:

if(DEFINED PROTOBUF_IMPORT_DIRS) 
    foreach(DIR ${PROTOBUF_IMPORT_DIRS}) 
     get_filename_component(ABS_PATH ${DIR} ABSOLUTE) 
     list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) 
     if(${_contains_already} EQUAL -1) 
      list(APPEND _protobuf_include_path -I ${ABS_PATH}) 
     endif() 
    endforeach() 
    endif() 

LIST(附加PROTOBUF_IMPORT_DIRS “SOME_PATHS”)可以-I标志后,添加更多的数据。

  1. 有些时候它仍然不起作用,我们可以为protobuf编写自定义代码。 我更新了the project