GCC Static Linking And Separate Loader - gcc

I'm trying to understand the process of static linking, loading of GCC:
I have the following toy program
#include "stdio.h"
int main() {
fprintf(stdout, "Hello World \n");
return 0 ;
}
I can compile it and run file as follows:
gcc -static -std=gnu99 -Wall -Wno-unused -g test.c -o test;
But as soon as I try to separate out the compile and linking process as follows:
gcc -static -std=gnu99 -Wall -Wno-unused -g test.c -c;
ld -o test -T link.lds test.o
where the link.lds is
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
I get the error "undefined reference to stdouttest.o: In function `main':
test.c:(.text+0x7): undefined reference to `stdout'
test.c:(.text+0x1e): undefined reference to `fwrite'
If I try adding the flag -lc to ld, it tells me that it is not found. I've tried running gcc with -lc
and/or -static-libgcc but I have the same problem.
What am I doing wrong?

Do
gcc -v -static -std=gnu99 -Wall -Wno-unused -g test.c
and look for the collect2 tag.
In my case it is
collect2 --sysroot=/ --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o test /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../.. /tmp/ccoR98Xr.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o
You have to replace the temporary object file. In my case I replaced /tmp/ccoR98Xr.o with test.o. Then do
gcc -c -std=gnu99 -Wall -Wno-unused -g test.c
ld --sysroot=/ --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o test /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../.. test.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o
It links to the object files : crt1.o, crti.o, crtbeginT.o, crtend.o, and crtn.o.
It links to the libraires: libgcc.a, libgcc_eh.a, and libc.a.
You can replace --start-group -lgcc -lgcc_eh -lc --end-group with -lgcc -lc -lgcc_eh -lc if you like.
Knowing this we can simply this to
ln -s `gcc -print-file-name=crt1.o`
ln -s `gcc -print-file-name=crti.o`
ln -s `gcc -print-file-name=crtn.o`
ln -s `gcc -print-file-name=libgcc_eh.a`
ln -s `gcc -print-file-name=libc.a`
gcc -c -std=gnu99 -Wall -Wno-unused -g test.c
ld -m elf_x86_64 -o test crt1.o crti.o test.o libc.a libgcc_eh.a libc.a crtn.o
I did not use crtbeginT.o, crtend.o, and libgcc.a because it worked without them.

Take a look at this, strace does the job (show you the secrets) but you will soon realize there are tons of options in it... You need to link a few stuff together (from GNU C lib) to get your executable, not only your object... You can add grep 'exec' in the end to make it cleaner.
Uhhh, also you need to do this:
as obj.s -o obj.o
Use GNU assembler to convert your .s to .o then link with ld.

Related

LTO and overriding stdlib functions in static libraries

I have an embedded platform that brings its own stdlib functions like malloc and printf in a static library. I need to compile this library with LTO. Unfortunately in this combination (-flto + -nostdlib + linking with stdlib replacements from an .a) the linker cannot find the functions.
I have prepared a MWE that should run on most Unix machines but since it contains multiple files I have put it into a repo:
https://github.com/stefanct/lto_static_libs
The included makefile allows to switch on some features on and off for testing:
nostdlib=y: add -nostdlib to the linking stage
nolto=y: disable LTO
libfunc=y: enable a call to a non-standard function within the library (you will see why at the end!)
The gist is to have one module containing a standard function, e.g.:
int puts(const char *s) {
return 2;
}
Compiling that into an object file with -flto, putting it into a static library with gcc-ar and eventually using that when linking with an application.
In my setup (GCC 11 branch built from source and GNU ld 2.31.1 from Debian Buster) I get the following results:
No options set: OK - the printf from the library gets overridden(?) by the standard function:
$ make -B
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -c -o libtest.o libtest.c
lto-dump -list libtest.o
Type Visibility Size Name
function default 4 lib_func
function default 4 puts
function default 4 printf
gcc-nm libtest.o
00000000 T lib_func
00000000 T printf
00000000 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -o exe main.o -L. -ltest
$ ./exe
hurga
No stdlib but also without LTO: OK - linking works fine(ish - running segfaults but that's to be expected I guess and could be worked around with -nodefaultlibs but I don't care here)
$ make -B nostdlib=y nolto=y
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter -c -o libtest.o libtest.c
gcc-nm libtest.o
0000000000000074 T lib_func
0000000000000000 T printf
0000000000000065 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter -o exe main.o -L. -ltest -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
No stdlib but leaving LTO enabled: suddenly puts is no longer found.
However, as you can see, the object file that gets put into the library contains the function just fine (and evengcc-mn libtest.a shows the same).
This is the case I would like to fix. Why is this breaking?
$ make -B nostdlib=y
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -c -o libtest.o libtest.c
lto-dump -list libtest.o
Type Visibility Size Name
function default 4 lib_func
function default 4 puts
function default 4 printf
gcc-nm libtest.o
00000000 T lib_func
00000000 T printf
00000000 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -o exe main.o -L. -ltest -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
/usr/bin/ld: /tmp/cczvyrrg.ltrans0.ltrans.o: in function `main':
<artificial>:(.text+0xe): undefined reference to `puts'
collect2: error: ld returned 1 exit status
make: *** [makefile:39: exe] Error 1
Interestingly enough, if we call another unrelated (non-standard) function in the same library things start to work again!?
$ make -B nostdlib=y libfunc=y
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -D LIB_FUNC -c -o libtest.o libtest.c
lto-dump -list libtest.o
Type Visibility Size Name
function default 4 lib_func
function default 4 puts
function default 4 printf
gcc-nm libtest.o
00000000 T lib_func
00000000 T printf
00000000 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -D LIB_FUNC -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects -D LIB_FUNC -o exe main.o -L. -ltest -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
Do I see a bug in binutils/ld? Is this fixed upstream?

