For Linux and I believe Mac OS X, if you're using gcc, or any compiler that uses glibc, you can use the backtrace() functions in execinfo.h
to print a stacktrace and exit gracefully when you get a segmentation fault. Documentation can be found in the libc manual.
Here's an example program that installs a SIGSEGV
handler and prints a stacktrace to stderr
when it segfaults. The baz()
function here causes the segfault that triggers the handler:
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int sig) {
void *array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 10);
// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
void baz() {
int *foo = (int*)-1; // make a bad pointer
printf("%d\n", *foo); // causes segfault
}
void bar() { baz(); }
void foo() { bar(); }
int main(int argc, char **argv) {
signal(SIGSEGV, handler); // install our handler
foo(); // this will call foo, bar, and baz. baz segfaults.
}
Compiling with -g -rdynamic
gets you symbol info in your output, which glibc can use to make a nice stacktrace:
$ gcc -g -rdynamic ./test.c -o test
Executing this gets you this output:
$ ./test
Error: signal 11:
./test(handler+0x19)[0x400911]
/lib64/tls/libc.so.6[0x3a9b92e380]
./test(baz+0x14)[0x400962]
./test(bar+0xe)[0x400983]
./test(foo+0xe)[0x400993]
./test(main+0x28)[0x4009bd]
/lib64/tls/libc.so.6(__libc_start_main+0xdb)[0x3a9b91c4bb]
./test[0x40086a]
This shows the load module, offset, and function that each frame in the stack came from. Here you can see the signal handler on top of the stack, and the libc functions before main
in addition to main
, foo
, bar
, and baz
.
Statically linking against any system library, and especially against libc
, on modern UNIX or Linux systems makes the binary significantly less portable. Just don't do it.
Instead, use backward compatibility (binaries linked on an older system continue to run on all newer ones) to your advantage, either by linking your binary on an old system (I use RedHat 6.2, and I have not seen a Linux system where my binary will not run in the last 8 years), or by using something like autopackage (which has been deleted after this answer was written).
To answer your original question:
gcc main.o -Wl,-Bstatic -lfoo -Wl,-Bdynamic
will cause linker to use archive version of libfoo. [It is important to have the trailing -Wl,-Bdynamic
precisely so you don't force static libc.]
Best Answer
gcc -lsome_dynamic_lib code.c some_static_lib.a