我希望使用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
感谢任何帮助。
答案 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标志后添加更多数据。