Unable to link find libraries when linking

When I link the .ld file using gcc I got the following error
/usr/bin/ld: cannot find -lreadline
collect2: error: ld returned 1 exit status
my run.sh scripts contains the following command
rm *.o *.bin *.iso
rm -rf isodir
assemble boot.s file
as --32 boot.s -o boot.o
linking the kernel with kernel.o and boot.o files
gcc -m32 -lunistd -Wno-unused-result -c kernelCheck.c -o kernel.o -std=gnu99 -ffreestanding -flto -O2 -Wall -Wextra -L/usr/lib -fno-exceptions
gcc -m32 -T linker.ld -o MoraWing.bin -ffreestanding -Wl,--build-id=none -O2 -nostdlib boot.o kernel.o -lgcc
grub-file --is-x86-multiboot MoraWing.bin
building the iso file
mkdir -p isodir/boot/grub
cp MoraWing.bin isodir/boot/MoraWing.bin
cp grub.cfg isodir/boot/grub/grub.cfg
grub-mkrescue -o MoraWing.iso ./isodir
run it in qemu
qemu-system-x86_64 -cdrom MoraWing.iso
You need to install libreadline-dev, or a similar package suitable for your system (you should also specify what your system is).

Same Makefile executing different commands in different computers

During installation of pintos, I had to run make.
Following is the Makefile.
all: setitimer-helper squish-pty squish-unix
CC = gcc
CFLAGS = -Wall -W
LDFLAGS = -lm
setitimer-helper: setitimer-helper.o
squish-pty: squish-pty.o
squish-unix: squish-unix.o
clean:
rm -f *.o setitimer-helper squish-pty squish-unix
In one computer it executed correctly. (output for the command is given below)
gcc -Wall -W -c -o setitimer-helper.o setitimer-helper.c
gcc -lm setitimer-helper.o -o setitimer-helper
gcc -Wall -W -c -o squish-pty.o squish-pty.c
gcc -lm squish-pty.o -o squish-pty
gcc -Wall -W -c -o squish-unix.o squish-unix.c
gcc -lm squish-unix.o -o squish-unix
but in other computer I got the following error
gcc -lm setitimer-helper.o -o setitimer-helper
setitimer-helper.o: In function `main':
setitimer-helper.c:(.text+0xc9): undefined reference to `floor'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'setitimer-helper' failed
make: *** [setitimer-helper] Error 1
If looked at first line of outputs of both make commands
gcc -Wall -W -c -o setitimer-helper.o setitimer-helper.c
and
gcc -lm setitimer-helper.o -o setitimer-helper
They are different.
Why make is executing different commands for the same Makefile? and What should I do to remove error?
In the first computer, the setitimer-helper.o file either doesn't exist or the setitimer-helper.c file is newer, so make needs to rebuild it. Thus it runs the compiler, then afterwards it performs the link operation:
gcc -Wall -W -c -o setitimer-helper.o setitimer-helper.c
gcc -lm setitimer-helper.o -o setitimer-helper
On the second computer, the setitimer-helper.o file already exists and is newer than the setitimer-helper.c file, so the compile command was not needed and the second computer proceeded directly to the link line:
gcc -lm setitimer-helper.o -o setitimer-helper
The real question is why you got the linker error on the second computer.
The answer to that is that the -lm flag needs to come on the linker line after the object files. This happens because you added -lm to the LDFLAGS variable which is not the right one: that should contain options that tell the linker where to look for files, etc. (for example, the -L option).
Libraries should be added to the LDLIBS variable, not LDFLAGS. Change your makefile to this:
all: setitimer-helper squish-pty squish-unix
CC = gcc
CFLAGS = -Wall -W
LDLIBS = -lm
setitimer-helper: setitimer-helper.o
squish-pty: squish-pty.o
squish-unix: squish-unix.o
clean:
rm -f *.o setitimer-helper squish-pty squish-unix
Your link line will then look like:
gcc setitimer-helper.o -o setitimer-helper -lm
and should work properly.

