8

Using

find_package(Protobuf REQUIRED
    PATHS ${PROTOBUF_SEARCH_PATH}
)

if (NOT ${Protobuf_FOUND})
    message( FATAL_ERROR "Could not find Protobuf!" )
endif()    

protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS Foo.proto)

I am getting an error message Unknown CMake command "protobuf_generate_cpp". If I check install folder of Protobuff, there is a CMake file <istall path>/cmake/protobuf-module.cmake which contains the function definition.

CMake    version: 3.10.2
Protobuf version: 3.6.1

What is the problem here?

carobnodrvo
  • 1,021
  • 1
  • 9
  • 32
  • It is `ProtobufConfig.cmake` file which is read during `find_package()` call. CMake stores directory, containing this file, in `Protobuf_DIR` cache variable. You may find value of this variable in `CMakeCache.txt` file, located in the build directory. Check that: 1. Proper file `ProtobufConfig.cmake` has been found (according to `Protobuf_DIR` variable). 2. Given file contains definition of `protobuf_generate_cpp` function. – Tsyvarev Sep 27 '18 at 11:41

3 Answers3

14

Looks like the cmake API has changed a bit. Try changing it to

protobuf_generate(
 LANGUAGE cpp
 TARGET <YOUR_TARGET_NAME> 
 PROTOS Foo.proto)

This will directly add the generated files to the target's source list. Have a look in at the protobuf_generate function in protobuf-config.cmake for the new options.

Andrew
  • 1,608
  • 16
  • 31
  • 18
    Where is the documentation for this? The official CMake documentation only lists protobuf_generate_cpp and protobuf_generate_python, even for the latest release. – scatter May 29 '19 at 15:00
  • I also would love to see the documentation for this. This is currently the only place on the internet that mentions this. – vuko_zrno Jul 26 '20 at 22:34
  • @scatter see my answer cmake's FindProtobuf does not provide this API. It comes from protocol buffers which is not so well documented. – Bruce Adams Sep 23 '20 at 22:38
  • @BruceAdams I don't know if the discussion on your issue is (still) true. It appears that `protobuf_generate` is now an [implementation detail(?)](https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/FindProtobuf.cmake#L141) of the CMake distributed FindProtobuf.cmake file. Looks like this was done [4 years ago](https://gitlab.kitware.com/cmake/cmake/-/commit/1bcc0f3678daea6bb7f999ebded1eab471b32e28). – jwm Oct 04 '22 at 21:56
  • @jwm the point of my answer was that it could (at least in 2020) come from either cmake or protocol_buffers. Both may have changed since then. protocol buffers has definitely improved its cmake support and might be the definitive choice now. I don't know. – Bruce Adams Oct 05 '22 at 11:44
  • @BruceAdams I wasn't questioning your answer; it was very thorough. For me, learning how CMake finds things has been a perilous adventure. I was simply pointing out that the dismissive "that comes from upstream; it's not our issue" [response](https://gitlab.kitware.com/cmake/cmake/-/issues/21228#note_834424) you got from CMake on your issue is not quite true. The CMake-delivered `FindProtobuf.cmake` does include (and has for a while) `protobuf_generate`. – jwm Oct 05 '22 at 17:49
  • 2
    I know it's late @scatter, but protocolbuffers finally wrote some [documentation](https://github.com/protocolbuffers/protobuf/blob/e1faf09604d26cc6803970815f91225b220175d4/docs/cmake_protobuf_generate.md) on it in September – user1081679 Jun 08 '23 at 23:07
7

The existing answers helped me but miss a lot of explanation of what is going on.

find_package can work in MODULE mode or CONFIG mode. In MODULE mode it searches for Find\<package\>.cmake (typically owned by cmake). In CONFIG mode it searches for \<package\>Config.cmake (provided by the package).

Both cmake and protocol buffers can provide an implementation for protobuf_generate_cpp():

>grep -ri 'function(PROTOBUF_GENERATE_CPP' /opt/cmake-3.18.1/ 
/opt/cmake-3.18.1/share/cmake-3.18/Modules/FindProtobuf.cmake:function(PROTOBUF_GENERATE_CPP SRCS HDRS)
>grep -ri 'function(PROTOBUF_GENERATE_CPP' /opt/protobuf-3.5.0/
/opt/protobuf-3.5.0/lib64/cmake/protobuf/protobuf-module.cmake:function(PROTOBUF_GENERATE_CPP SRCS HDRS)

Using the PATHS hint puts cmake into CONFIG mode so that it will use the protobuf provided implementation if it can find a Config.cmake module.

In this case protobuf_generate_cpp() comes from config.cmake which requires:

set(protobuf_MODULE_COMPATIBLE ON CACHE BOOL "")

Because as @HaxtraZ mentions the config module contains:

if(protobuf_MODULE_COMPATIBLE)
   include("${CMAKE_CURRENT_LIST_DIR}/protobuf-module.cmake")
endif()

This is not required if using the FindProtobuf MODULE and is thus not documented there.

Though it is not really its fault cmake could warn about the possible conflict. If have raised this here:

https://gitlab.kitware.com/cmake/cmake/issues/21228

I have also reported the confusion caused by the missing documentation to the protocol buffers project here:

https://github.com/protocolbuffers/protobuf/issues/7912

Note: The default on some Linux installations (at least CentOS7 and Debian9) is typically to have protocol buffers produced using configure/make rather than cmake which does not install the cmake config files at all. So find_package(protobuf 3.5.0 REQUIRED) will work but find_package(protobuf 3.5.0 REQUIRED PATH I/only/wanted/to/help) will fail.

Bruce Adams
  • 4,953
  • 4
  • 48
  • 111
  • Unfortunately, using `CONFIG` mode and setting this boolean variable does not work (on Windows at least) – oarfish Feb 04 '21 at 06:09
5

You need protobuf_MODULE_COMPATIBLE.

I'm using CMake3.14. The last 3 lines of protobuf-config.cmake is:

if(protobuf_MODULE_COMPATIBLE)
  include("${CMAKE_CURRENT_LIST_DIR}/protobuf-module.cmake")
endif()

and protobuf_generate_cpp() is defined in protobuf-module.cmake.

So, in order to protobuf_generate_cpp(), people have to turn protobuf_MODULE_COMPATIBLE on in their CMakeLists.txt:

set(protobuf_MODULE_COMPATIBLE ON CACHE BOOL "")

Remember clean your previously generate cmake cache files then call cmake again.

ChrisZZ
  • 1,521
  • 2
  • 17
  • 24