find_package(Protobuf) works on macOS, undefined reference on Linux
Context
One of the libraries used by the application in our current project uses Google Protocol Buffers and generates a number of C++ source and header files from several .proto
files. For the last year or so, we have used qmake as a build tool, but are happy to migrate to cmake now.
Problem
- on macOS, everything works fine with the old qmake and new cmake build
- on Linux, the old qmake build also works fine; with cmake, we run into linker errors for probably every symbol in the GPB library, e.g.:
(location in our code)
undefined reference to `google::protobuf::FieldDescriptor::type() const
(location in our code)
undefined reference to `google::protobuf::Descriptor::FindNestedTypeByName(...) const
In function `google::protobuf::RepeatedPtrField<...>::TypeHandler::Type const& google::protobuf::internal::RepeatedPtrFieldBase::Get<google::protobuf::RepeatedPtrField<...>::TypeHandler>(int) const':
/usr/local/include/google/protobuf/repeated_field.h:1481: undefined reference to `google::protobuf::internal::LogMessage::LogMessage(google::protobuf::LogLevel, char const*, int)'
(plus 100s or 1000s more...)
What we've tried so far
After doing an intensive online research and looking at this SO post, we double-checked and peer-reviewed our CMakeLists.txt
files and added INTERFACE
to target_link_libraries(...)
to give that a try, but the error persists.
We clearly don't have the knowledge here to even know where to start looking for the cause.
Symptoms
There is this snippet in the CMakeLists.txt
file of the library that makes use of GPB:
find_package(Protobuf REQUIRED)
message("Protobuf_LIBRARIES: " ${Protobuf_LIBRARIES})
target_link_libraries(${PROJECT_NAME} INTERFACE ${Protobuf_LIBRARIES})
- on macOS, running
cmake
displays this output:
...
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - found
-- Found Threads: TRUE
-- Found Protobuf: /usr/local/lib/libprotobuf.dylib (found version "3.5.1")
-- Configuring done
...
(For some reason, the message does not show up ?!?)
- on Linux, the output looks like this:
...
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Found Protobuf: /usr/local/lib/libprotobuf.so
Protobuf_LIBRARIES:
-- Configuring done
...
Our wild guess
So from what we can tell, Protobuf_LIBRARIES
- despite the Found Protobuf: ...
message - is empty on Linux for some reason and therefore, the library is not properly linked to the application, hence the undefined errors.
The cmake build works on macOS, so the CMakeLists.txt
files are not totally off. The qmake Linux build works, so the Google Protocol Buffers installation seems to be ok, too.
Is this a bug in cmake Protobuf support ? Or are we doing something wrong ?
Is there anything else we can do to diagnose the issue and / or narrow down the cause ?
Other observations
There are two message sections in CMakeFiles/CMakeError.log
:
Determining if the pthread_create exist failed with the following output:
...
CheckSymbolExists.c:(.text+0x16): undefined reference to `pthread_create'
...
Determining if the function pthread_create exists in the pthreads failed with the following output:
...
/usr/bin/ld: cannot find -lpthreads
but we assume those are caused by the first two attempts to find pthread_create
also visible in the build log above.
Versions involved:
- macOS:
macos:~ user$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.12.6
BuildVersion: 16G1114
macos:~ user$ brew info cmake
cmake: stable 3.10.2 (bottled), HEAD
...
macos:~ user$ cmake --version
cmake version 3.10.2
...
macos:~ user$ brew info protobuf
protobuf: stable 3.5.1 (bottled), HEAD
...
macos:~ user$ protoc --version
libprotoc 3.5.1
- Linux:
user@linux:~$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"
user@linux:~$ aptitude show cmake | grep Version
Version: 3.5.1-1ubuntu3
user@linux:~$ cmake --version
cmake version 3.5.1
...
Default Google Protocol Buffer packages on Ubuntu 16.04 LTS are too old, so they were built and installed from source as per installation instructions, latest master some time today.
user@linux:~$ protoc --version
libprotoc 3.5.1
(are those version numbers a coincidence ?!?)
Final word
We're happy to provide whatever further information might be required. cmake is clearly the better build tool and we really want to get this going, so we can complete the migration.