Re: [protobuf] Linker error

3,595 views
Skip to first unread message

Feng Xiao

unread,
Feb 28, 2013, 2:46:55 AM2/28/13
to Mohammad Husain, prot...@googlegroups.com


On Thu, Feb 28, 2013 at 5:01 AM, Mohammad Husain <farha...@hotmail.com> wrote:
I am having a bizarre linker problem with the simple program I wrote with protobuf. When I run the make command I see tons of linker errors like the following:

user.pb.o:(.rodata._ZTIN4misc4UserE[_ZTIN4misc4UserE]+0x10): undefined reference to `typeinfo for google::protobuf::Message'
user.pb.o:(.rodata._ZTIN4misc13User_FullNameE[_ZTIN4misc13User_FullNameE]+0x0): undefined reference to `vtable for __cxxabiv1::__si_class_type_info'
user.pb.o:(.rodata._ZTIN4misc13User_FullNameE[_ZTIN4misc13User_FullNameE]+0x10): undefined reference to `typeinfo for google::protobuf::Message'
user.pb.o:(.eh_frame+0x38b): undefined reference to `__gxx_personality_v0'
collect2: error: ld returned 1 exit status
make: *** [hello_protobuf] Error 1

However, the C++ example in the protobuf package builds and runs fine. Here is the output of the pkgconfig command:

$ pkg-config --cflags --libs protobuf
-pthread -I/usr/local/include  -pthread -L/usr/local/lib -lprotobuf -lz -lpthread 
$ protoc --version
libprotoc 2.4.1
I am using version 2.4.1. I believe something is wrong with my Makefile. Can anyone help?

I tried to attach the source and Makefile but probably attachment is disabled in the group. Here are my file contents:

<user.proto>
package misc;

message User {
    required string username = 1;
    required int32 id = 2;
    optional string email = 3;

    message FullName {
        required string firstName = 1;
        optional string middleName = 2;
        required string lastName = 3;
    }

    optional FullName fullName = 4;;
}
</user.proto>

<hello_protobuf.cpp>
#include <iostream>
#include "user.pb.h"

int main(int argc, char **argv) {
    misc::User u;

    u.set_username("username");
    u.set_id(1);

    std::cout << "Username: " << u.username() << " and ID: " << u.id() << std::endl;

    return 0;
}
</hello_protobuf.cpp>

<Makefile>
all: hello_protobuf

CC = g++
DEBUG = -g
LIBS = `pkg-config --cflags --libs protobuf`
CFLAGS = -Wall $(DEBUG)
LFLAGS = -Wall $(DEBUG) $(LIBS)

protoc_middleman: user.proto
    protoc --cpp_out=. user.proto
    @touch protoc_middleman

OBJS = hello_protobuf.o user.pb.o
These .o files are not compiled with appropriate flags. You need to add a rule for them, something like:
%.o: %.cc
  $(CC) $(CFLAGS) $< -o $@
 

hello_protobuf: $(OBJS) protoc_middleman
    pkg-config --cflags protobuf  # fails if protobuf is not installed
    $(CC) $(LFLAGS) $(OBJS) -o hello_protobuf

clean:
    \rm *.o hello_protobuf
</Makefile>

--
You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to protobuf+u...@googlegroups.com.
To post to this group, send email to prot...@googlegroups.com.
Visit this group at http://groups.google.com/group/protobuf?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Ilia Mirkin

unread,
Feb 28, 2013, 2:48:08 AM2/28/13
to Mohammad Husain, prot...@googlegroups.com
You don't appear to include the path to protobuf when compiling
user.pb.o -- there's no explicit rule so it'll just $(CXXFLAGS). You
should either add

%.pb.o: %.pb.cc
$(CC) $(CXXFLAGS) $(pkgconfig --cflags protobuf) -o $@ $^

Or add CXXFLAGS = $(pkgconfig --cflags protobuf) at the top, which
will make it add the include path everywhere. (I note you're using
CFLAGS... afaik that doesn't get used by the default c++ compilation
rule. Take a look at the commands make prints out and make sure
they're what you'd expect.) Also you'll need this when compiling
hello_protobuf.o, since it also needs the protobuf library.

If the above doesn't explain the issue, you might paste the whole
output from make which will include the actual commands being run.

-ilia

Mohammad Husain

unread,
Feb 28, 2013, 2:10:24 PM2/28/13
to Ilia Mirkin, prot...@googlegroups.com
Hi Ilia,

Though I have CFLAGS defined in my makefile I don't think that is being used. The Makefile in the example directory (copied below) does not have either the %.o:%.cc rule or any CFLAGS or CXXFLAGS but still it can build the executable successfully using the default ones.

<ExampleMakefile>
# See README.txt.

.PHONY: all cpp java python clean

all: cpp java python

cpp:    add_person_cpp    list_people_cpp
java:   add_person_java   list_people_java
python: add_person_python list_people_python

