No Member Found when use cmake construct proto

天大地大妈咪最大 提交于 2019-12-23 02:17:23

问题


I wish to use proto and managed by cmake.

Suppose the files are as follow

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

If I wanna just generate some cpp files, I can just use command

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

and the desired files can be generated.

However, if I use CMake, it will report an error as follow :

[ 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

Any help are appreciated.


回答1:


I'm not too familiar with cmake, so I could be missing something, but it appears to me that cmake's PROTOBUF_GENERATE_CPP is broken in the case where your proto files span multiple directories.

When PROTOBUF_GENERATE_CPP is placed in common/foo/CMakeLists.txt, cmake executes the following command to generate 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

When PROTOBUF_GENERATE_CPP is placed in the top-level CMakeLists.txt, cmake executes the following command to generate foo.pb.*:

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

Both of these are wrong. Specifically, the flag -I /<project-dir>/common/foo should not be there. -I should only be used to specify the root of the source tree. Only -I /<project-dir> is correct. Again, this appears to be a bug in cmake, since AFAICT there is no documented way to make it do the right thing.

This is confusing the Protobuf compiler because it uses the file's path relative to the root directory to decide its canonical name. In your case, foo.proto's canonical name should be common/foo/foo.proto, because this is the name that all other files use to import it. The symbol protobuf_AddDesc_common_2ffoo_2ffoo_2eproto is constructed from this canonical name (you can see the canonical name is encoded in it, using _xx as escapes for / and . characters). Unfortunately, because cmake is passing -I /<project-dir>/common/foo to protoc, the protobuf compiler concludes that foo.proto's canonical name is simply foo.proto, with no prefix (because it thinks that /<project-dir>/common/foo is the source root directory, due to the incorrect -I flag). This causes problems when other files import foo.proto, because in those other files the protocol compiler believes that the canonical name is common/foo/foo.proto. So, it generates mismatching code.

Here is the documentation for FindProtobuf. It does not contain any discussion of this issue, which makes me suspect that the authors are not aware that it is broken. However, this would seem very surprising since cmake is widely-used and this code is years old. Perhaps the documentation is simply incomplete? I would suggest filing a bug.




回答2:


Thanks for the help via CMake's mailing list, I got some point.

We may prepare a follow code as workaround.

  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(APPEND PROTOBUF_IMPORT_DIRS "SOME_PATHS") can add more data after -I flag.



来源:https://stackoverflow.com/questions/29720410/no-member-found-when-use-cmake-construct-proto

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!