views:

8941

answers:

6

This is a follow-up to this question.

I'm trying to create a shared class library in C++ on Linux. I'm able to get the library to compile, and I can call some of the (non-class) functions using the tutorials that I found here and here. My problems start when I try to use the classes that are defined in the library. The second tutorial that I linked to shows how to load the symbols for creating objects of the classes defined in the library, but stops short of using those objects to get any work done.

Does anyone know of a more complete tutorial for creating shared C++ class libraries that also shows how to use those classes in a separate executable? A very simple tutorial that shows object creation, use (simple getters and setters would be fine), and deletion would be fantastic. A link or a reference to some open source code that illustrates the use of a shared class library would be equally good.

+1  A: 

Chapter 1 of C++ Cookbook has several scenarios for building static and dynamic C++ libraries using various build tools, include Make, Boost.build, and a few IDEs.

Scottie T
Thanks, I'll have to swing by a bookstore on the way home to see if it has enough detail for me. I'm using a limited school-edition Safari account and unfortunately C++ Cookbook is restricted. :(
Bill the Lizard
+10  A: 
nimrodm
This appears (to my very untrained eye) to be statically linking libshared.so to your executable, rather than using dynamic linking at run-time. Am I correct?
Bill the Lizard
No. This is standard Unix (Linux) dynamic linking. A dynamic library has the extension ".so" (Shared Object) and is linked with the executable (main in this case) at load time -- every time main is loaded. Static linking occurs at link time and uses libraries with the extension ".a" (archive).
nimrodm
This is dynamically linked at _build_ time. In other words you need prior knowledge of the library you're linking against (e.g. linking against 'dl' for dlopen). This is different from dynamically _loading_ a library, based on say, a user specified filename, where prior knowledge is not needed.
codelogic
Build time? What exactly do you mean by build? The library is linked in when 'main' is loaded. This is handled by the linux dynamic linker (ld-linux.so - last in the dependency list). Replacing libshared.so with a newer library will work automatically. No need to recompile/re-link (rebuild?)
nimrodm
Thank you, I did finally get this to work. I also verified that the shared library is loaded at run time. Pretty simple to verify by just deleting the library and running main. :)
Bill the Lizard
What I was trying to explain (badly) is that in this case, you need to know the name of the library at build time (you need to pass -lshared to gcc). Usually, one uses dlopen() when that information is not available, i.e. the library's name is discovered at runtime (eg: plugin enumeration).
codelogic
+2  A: 

Basically, you should include the class' header file in the code where you want to use the class in the shared library. Then, when you link, use the '-l' flag to link your code with the shared library. Of course, this requires the .so to be where the OS can find it. See 3.5. Installing and Using a Shared Library

Using dlsym is for when you don't know at compile time which library you want to use. That doesn't sound like it's the case here. Maybe the confusion is that Windows calls the dynamically loaded libraries whether you do the linking at compile or run-time (with analogous methods)? If so, then you can think of dlsym as the equivalent of LoadLibrary.

If you really do need to dynamically load the libraries (i.e., they're plug-ins), then this FAQ should help.

Matt Lewis
The reason I need a dynamic shared library is that I'll also be calling it from Perl code. It may be a complete misconception on my own part that I also need to call it dynamically from other C++ programs that I'm developing.
Bill the Lizard
I've never tried integrated perl and C++, but I think you need to use XS: http://www.johnkeiser.com/perl-xs-c++.html
Matt Lewis
+12  A: 

myclass.h

#ifndef __MYCLASS_H__
#define __MYCLASS_H__

class MyClass
{
public:
  MyClass();

  /* use virtual otherwise linker will try to perform static linkage */
  virtual void DoSomething();

private:
  int x;
};

#endif

myclass.cc

#include "myclass.h"
#include <iostream>

using namespace std;

extern "C" MyClass* create_object()
{
  return new MyClass;
}

extern "C" void destroy_object( MyClass* object )
{
  delete object;
}

MyClass::MyClass()
{
  x = 20;
}

void MyClass::DoSomething()
{
  cout<<x<<endl;
}

class_user.cc

#include <dlfcn.h>
#include <iostream>
#include "myclass.h"

using namespace std;

int main(int argc, char **argv)
{
  /* on Linux, use "./myclass.so" */
  void* handle = dlopen("myclass.so", RTLD_LAZY);

  MyClass* (*create)();
  void (*destroy)(MyClass*);

  create = (MyClass* (*)())dlsym(handle, "create_object");
  destroy = (void (*)(MyClass*))dlsym(handle, "destroy_object");

  MyClass* myClass = (MyClass*)create();
  myClass->DoSomething();
  destroy( myClass );
}

On Mac OS X, compile with:

g++ -dynamiclib -flat_namespace myclass.cc -o myclass.so
g++ class_user.cc -o class_user

On Linux, compile with:

g++ -fPIC -shared myclass.cc -o myclass.so
g++ class_user.cc -ldl -o class_user

If this were for a plugin system, you would use MyClass as a base class and define all the required functions virtual. The plugin author would then derive from MyClass, override the virtuals and implement create_object and destroy_object. Your main application would not need to be changed in any way.

codelogic
I'm in the process of trying this, but just have one question. Is it strictly necessary to use void*, or could the create_object function return MyClass* instead? I'm not asking you to change this for me, I'd just like to know if there's a reason to use one over the other.
Bill the Lizard
It can be MyClass*, no reason for it to be void*, I've updated it.
codelogic
Thanks, I tried this and it worked as is on Linux from the command line (once I made the change you suggested in the code comments). I appreciate your time.
Bill the Lizard
+1  A: 

Although the answers from codelogic and nimrodm do work, I just wanted to add that I picked up a copy of Beginning Linux Programming since asking this question, and its first chapter has example C code and good explanations for creating and using both static and shared libraries. These examples are available through Google Book Search in an older edition of that book.

Bill the Lizard
A: 

nimrodm,

Lets say you create an object Ab from class A.

A is defined in a header file h1.h A is implemented in a shared library file myShared.so

Lets now say that objet Ab is instanciated from a third file main.cpp and objet Ac is instanciated from a fourth file main2.cpp which also uses myShared.so.

Question: Will Ac and Ab be a shared object? I'm doing a program where this seems to be the case, but then I might be missing something.

thanks

h

hz