Static linking

From Linuxintro

Example

Let's say you want a library that defines a function help() that outputs "hello world". First create help.cpp

cat >help.cpp
#include <iostream>

extern "C" void help() 
{
  std::cout << "hello world" << '\n';
}

Then create main.cpp which will be the program calling the function help():

cat >main.cpp
#include <iostream>
#include <dlfcn.h> 

extern "C" void help(); 

int main() 
{
  help();
  return 0;
}

Now compile help.cpp, but do not make it an executable. An attempt to make it an executable will fail because it does not contain a main routine.

# gcc -c help.cpp

Verify your library help.o has been created:

# ls -ltr
total 12
-rw-r--r-- 1 root root   87 Dec 31 11:32 help.cpp
-rw-r--r-- 1 root root  105 Dec 31 11:57 main.cpp
-rw-r--r-- 1 root root 2712 Dec 31 11:57 help.o

Create an archive out of help.o. In a real case you would use more than one .o file:

# ar -r help.a help.o
# ls -ltr
total 16
-rw-r--r-- 1 root root   87 Dec 31 11:32 help.cpp
-rw-r--r-- 1 root root  105 Dec 31 11:57 main.cpp
-rw-r--r-- 1 root root 2712 Dec 31 11:57 help.o
-rw-r--r-- 1 root root 2854 Dec 31 12:00 help.a

Verify main.cpp has an unresolved dependency to a function help:

# g++ main.cpp 
/tmp/ccvIeJnW.o: In function `main':
main.cpp:(.text+0x5): undefined reference to `help'
collect2: ld returned 1 exit status

Put the archive in a place so gcc can find it:

# cp help.a /usr/lib/libhelp.a

Compile and link your program:

# g++ -o myprogram main.cpp -lhelp

Test it:

# ./myprogram 
hello world

Verify it does NOT have a dependency on help.so or help.o:

# ldd myprogram 
        linux-vdso.so.1 =>  (0x00007fff34dff000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f784ce16000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f784cbbf000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f784c9a9000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f784c649000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f784d120000)
# 

Verify it really contains code to output hello world in the executable file:

# strings myprogram 
/lib64/ld-linux-x86-64.so.2
SuSESuSE
libstdc++.so.6
__gmon_start__
_Jv_RegisterClasses
_ZNSt8ios_base4InitD1Ev
_ZSt4cout
_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c
_ZNSt8ios_base4InitC1Ev
libm.so.6
libgcc_s.so.1
libc.so.6
__cxa_atexit
__libc_start_main
GLIBC_2.2.5
GLIBCXX_3.4
%z       
%r       
%j       
%b       
%Z       
fff.
l$ L
t$(L
|$0H
hello world

Look at its size so you can compare it with the same example that has been linked dynamically:

# ll myprogram 
-rwxr-xr-x 1 root root 12541 Dec 31 12:03 myprogram

You see it has a size of 12 541 bytes while the executable file that has been linked dynamically has a size of 12 173 bytes.

See also