Telling ld where to look for dependent shared libraries during compilation

I'm trying to crosscompile some libraries for an ARM processor, specifically:
DirectFB, which depends on libpng, which depends on zlib.
Libpng is linked against zlib, but since the paths on the build system don't match the paths on the target system, ld can't find the zlib that libpng is linked against during the compilation of DirectFB.
I've reduced the issue to the following example:
testb depends on libb, which depends on liba.
Build liba:
gcc -Wall -fPIC -c a.c
gcc -shared -Wl,-soname,liba.so.1 -o liba.so.1.0 a.o
ln -fs liba.so.1.0 liba.so.1
ln -fs liba.so.1 liba.so
Built testa:
gcc -Wall -I. -L. testa.c -la -o testa
LD_LIBRARY_PATH=. ./testa
a: 0
Build libb:
gcc -Wall -fPIC -I. -L. -c b.c -la
gcc -shared -Wl,-soname,libb.so.1 -o libb.so.1.0 b.o
ln -fs libb.so.1.0 libb.so.1
ln -fs libb.so.1 libb.so
So far, so good. However, building testb fails:
gcc -Wall -I. -L. testb.c -lb -o testb
Results in:
./libb.so: undefined reference to `a'
collect2: ld returned 1 exit status
make: *** [testb] Error 1
So ld can't find the definition of a in liba, even though libb is linked against liba, and both are in the current directory, which is being passed with "-L."
Running gcc with -v results in:
gcc -v -Wall -I. -L. testb.c -lb -o testb
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.4.3-4ubuntu5.1' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --program-suffix=-4.4 --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i486 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1)
COLLECT_GCC_OPTIONS='-v' '-Wall' '-I.' '-L.' '-o' 'testb' '-mtune=generic' '-march=i486'
/usr/lib/gcc/i486-linux-gnu/4.4.3/cc1 -quiet -v -I. testb.c -D_FORTIFY_SOURCE=2 -quiet -dumpbase testb.c -mtune=generic -march=i486 -auxbase testb -Wall -version -fstack-protector -o /tmp/ccqAkMFb.s
GNU C (Ubuntu 4.4.3-4ubuntu5.1) version 4.4.3 (i486-linux-gnu)
compiled by GNU C version 4.4.3, GMP version 4.3.2, MPFR version 2.4.2-p1.
GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=128244
ignoring nonexistent directory "/usr/local/include/i486-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../i486-linux-gnu/include"
ignoring nonexistent directory "/usr/include/i486-linux-gnu"
#include "..." search starts here:
#include <...> search starts here:
.
/usr/local/include
/usr/lib/gcc/i486-linux-gnu/4.4.3/include
/usr/lib/gcc/i486-linux-gnu/4.4.3/include-fixed
/usr/include
End of search list.
GNU C (Ubuntu 4.4.3-4ubuntu5.1) version 4.4.3 (i486-linux-gnu)
compiled by GNU C version 4.4.3, GMP version 4.3.2, MPFR version 2.4.2-p1.
GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=128244
Compiler executable checksum: 2349e080d2b2f3f970047e63bbe98cb2
COLLECT_GCC_OPTIONS='-v' '-Wall' '-I.' '-L.' '-o' 'testb' '-mtune=generic' '-march=i486'
as -V -Qy -o /tmp/ccc6ux7S.o /tmp/ccqAkMFb.s
GNU assembler version 2.20.1 (i486-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.20.1-system.20100303
COMPILER_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../:/lib/:/usr/lib/:/usr/lib/i486-linux-gnu/
COLLECT_GCC_OPTIONS='-v' '-Wall' '-I.' '-L.' '-o' 'testb' '-mtune=generic' '-march=i486'
/usr/lib/gcc/i486-linux-gnu/4.4.3/collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o testb -z relro /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o -L. -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486-linux-gnu /tmp/ccc6ux7S.o -lb -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o
./libb.so: undefined reference to `a'
collect2: ld returned 1 exit status
make: *** [testb] Error 1
Setting LD_LIBRARY_PATH and/or LIBRARY_PATH to the current directory doesn't resolve the problem.
Compiling with -la works, but it shouldn't be necessary, since libb is linked against liba. For example, when linking against libpng in a native build environment (correct paths, library paths in ld.so.conf) doesn't require -lz.
Also, setting additional libs to link against is a pain, because I would have to patch the Makefiles for every compilation that depends on a lib that depends on another lib.
In summary, how do I tell ld where to look for dependent shared libraries during compilation?
My problem is similar to these two:
Cross-linking for ARM/QNX fails with indirect/transitive dependencies
How to resolve shared library linking during compilation( GCC )?
Neither suggests a solution which doesn't require the addition of -la, which in my opinion shouldn't be necessary.
Files used:
a.c:
int a() {
return 0;
}
liba.h:
#ifndef LIBA_H
#define LIBA_H
int a();
#endif
testa.c:
#include <stdio.h>
#include <liba.h>
int main() {
printf("a: %d\r\n", a());
return 0;
}
b.c:
#include <liba.h>
int b() {
return a();
}
libb.h:
#ifndef LIBB_H
#define LIBB_H
int b();
#endif
testb.c:
#include <stdio.h>
#include <libb.h>
int main() {
printf("b: %d\r\n", b());
return 0;
}
Makefile:
# Makefile for shared library test
all:
liba:
gcc -Wall -fPIC -c a.c
gcc -shared -Wl,-soname,liba.so.1 -o liba.so.1.0 a.o
ln -fs liba.so.1.0 liba.so.1
ln -fs liba.so.1 liba.so
testa: liba
gcc -Wall -I. -L. testa.c -la -o testa
runtesta: testa
LD_LIBRARY_PATH=. ./testa
libb: liba
gcc -Wall -fPIC -I. -L. -c b.c -la
gcc -shared -Wl,-soname,libb.so.1 -o libb.so.1.0 b.o
ln -fs libb.so.1.0 libb.so.1
ln -fs libb.so.1 libb.so
testb: libb
gcc -v -Wall -I. -L. testb.c -lb -o testb
runtestb: testb
LD_LIBRARY_PATH=. ./testb
clean:
# clean up
rm -rf *.o
rm -rf liba.s*
rm -rf libb.s*
rm -rf testa testb
You must add -la to linking phase of lb (second line below is essential):
$ gcc -Wall -fPIC -I. -L. -c b.c -la
$ gcc -L. -shared -o libb.so b.o -la
$ LD_LIBRARY_PATH=. gcc -Wall -I. -L. testb.c -lb -o testb
$ LD_LIBRARY_PATH=. ./testb
b: 0
Also -la on compilation isn't really required, I left it only because it was in your original example. Instead first line
$ gcc -Wall -fPIC -I. -L. -c b.c
will be enough.
Common rule is -- linker is guy, who need libraries, not compiler.

