Sign in to follow this  
CableGuy

DLLs in linux.

Recommended Posts

One more question.

In windows when you compile a dll you get a lib file which you
use to link with your programs, So the linker can know the symbols and everything.
From what i understood in linux you link directly to the "DLL".
If that is the case how do you export C++ class?

Share this post


Link to post
Share on other sites
On Linux you either export all symbols or none, to build a shared object you pass the -shared flag to the linker, which will export all symbols.

Then to link a second program against your .so, you use the -L and -l flags as you would with static libraries.

Share this post


Link to post
Share on other sites
Quote:
Original post by CableGuy
Which also handles classes?


Yes, a class method is in reality a function that takes a pointer (the "this" pointer) to the particular instance of the class (object) on witch it is being called, the class itself is declared on a header file, the compiler and linker take care of all the dirty work for you.

Note that due to Name Mangling and differences between compiler ABI's, you may not be able to link an application with compiler A against a C++ shared library compiled with compiler B, this is the same as with Windows DLLs, and thats why COM and CORBA came to be.

Share this post


Link to post
Share on other sites
Enjoy [smile]


// polygon.hpp:

#ifndef POLYGON_HPP
#define POLYGON_HPP

class polygon {
protected:
double side_length_;

public:
polygon()
: side_length_(0) {}

void set_side_length(double side_length) {
side_length_ = side_length;
}

virtual double area() const { }
};

// the types of the class factories
typedef polygon* create_t();
typedef void destroy_t(polygon*);

#endif




//main.cc:

#include "polygon.hpp"
#include <iostream>
#include <dlfcn.h>

int main() {
using std::cout;
using std::cerr;

// load the triangle library
void* triangle = dlopen("./triangle.so", RTLD_LAZY);
if (!triangle) {
cerr << "Cannot load library: " << dlerror() << '\n';
return 1;
}

// load the symbols
create_t* create_triangle = (create_t*) dlsym(triangle, "create");
destroy_t* destroy_triangle = (destroy_t*) dlsym(triangle, "destroy");
if (!create_triangle || !destroy_triangle) {
cerr << "Cannot load symbols: " << dlerror() << '\n';
return 1;
}

// create an instance of the class
polygon* poly = create_triangle();

// use the class
poly->set_side_length(7);
cout << "The area is: " << poly->area() << '\n';

// destroy the class
destroy_triangle(poly);

// unload the triangle library
dlclose(triangle);
}




// triangle.cc:

#include "polygon.hpp"
#include <cmath>

class triangle : public polygon {
public:
virtual double area() const {
return side_length_ * side_length_ * sqrt(3) / 2;
}
};


// the class factories

extern "C" polygon* create() {
return new triangle;
}

extern "C" void destroy(polygon* p) {
delete p;
}




# Compiler/Linker/dynamic linker
CC = g++
LD = g++

# flags to compile object files that can be used in a dynamic library
CFLAGS = -fPIC
# on some platforms, use '-fpic' instead.

# Flags to create a dynamic library.
DYNLINKFLAGS = -fPIC -shared -nostdlib -rdynamic
# on some platforms, use '-G' instead.

# files removal
RM = /bin/rm -f

# program's object files
PROG_OBJS = main.o

# program's executable
PROG = prog

# libraries to link with the program during compile time.
LIBS = -ldl

# shared library files
LIB_FILES = triangle.so

# shared libraries object files
LIB_OBJS = triangle.o

prog: prog.o
g++ $(CFLAGS) $(LIBS) -o prog main.o

prog.o: main.cc
g++ $(CFLAGS) $(LIBS) -c main.cc

# top-level rule
all: $(LIB_FILES) $(PROG)

$(PROG): $(PROG_OBJS)
$(LD) $(LDFLAGS) $(PROG_OBJS) $(LIBS) -o $(PROG)

# compile C source files into object files.
%.o: %.cc
$(CC) $(CFLAGS) -c $<


# create our librarys
triangle.so: triangle.o
$(LD) $(DYNLINKFLAGS) $< -o $@



# clean everything
clean:
$(RM) $(PROG_OBJS) $(PROG) $(LIB_OBJS) $(LIB_FILES)

# clean the program and its object files, don't touch the library.
cleanprog:
$(RM) $(PROG_OBJS) $(PROG)

# clean the library and its object files only
cleanlib:
$(RM) $(LIB_OBJS) $(LIB_FILES)

# clean the library's object files only
cleanlibobjs:
$(RM) $(LIB_OBJS)



To build it type "make" and then "make triangle.so".

Share this post


