LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-13-2011, 10:41 AM   #1
micropanther
LQ Newbie
 
Registered: Oct 2007
Location: Charlotte, NC
Distribution: Ubuntu 10.04, Davinci (MacOS/X)
Posts: 20

Rep: Reputation: 0
"Unresolved reference" errora while doing dynamic Linking of C++.so (shared object)


I am creating two shared libs that i intend to be dynamically linkable in C and C++, cross platform Linux/Windows/Mac.

As a basic sketch, true for both libs, the lib code is in several .c/.cpp and .h files.

For now, I'll talk about the part that I am actively working on, a lib named Discover, i.e. libdiscover.so.1.0.

First, everything is in a namespace, RemKon_Discover.

The main Discover.cpp defines the methods for the Discover class (declared in Discover.h) and has extern "C' routines that can return pointers to my main c++ object. The call to GetLibraryMainPointer() creates a Discover class object, theMainObject (ok, I win a prize for dumb names) and returns the (non-mangled) pointer to the caller over in my test program. The Discover class itself is declared extern "c" and the tester program #includes "Discover.h".

In the test program, dlopen() correctly opens the lib and dlsym() gets the pointer to theMainObject. However, when I use that pointer in the tester program to access a method (aDiscoverObject->hello(), e.g.) I get compile time errors saying that Discover::hello() in an undefined reference.

My makefile is attached.