Boost static linking in unix

I am using the Boost library in Unix, GCC. I read the following topic: Boost static linking and added -static to my Makefile. However, this does not work.
Here is my Makefile:
all: nbbo
nbbo: nbbo.o reader.o
g++ -static -O3 -ffast-math -funroll-loops -ansi -pedantic-errors -L/usr/lib -lboost_filesystem -lboost_serialization -lboost_iostreams -lz -I /usr/include/boost -o nbbo nbbo.o reader.o
nbbo.o: nbbo.cpp
g++ -static -O3 -ffast-math -funroll-loops -ansi -pedantic-errors -I /usr/include/boost -c -o nbbo.o nbbo.cpp
reader.o: reader.cc reader.h
g++ -static -O3 -ffast-math -funroll-loops -ansi -pedantic-errors -I /usr/include/boost -c -o reader.o reader.cc
clean:
rm *.o
And here is the error message:
nbbo.o: In function `__tcf_10':
nbbo.cpp:(.text+0x3d9): undefined reference to `boost::serialization::extended_type_info::key_unregister() const'
nbbo.cpp:(.text+0x3e3): undefined reference to `boost::serialization::typeid_system::extended_type_info_typeid_0::type_unregister()'
nbbo.cpp:(.text+0x3fb): undefined reference to `boost::serialization::typeid_system::extended_type_info_typeid_0::~extended_type_info_typeid_0()'
etc
Which "UNIX" are you using? Using the -static flag should work fine on linux. But not on OSX. On OSX you have to remove the static flag and give the complete path to the library in order to link statically. I dont know how this would work on other "UNIXes"
eg.
g++ ..... /path/to/your/lib.a ... -o ..

Resources