Link to post
Share on other sites
An alternative is to use [url=http://www.scons.org/]scons[/url].
Here is an example file (read the tutorial, it's pretty good):
# the game will be divided into tree separate parts:
# 1) a game library (independant of any 3rd-party library or OS)
# 2) a simplistic game engine (that does all the 3rd-party libraries and OS-dependant code)
# 3) one executable to rule them all :D

#####################################################################
# give a name for each binary module:
game_library = "fooblocks"
game_engine = "fooblocks-engine"
executable = "fooblocks"
#####################################################################

#####################################################################
# set the sources:

engine_sources = Split("""
init.c
graphics.c
input.c
text.c
time.c
""")

library_sources = Split("""
draw.c
gamelogic.c
ingameloop.c
player.c
""")

executable_sources = Split("""
fooblocks.c
""")
#####################################################################

#####################################################################
# declare the needed libraries

common_libs = Split("""
SDL
SDL_ttf
""")

# setting the dependancies:
engine_libs = common_libs
library_libs = common_libs + [game_engine] # TODO: see if common_libs is necessary at all
executable_libs = common_libs + [game_engine, game_library]
#####################################################################


#####################################################################
# general options

#prg_lib_path = Split("/usr/lib /usr/local/lib .")
prg_hdr_path = Split(".")
prg_lib_path = Split(".");

# do not recompile if there is no functional change
TargetSignatures("content") # default is build

#####################################################################

#####################################################################
# build the binary modules:

# the game engine:
SharedLibrary(
game_engine,
engine_sources,
LIBS = engine_libs,
LIBPATH = prg_lib_path,
CPPPATH = prg_hdr_path
)

# the game library:
SharedLibrary(
game_library,
library_sources,
LIBS = library_libs,
LIBPATH = prg_lib_path,
CPPPATH = prg_hdr_path
)

# the executable:
Program(executable,
executable_sources,
LIBS = executable_libs,
LIBPATH = prg_lib_path,
CPPPATH = prg_hdr_path
)
#####################################################################

As you can see, it's much easier to both read and maintain. As far as I am concerned, I'll never use autotoos/make in my projects. There are some reasons for this:
1) there is a single configuration file, which is way easier to read and maitain
2) the end user needs to have only one program installed, save for the buildchain
3) I don't need to know all compiler flags
4) I don't need MinGW or Cygwin in Windows to compile my projects (=> greatly simplifies porting)
5) I would choose Python over any shell-like language (brrr, C or ASM :P)

Share this post


Link to post
Share on other sites
Quote:
Original post by dilyan_rusev
Here is an example file...:

And here's the same example using autoconf/automake/libtool:

lib_LTLIBRARIES = fooblocks-engine.la fooblocks.la
bin_PROGRAMS = fooblocks

fooblocks_engine_la_SOURCES = init.c graphics.c input.c text.c time.c

fooblocks_la_SOURCES = draw.c gamelogic.c ingameloop.c player.c

fooblock_SOURCES = fooblocks.c
fooblocks_CXXFLAGS = $(SDL_CXXFLAGS)
fooblocks_LDFLAGS = $(SDL_LDFLAGS)
fooblocks_LIBS = fooblocks.la fooblocks-engine.la $(SDL_LIBS)

Quote:
As you can see, it's much easier to both read and maintain.

Really?

--smw

Share this post


Link to post
Share on other sites
Well, there are a few things to mentions.
1) I don't want a flame war started
2) I'm still learning scons, so I don't use all the automisation, as you do with autotools
3) Whatever you keep saying, porting is easier with scons
4) As I said in my first post, scons is an alternative, not the alternative, so I think this little dispute is over. Just let him choose by himselft. What we like is of little or no concern at all. After all, GNU/Linux is the freedom to choose, before anything else.

Share this post


Link to post
Share on other sites
Well, to complete the set, here's a CMake version :P


FIND_PACKAGE(SDL)
INCLUDE_DIRECTORIES(${SDL_INCLUDE_DIR})
ADD_LIBRARY(fooblocks-engine SHARED init.c graphics.c input.c text.c time.c)
ADD_LIBRARY(fooblocks-logic SHARED draw.c gamelogic.c ingameloop.c player.c)
ADD_EXECUTABLE(fooblocks fooblocks.c)
TARGET_LINK_LIBRARIES(fooblocks fooblocks-main fooblocks-logic ${SDL_LIBRARY})


Share this post


Link to post
Share on other sites
autoconf/automake/libtool has one big advantage over other build systems: There are lots of other programs built on top of it. Turning an autotools application in a .deb package (and probably RMP or KLik as well) is very easy and largely automated (e.g. debuild).

Share this post


Link to post
Share on other sites
Quote:
Original post by ZQJ
Well, to complete the set, here's a CMake version :P

Sweet. If I didn't already have so much invested in the autotools I might consider learning cmake.
Quote:
Original post by Sander
autoconf/automake/libtool has one big advantage over other build systems: There are lots of other programs built on top of it. Turning an autotools application in a .deb package (and probably RMP or KLik as well) is very easy and largely automated (e.g. debuild).

It's not so much of an advantage: both dpkg and rpmbuild are flexible enough that all you need do is write the appropriate rules file (for dpkg) or spec file (for rpmbuild) and you can use scons, cmake, ant, jam, or DCL batch files. The handy default for each of the major Linux packaging tools is the autotools, but it's not a requirement.

I would just recommend using a more sophisticated tool than yer basic makefile of you're buidling shared libraries, just like I would suggest using a high-level language for game writing. You would be mad to do otherwise.

--smw

Share this post


Link to post
Share on other sites
Quote:
Original post by BBB
Enjoy [smile]

*** Source Snippet Removed ***

*** Source Snippet Removed ***

*** Source Snippet Removed ***

*** Source Snippet Removed ***

To build it type "make" and then "make triangle.so".


Much appreciated! Rate++

Share this post


Link to post
Share on other sites
Sign in to follow this