Code:
./RemKonTester/Debug/RemKonTester.o: In function `main':
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:111: undefined reference to `RemKon_Discover::DiscoverObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:116: undefined reference to `RemKon_Discover::DiscoverObject::SetLogLevel(unsigned int)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:117: undefined reference to `RemKon_Discover::DiscoverObject::hello()'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:118: undefined reference to `RemKon_Discover::DiscoverObject::LocalIpAddress(int)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:122: undefined reference to `RemKon_Discover::DiscoverObject::RegisterCallback(bool (*)(void*), void*)'
/home/wmiller/Projects/Eclipse/./RemKonTester/RemKonTester.cpp:123: undefined reference to `RemKon_Discover::DiscoverObject::Search()'
collect2: ld returned 1 exit status
Question, what am I missing or doing wrong? Notice that the line to link RemKonTester does not have any -l (lowercase -L)'s in it. If they are there I get static linking. That's a no no.

Wes
Attached Files
File Type: txt makefile.txt (7.3 KB, 39 views)

Last edited by archtoad6; 04-15-2011 at 05:39 AM. Reason: Move to Programming, preserve 0-reply
 
Old 04-15-2011, 06:37 AM   #2
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
The Makefile is not "yours"; it was generated by Eclipse.

There are two possibilities that would explain the undefined reference error(s): 1) You neglected to specify the library that contains the implementation of the unresolved functions (or data objects), or 2) you failed to implement these unresolved functions.

Please recheck your library code to verify the functions are indeed implemented. If all is good, then check your Eclipse project settings.

You might also want to consider learning how to build a project using the command line, perhaps using a Makefile that you have created, before placing all your faith in an IDE.

P.S. Check to ensure the following is complete:
Code:
liblinkflags := -lstdc++ -lrt -lpthread -fPIC  -shared
tstlinkflags := -ldl  -lpthread -rdynamic
Note, you do not need to specify -lstdc++, nor -fPIC, for your link flags. For the former, g++ automatically links again the library; for the latter, it is not applicable when linking (should only be used when compiling library source code).

Edit: You have not specified -ledgeio nor -ldiscover in the link flags above.

Last edited by dwhitney67; 04-15-2011 at 06:45 AM.
 
Old 04-15-2011, 01:19 PM   #3
JohnGraham
Member
 
Registered: Oct 2009
Posts: 467

Rep: Reputation: 139Reputation: 139
Quote:
Originally Posted by micropanther View Post
In the test program, dlopen() correctly opens the lib and dlsym() gets the pointer to theMainObject. However, when I use that pointer in the tester program to access a method (aDiscoverObject->hello(), e.g.) I get compile time errors saying that Discover::hello() in an undefined reference.

Notice that the line to link RemKonTester does not have any -l (lowercase -L)'s in it. If they are there I get static linking. That's a no no.
It sounds like you're expecting to be able to get a pointer to aDiscoverObject from dlsym() and for all its methods to come with it, so you can call them without linking to the library they come from at link-time - well, that's just not possible. When you call object->method(x, y) in C++, what you're really doing is making a call to something like __Znamespace_object_method(object, x, y). The method itself is just a plain function, and if you want to call it, you'll have to be able to see it at link-time or the linker will report an error.

To do what you want to do, you'd have to use dlsym() to get a pointer to the method (which will involve finding the mangled name of the method) and the object, and call something like (*meth)(obj, x, y). Unfortunately, C++'s implementation of how exactly parameters are passed to member functions (or how names are mangled) isn't mandated by any standard - you can find out what a particular implementation does and do that, but if things change your library won't be able to work. And it certainly won't be portable at all.

Bottom line: calling C++ class member functions using dlsym is a no-go area. If you really want to export a C++ API in this way, make wrapper functions with C-style linkage and pass pointers to objects around.

(That's all assuming I've understood what you're trying to do correctly...)

Last edited by JohnGraham; 04-15-2011 at 01:21 PM.
 
Old 04-17-2011, 11:01 AM   #4
micropanther
LQ Newbie
 
Registered: Oct 2007
Location: Charlotte, NC
Distribution: Ubuntu 10.04, Davinci (MacOS/X)
Posts: 20

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by dwhitney67 View Post
The Makefile is not "yours"; it was generated by Eclipse.
No, it's mine. Eclipse makes Makefile, not makefiles (capitalization). This is my makefile I wrote by hand. The behavior is exactly the same as Eclipse's though.


Quote:
Originally Posted by dwhitney67 View Post
Please recheck your library code to verify the functions are indeed implemented. If all is good, then check your Eclipse project settings.
All there. All working is VC++ with dynamic linking.


Edit: You have not specif
Quote:
Originally Posted by dwhitney67 View Post
ied -ledgeio nor -ldiscover in the link flags above.
No, adding those cause evewrything to compile, but I get static linking which I DO NOT want. I want to ship object code only.

Thanks,

Wes
 
Old 04-17-2011, 02:42 PM   #5
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Quote:
Originally Posted by micropanther View Post
No, adding those cause evewrything to compile, but I get static linking which I DO NOT want. I want to ship object code only.
How did you achieve static linking? You created two shared-object libraries (and no static libraries), and when you build the executable, I do not see any instruction telling the linker to use -static.

Thus could you please elaborate a little further as to what you meant above?
 
Old 04-18-2011, 08:45 AM   #6
micropanther
LQ Newbie
 
Registered: Oct 2007
Location: Charlotte, NC
Distribution: Ubuntu 10.04, Davinci (MacOS/X)
Posts: 20

Original Poster
Rep: Reputation: 0
Quote:
How did you achieve static linking? You created two shared-object libraries (and no static libraries), and when you build the executable, I do not see any instruction telling the linker to use -static.

Thus could you please elaborate a little further as to what you meant above?
Well, I think you've found my problem from a different angle. Maybe it isn't doing static linking, oly something that fools me into thinking it is.

When I execute my tester program, I see messages from the libraries before I see the tester program start. The init() in one or the other library runs twice (I THINK the loader is seeing that I have two so_init()s and runs the same one twice -- first one it finds maybe? Anyway, only after the so-init() runs (twice) and I get some debug messages from the libraries, do I see the first debug messages from my tester code.

Code:
 
./Debug/RemKonTester 
DEBUGMSG:   Discover.so: starting.           // Discover.so cited but EdgeIO-Lib.log created
Logfile "EdgeIO_Lib.log" created.
DEBUGMSG:   Discover.so: starting.           // Got it right here
Logfile "Discover_Lib.log" created.
Logfile "RemKonTester.log" created.          // First thing said by tester code.  Tester created log obj in global space
DEBUGMSG:   Discover.so: starting.           // Next four lines follow dlopen()/dlsym() in tester   
Logfile "EdgeIO_Lib.log" created.
DEBUGMSG:  EdgeIO Object Created.

04/18/11 09:24:51:  Library libedgeio.so attached and Version Info retrieved.   // Tester msg
anEdgeIoObject.test_int = 980722              Public var in EdgeIO lib
anEdgeIoObject.hello() = EdgeIoObject says hello.   // hello() function in EdgeIO lib

DEBUGMSG:   Discover.so: starting.
Logfile "Discover_Lib.log" created.
DEBUGMSG:   Discover Object Created.
04/18/11 09:24:51:  Library libdiscover.so attached and Version Info retrieved.
aDiscoverObject.test_int = 704293
aDiscoverObject.hello() = DiscoverObject says hello.

04/18/11 09:24:51:  Discover loglevel set to 4.  


Does this help?

Wes
 
Old 04-18-2011, 09:00 AM   #7
dwhitney67
Senior Member
 
Registered: Jun 2006
Location: Maryland
Distribution: Kubuntu, Fedora, RHEL
Posts: 1,541

Rep: Reputation: 335Reputation: 335Reputation: 335Reputation: 335
Are you still employing the use of dlopen()? If so, is there a particular reason for doing such?

I get the impression from your project that you are merely creating two shared-object libraries, and then linking them with your application so that you can build an executable. You then run the program, and generate some output. How/when this output is produced is still appearing fuzzy in my crystal ball.

Just for grins, here is the most trivial app that employs the use of a shared-object library; perhaps you could play with it before delving into more complex things.

SimpleLib.h
Code:
#ifndef LIB_HEADER_H
#define LIB_HEADER_H

void function();

#endif
SimpleLib.cpp:
Code:
#include "SimpleLib.h"
#include <iostream>

void function()
{
   std::cout << "Function called." << std::endl;
}
Build library:
Code:
g++ -Wall -fPIC SimpleLib.cpp -shared -o libsimple.so
App.cpp:
Code:
#include "SimpleLib.h"

int main()
{
   function();
}
Build application:
Code:
g++ -Wall App.cpp -L./ -lsimple -o app
Run application:
Code:
LD_LIBRARY_PATH=./ ./app

Last edited by dwhitney67; 04-18-2011 at 09:01 AM.
 
Old 04-18-2011, 09:38 AM   #8
micropanther
LQ Newbie
 
Registered: Oct 2007
Location: Charlotte, NC
Distribution: Ubuntu 10.04, Davinci (MacOS/X)
Posts: 20

Original Poster
Rep: Reputation: 0
""Unresolved reference" errora while doing dynamic Linking of C++.so (shared object)

Quote:
Originally Posted by JohnGraham View Post
It sounds like you're expecting to be able to get a pointer to aDiscoverObject from dlsym() and for all its methods to come with it, so you can call them without linking to the library they come from at link-time - well, that's just not possible. When you call object->method(x, y) in C++, what you're really doing is making a call to something like __Znamespace_object_method(object, x, y). The method itself is just a plain function, and if you want to call it, you'll have to be able to see it at link-time or the linker will report an error.
Well, yeah that's what I want.

Quote:
Originally Posted by JohnGraham View Post
To do what you want to do, you'd have to use dlsym() to get a pointer to the method (which will involve finding the mangled name of the method) and the object, and call something like (*meth)(obj, x, y). Unfortunately, C++'s implementation of how exactly parameters are passed to member functions (or how names are mangled) isn't mandated by any standard - you can find out what a particular implementation does and do that, but if things change your library won't be able to work. And it certainly won't be portable at all.
Ummmm,

Code:
extern "C"
class xyv
{
   ...
};
} // end extern "C"
should make the class and its methods 'seeable", right?




Wes

Last edited by micropanther; 04-18-2011 at 09:40 AM. Reason: Type, forgot code block.
 
Old 04-18-2011, 10:06 AM   #9
JohnGraham
Member
 
Registered: Oct 2009
Posts: 467

Rep: Reputation: 139Reputation: 139
Quote:
Originally Posted by micropanther View Post
Ummmm,

Code:
extern "C"
class xyv
{
   ...
};
} // end extern "C"
should make the class and its methods 'seeable", right?
What do you think `extern "C"' means? It has nothing to do with visibility - it's all about linkage and name mangling. It bypasses C++'s name mangling (which it needs to support namespaces/classes/overloading) so that functions have C-style linkage. You cannot `extern "C"' a class because you need the name mangling - declaring a class extern "C" will either be ignored by the compiler or generate an error.