clean:
    rm -f add_person_cpp list_people_cpp add_person_java list_people_java add_person_python list_people_python
    rm -f javac_middleman AddPerson*.class ListPeople*.class com/example/tutorial/*.class
    rm -f protoc_middleman addressbook.pb.cc addressbook.pb.h addressbook_pb2.py com/example/tutorial/AddressBookProtos.java
    rm -f *.pyc
    rmdir com/example/tutorial 2>/dev/null || true
    rmdir com/example 2>/dev/null || true
    rmdir com 2>/dev/null || true

protoc_middleman: addressbook.proto
    protoc --cpp_out=. --java_out=. --python_out=. addressbook.proto
    @touch protoc_middleman

add_person_cpp: add_person.cc protoc_middleman

    pkg-config --cflags protobuf  # fails if protobuf is not installed
    c++ add_person.cc addressbook.pb.cc -o add_person_cpp `pkg-config --cflags --libs protobuf`

list_people_cpp: list_people.cc protoc_middleman

    pkg-config --cflags protobuf  # fails if protobuf is not installed
    c++ list_people.cc addressbook.pb.cc -o list_people_cpp `pkg-config --cflags --libs protobuf`

javac_middleman: AddPerson.java ListPeople.java protoc_middleman
    javac AddPerson.java ListPeople.java com/example/tutorial/AddressBookProtos.java
    @touch javac_middleman

add_person_java: javac_middleman
    @echo "Writing shortcut script add_person_java..."
    @echo '#! /bin/sh' > add_person_java
    @echo 'java -classpath .:$$CLASSPATH AddPerson "$$@"' >> add_person_java
    @chmod +x add_person_java

list_people_java: javac_middleman
    @echo "Writing shortcut script list_people_java..."
    @echo '#! /bin/sh' > list_people_java
    @echo 'java -classpath .:$$CLASSPATH ListPeople "$$@"' >> list_people_java
    @chmod +x list_people_java

add_person_python: add_person.py protoc_middleman
    @echo "Writing shortcut script add_person_python..."
    @echo '#! /bin/sh' > add_person_python
    @echo './add_person.py "$$@"' >> add_person_python
    @chmod +x add_person_python

list_people_python: list_people.py protoc_middleman
    @echo "Writing shortcut script list_people_python..."
    @echo '#! /bin/sh' > list_people_python
    @echo './list_people.py "$$@"' >> list_people_python
    @chmod +x list_people_python
</ExampleMakefile>

> Date: Thu, 28 Feb 2013 02:48:08 -0500
> Subject: Re: [protobuf] Linker error
> From: imi...@alum.mit.edu
> To: farha...@hotmail.com
> CC: prot...@googlegroups.com

Mohammad Husain

unread,
Feb 28, 2013, 2:16:30 PM2/28/13
to Feng Xiao, prot...@googlegroups.com
I actually had the rule but after comparing my Makefile with the one in the examples directory I removed it hoping that would fix the issue.


Date: Thu, 28 Feb 2013 15:46:55 +0800

Subject: Re: [protobuf] Linker error

Ilia Mirkin

unread,
Feb 28, 2013, 3:41:00 PM2/28/13
to Mohammad Husain, prot...@googlegroups.com
There are a million ways to do things with makefiles... did you try my
suggestion? The example you pasted builds the binary all in one step
(compile and link) and includes the protobuf cflags and ldflags as
arguments to the compiler. So it works. Your makefile does not include
the protobuf cflags when compiling. So it doesn't work. The fact that
yours does it in two stages (compile, then link) vs this example
makefile doing it one stage is basically irrelevant though. It is
usually better to do things in two stages though (unlike this example
makefile) so that you get to reuse existing work better.

-ilia

Mohammad Husain

unread,
Feb 28, 2013, 4:57:56 PM2/28/13
to Ilia Mirkin, prot...@googlegroups.com
I just tried your suggestion (copied the Makefile below). The errors are still there :(. I have pasted the output here:

http://pastebin.com/S8K9WzK0

<Makefile>
all: hello_protobuf

# CC = g++

DEBUG = -g
LIBS = `pkg-config --cflags --libs protobuf`
LFLAGS = -Wall $(DEBUG) $(LIBS)

protoc_middleman: user.proto
    protoc --cpp_out=. user.proto
    @touch protoc_middleman

%.pb.o: %.pb.cc
    $(CXX) $(CXXFLAGS) $(pkgconfig --cflags protobuf) -o $@ $^


OBJS = hello_protobuf.o user.pb.o

hello_protobuf: $(OBJS) protoc_middleman
    pkg-config --cflags protobuf  # fails if protobuf is not installed
    $(CXX) $(LFLAGS) -o hello_protobuf $(OBJS)

clean:
    \rm *.o
    \rm hello_protobuf 2>/dev/null || true
</Makefile>

> Date: Thu, 28 Feb 2013 15:41:00 -0500

Ilia Mirkin

unread,
Feb 28, 2013, 5:00:21 PM2/28/13
to Mohammad Husain, prot...@googlegroups.com
Hmmm... I must have misremembered how Makefile stuff works, my bad.
Instead of $(pkg-config --cflags protobuf) try `pkg-config --cflags
protobuf`. (There's some way to evaluate stuff in the Makefile
directly, but apparently $() isn't it -- that's the sh way...)

Mohammad Husain

unread,
Feb 28, 2013, 5:08:44 PM2/28/13
to Ilia Mirkin, prot...@googlegroups.com
I tried that but unfortunately no luck yet: http://pastebin.com/Ln4AC7fH.

> Date: Thu, 28 Feb 2013 17:00:21 -0500

Ilia Mirkin

unread,
Feb 28, 2013, 5:13:57 PM2/28/13
to Mohammad Husain, prot...@googlegroups.com
There's a -c missing... the line should be like

$(CXX) $(CXXFLAGS) `pkg-config --cflags protobuf` -c -o $@ $^

Mohammad Husain

unread,
Feb 28, 2013, 6:00:01 PM2/28/13
to Ilia Mirkin, prot...@googlegroups.com
I added that but nothing changed :(

> Date: Thu, 28 Feb 2013 17:13:57 -0500

Mohammad Husain

unread,
Mar 4, 2013, 9:25:26 PM3/4/13
to prot...@googlegroups.com
Hi all,

With Ilia's help I could make some progress. I could come up with a Makefile which demonstrates that the problem is definitely with the way I am writing the Makefile:

<Makefile>
all: hello_protobuf

DEBUG = -g
LDFLAGS += `pkg-config --cflags --libs protobuf`
CXXFLAGS += `pkg-config --cflags --libs protobuf` -Wall $(DEBUG)


protoc_middleman: user.proto
    protoc --cpp_out=. user.proto
    @touch protoc_middleman

OBJS = hello_protobuf.o user.pb.o

hello_protobuf_1: hello_protobuf.cc protoc_middleman

    pkg-config --cflags protobuf  # fails if protobuf is not installed
    $(CXX) hello_protobuf.cc user.pb.cc -o hello_protobuf `pkg-config --cflags --libs protobuf`

hello_protobuf: protoc_middleman $(OBJS)
    $(CXX) $(LDFLAGS) -o hello_protobuf $(OBJS)

.PHONY = clean

clean:
    -rm -f *.o protoc_middleman
    -rm -f hello_protobuf
</Makefile>

The target "hello_protobuf_1" builds fine. I basically copied it from the Makefile in the examples directory:

$ make hello_protobuf_1
protoc --cpp_out=. user.proto

pkg-config --cflags protobuf  # fails if protobuf is not installed
-pthread -I/usr/local/include 
g++ hello_protobuf.cc user.pb.cc -o hello_protobuf `pkg-config --cflags --libs protobuf`
$ ./hello_protobuf
Username: username and ID: 1

However, the more conventional looking target "hello_protobuf" fails to build. I don't see any reason why it should fail:

$ make clean; make hello_protobuf
rm -f *.o protoc_middleman
rm -f hello_protobuf
protoc --cpp_out=. user.proto
g++ `pkg-config --cflags --libs protobuf` -Wall -g   -c -o hello_protobuf.o hello_protobuf.cc
g++ `pkg-config --cflags --libs protobuf` -Wall -g   -c -o user.pb.o user.pb.cc
g++ `pkg-config --cflags --libs protobuf` -o hello_protobuf hello_protobuf.o user.pb.o
hello_protobuf.o: In function `misc::User::set_username(char const*)':
user.pb.h:488: undefined reference to `google::protobuf::internal::kEmptyString'
...

Does anyone have any idea what I am missing with the target "hello_protobuf"?


From: farha...@hotmail.com
To: imi...@alum.mit.edu
CC: prot...@googlegroups.com
Subject: RE: [protobuf] Linker error
Date: Thu, 28 Feb 2013 11:10:24 -0800

Oliver Jowett

unread,
Mar 5, 2013, 4:03:04 AM3/5/13
to Mohammad Husain, prot...@googlegroups.com
On Tue, Mar 5, 2013 at 2:25 AM, Mohammad Husain <farha...@hotmail.com> wrote:

g++ `pkg-config --cflags --libs protobuf` -o hello_protobuf hello_protobuf.o user.pb.o

Probably just argument ordering. The library reference (which will come from pkg-config --libs) needs to appear after the object files that refer to symbols in the library.

In particular the g++ manpage says "It makes a difference where in the command you write [the -l option]; the linker searches and processes libraries and object files in the order they are specified.  Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o.  If bar.o refers to functions in z, those functions may not be loaded."

Oliver

Mohammad Husain

unread,
Mar 5, 2013, 3:50:56 PM3/5/13
to Oliver Jowett, prot...@googlegroups.com, imi...@alum.mit.edu
That was it! I changed the order and it worked!

$(CXX) -o hello_protobuf $(OBJS) $(LDFLAGS)

Thanks a lot.


Date: Tue, 5 Mar 2013 09:03:04 +0000

Subject: Re: [protobuf] Linker error
Reply all
Reply to author
Forward
0 new messages