March 2010 Archives

gcc/g++: Mixed static and dynamic linking

| No Comments
I couldn't find any good guide on how to do mixed static and dynamic linking with gcc or g++, so I just figured it out by trial and error. This is what I came up with. I hope it is technically accurate.

First of all, you need to decide what libraries you want statically linked (leaving, of course, the rest to be dynamically linked). You have to decide on your own strategy, but generic libraries, like your game engine, or your regular expression handler, are likely candidates. But you'll probably want to use dynamic linking for implementation specific functionality. For example, you don't want to statically link opengl libraries, because there will be a different implementation of that interface on each computer depending on what graphics card drivers have been installed.

Then, you will need to get the code archives for the libraries you want to statically link. These are *.a files, such as libclanCore.a. You get these when you compile the library from source, usually by specifying  --enable-static on the configure command line. When compiling these libraries, you'll generally want to be using the most generic compiling options you ca (-O2 optimization is usually fine) since the code may be run on a very wide variety of processors. Copy the *.a files you need into your source code directory.

Next, compile local source code files into object code. E.g.:

$ g++ -O2 -c *.cpp
Now, you need to do the linking. This part can be a bit tricky, and it will all be done in one command. For comparison, I'll first show you how I would normally link my code, using only dynamic linking:

$ g++ -O2   -o lusus_stack data.o lusus_stack.o     \
lusus_stack_funcs.o lusus_fallingleaf.o \
lusus_explodinglogo.o lusus_stacktitle.o \
lusus_wstackgraphic.o  -lXxf86vm -lclanApp \
-lclanCore -lclanDisplay -lclanSound -lclanVorbis \
-lfontconfig -lfreetype -lclanGDI

This produces an executable called lusus_stack. But I want to statically compile in all the clanlib game engine files. So I copy the libclan*.a files I needed into my source directory, and use this command:

$ g++ data.o lusus_stack.o lusus_stack_funcs.o      \
lusus_fallingleaf.o lusus_explodinglogo.o \
lusus_stacktitle.o lusus_wstackgraphic.o -o statapp \
libclanVorbis.a -lvorbis libclanSound.a -lasound \
libclanGDI.a libclanDisplay.a -lpng12 -ljpeg \
libclanApp.a libclanCore.a -lXxf86vm -lfontconfig \
-lpthread
You'll notice four elements here:
  • My local object code (*.o files)
  • Imported code archives (*.a files)
  • dynamically linked libraries (normal -l syntax)
  • the file name to be given to the executable (-o)
I did not use the -static option, because -static prevents any dynamic linking from being used.

You will also see that I had to specify more libraries this time to be dynamically linked. These are the dependencies of the statically linked archives. You have to specify these manually now, because the system won't be able to dynamically figure them out later (from the shared object files).

How do you figure out what the dependencies are? One way is to use the ldd tool on the shared object (.so) version of the library, like so:

$ ldd /usr/local/lib/libclanDisplay.so 
    linux-vdso.so.1 =>  (0x00007fff7bbff000)
    libpng12.so.0 => /usr/lib/libpng12.so.0 (0x00007fd1174b5000)
    libjpeg.so.7 => /usr/lib/libjpeg.so.7 (0x00007fd117277000)
    libz.so.1 => /lib/libz.so.1 (0x00007fd117061000)
    libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/libstdc++.so.6 (0x00007fd116d5e000)
    libm.so.6 => /lib/libm.so.6 (0x00007fd116ada000)
    libc.so.6 => /lib/libc.so.6 (0x00007fd116785000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fd117a5d000)
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007fd11656f000)

Some of these libraries you won't need to specify, like libc, because they are automatically included by gcc/g++, or because they are dynamically loaded by some other library to which you are dynamically linking. But you can see here some obvious ones like libpng and libjpeg.

Now, important note: It does matter in which order you place the files on the command-line when you go to do the linking! The reason for this: when gcc/g++ looks to resolve undefined references to functions, it will only resolve those references for files that have already been processed.

What that means: if FILE A depends on functions from FILE B, put FILE A before FILE B on the command-line.

How will you know if you failed to link in a library needed by one of your static libraries? Simple: gcc/g++ will spit out about 300 pages worth of complaints, looking something like this:

libclanDisplay.a(jpeg_provider.o): In function `CL_JPEGProvider::save(CL_PixelBuffer, CL_StringContainer<char, CL_StringReference<char, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, CL_VirtualDirectory&, int)':
/scratch/choward/ClanLib-2.0.4/Sources/Display/ImageProviders/jpeg_provider.cpp:114: undefined reference to `jpeg_std_error'
/scratch/choward/ClanLib-2.0.4/Sources/Display/ImageProviders/jpeg_provider.cpp:116: undefined reference to `jpeg_CreateCompress'
/scratch/choward/ClanLib-2.0.4/Sources/Display/ImageProviders/jpeg_provider.cpp:137: undefined reference to `jpeg_stdio_dest'
/scratch/choward/ClanLib-2.0.4/Sources/Display/ImageProviders/jpeg_provider.cpp:152: undefined reference to `jpeg_set_defaults'
/scratch/choward/ClanLib-2.0.4/Sources/Display/ImageProviders/jpeg_provider.cpp:156: undefined reference to `jpeg_set_quality'
...

You can figure out what library is missing its dependencies from the first line here: libclanDisplay. And you have to guess which library you need from the complaints about what functions are missing. It's pretty obvious here that we need libjpeg.

Anyway, that's all folks. If I have posted anything inaccurate or incomplete, let me know in the comments.

[Shameless plug: Be sure to checkout out my programming web site at linuxprogrammingforums.com!]

New Website: Linux Programming Forums

| No Comments
I have started a new web site:

linuxprogrammingforums.com

The web site provides online forum resource for a wide variety of languages and programming topics. The layout and organization of the forums is geared toward the needs and mindset of programmers with a Linux background.

The board motto is

"May the source be with you."

Java BufferedImage: Beware of getSubimage!

| No Comments
Wow, I just spent way too long trying to figure out a bug in some of my gaming code. Nothing made sense no matter how many times I looked at the problem and how many angles I considered. The weirdest things were happening in my graphical output, and I was getting very frustrated.

I got desperate and decided to look over the APIs of all the graphical functions I was using. Then I looked at the BufferedImage.getSubimage function API and it was painfully obvious:

getSubimage

public BufferedImage getSubimage(int x,
                                 int y,
                                 int w,
                                 int h)

    Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image.

    Parameters:
        w - the width of the specified rectangular region
        h - the height of the specified rectangular region
    Returns:
        a BufferedImage that is the subimage of this BufferedImage.
    Throws:
        RasterFormatException - if the specified area is not contained within this BufferedImage.

I had assumed that getSubimage would return a new BufferImage array, but it actually is really just a map to part of the original BufferImage array. Consequently, whenever I was painting in the new BufferImage object, I was actually painting all over my original BufferImage!

Well, that was a lesson learned the really hard way.
The site blog for indicium.us.
Linux Projects
Online Games
Unsung Linux Games

RSS Feed

Powered by Movable Type 4.21-en
and GNU/Linux


Creative Commons License
The content of this blog is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License. See my copyleft page for more details.