Quote:
Quote:
It sounds like you're expecting to be able to get a pointer to aDiscoverObject from dlsym() and for all its methods to come with it, so you can call them without linking to the library they come from at link-time - well, that's just not possible. When you call object->method(x, y) in C++, what you're really doing is making a call to something like __Znamespace_object_method(object, x, y). The method itself is just a plain function, and if you want to call it, you'll have to be able to see it at link-time or the linker will report an error.
Well, yeah that's what I want.
Like I said, just getting a pointer to an object won't "bring" the methods out of a shared library - you'll still have to get pointers to the functions you're calling, and call it with whatever hidden arguments that implementation of C++ expects. This is non-portable for the same reason that you can't use a C++ library that's been compiled with a different compiler to the one you're using for compiling/linking your application - the name mangling and ABI will be different.

Unless you have a specific reason for doing what you want to do using dlopen/dlsym etc. and know (or want to learn) how to export a C++ library through a C API (hint: C can't use classes...), I'd suggest you stick with just plain dynamic linking if you want anything that will work...

Last edited by JohnGraham; 04-18-2011 at 10:08 AM.
 
Old 04-19-2011, 06:52 AM   #10
micropanther
LQ Newbie
 
Registered: Oct 2007
Location: Charlotte, NC
Distribution: Ubuntu 10.04, Davinci (MacOS/X)
Posts: 20

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by dwhitney67 View Post
Are you still employing the use of dlopen()? If so, is there a particular reason for doing such?
Yes, still using dlopen() and dlsym(). Because I want to ship dynamically linkable, object-code-only libs.

Quote:
Originally Posted by dwhitney67 View Post
I get the impression from your project that you are merely creating two shared-object libraries, and then linking them with your application so that you can build an executable. You then run the program, and generate some output. How/when this output is produced is still appearing fuzzy in my crystal ball.
I am creating two Object Code Only libraries, thus they need to be dynamically linkable. They will find (Discover) a class of internet devices we sell then control them (EdgeIO). The libs are just to make it easier for customers to program with/for our hardware. The C++ test program dlopen()s the two libs and invokes their functions. Right now, the tester loads both, but only really uses Discover. The tester registers a callback function that Discover uses to notify the tester where to find a structure of currently found devices. Dead simple stuff.

My concern comes from John Graham's posts that say I can't do what I really want to do. This really worries me since I have exactly what I want for VC++, just not with g++. I don't want an MS linux compiler, but I sure would love some degree of sameness between the two (three -- OS/X?) op syses.

Quote:
Originally Posted by dwhitney67 View Post
Just for grins, here is the most trivial app that employs the use of a shared-object library; perhaps you could play with it before delving into more complex things.
Why not. I have, however, done this before and gotten the desired results with both g++ and VC++.

Thanks for your help.

Wes
 
Old 04-19-2011, 06:59 AM   #11
micropanther
LQ Newbie
 
Registered: Oct 2007
Location: Charlotte, NC
Distribution: Ubuntu 10.04, Davinci (MacOS/X)
Posts: 20

Original Poster
Rep: Reputation: 0
Well, I'm just going to take your word for it. I have gotten whatever it is I am trying to do to work before in a project that compiled for 19 different OS'es including Windows 32 and 64, 9 linuxes and AIX. Maybe someday I'll figure out why one worked and the other doesn't. In the meantime, I am going back to pure C external calls.

I have posted more detail in other replies if you care to read them.

Thanks for all the help.

Wes
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Can't call method "prepare" without a package or object reference shifter Programming 5 10-04-2010 09:04 AM
Tip: handling "cannot open shared object file..." sundialsvcs Linux - Newbie 1 03-06-2006 12:57 PM
G++ Linking Error "undefined reference" djjumper9 Programming 2 04-13-2004 09:36 AM
Not loading gdm;"libX11.so.6 cannot open shared object" zlobby Linux - Newbie 6 03-03-2004 04:30 PM
/usr/libexec/ld-elf.so.1: Shared object "libgd.so.4" not found lxxy *BSD 1 12-04-2003 12:01 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 03:36 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration