Static vs Dynamic Linking in C – Understanding the Differences

cdeploymentdynamic-linkinglinkingstatic-linking

I've been bitten for the n-th time now by a library mismatch between a build and deployment environment. The build environment had libruby.so.2.0 and the deployment environment had libruby.a. One ruby was built with RVM, the other was built with ruby-build. The reason I ran into a problem was because zookeeper was compiled in a build environment that had the shared library but the deployment environment only had the static library.

In all the years I've been writing application code I have never once wished that the binaries I was using where linked against shared objects. What is the reason the dichotomy persists to this day on modern operating systems?

Best Answer

Static

With a statically linked application, everything that you need to run the application is part of the application itself. It depends on nothing else.

If there is a fatal error in a dynamically linked library, it doesn't 'care'.

If the dynamically linked version of a library it uses isn't there (someone accidentally removed /lib on a unix system?) it doesn't care.

It requires no additional installs of libraries to run on any binary compatible platform. You download the app and you can run it.

There is an entire directory of statically linked applications on every unix system in /sbin that are guaranteed to always work even if significant parts of the system are otherwise broken or missing. reboot? halt? ifconfig? mount? fsck? ping? Those are likely all in /sbin so that even if the libraries are missing or corrupt (or not mounted because they're on a network filesystem...) you can still run those commands to get the system working (and mount that networked file system with the libraries you are looking for).

True story: One sysadmin many years ago, back when an 80 megabyte hard disk was big was looking for some space. Standard compiles included debugging/symbol information and that took a few kilobytes in each binary. So, he found every executable on the system and ran strip on it. Did you know that shared libraries are 'executables' on many systems? Removing the symbol information from them prevents anything from dynamically linking to them... oops. The only things working where those in /sbin. Fortunately, there was enough there that he was able to mount the other system of the same type and copy the shared libraries back over to the messed up system...

Dynamic

You want to update a library? No problem. Just put the library in the proper spot and all is well. Yea, that's a bit simplistic, but its the idea.

$ ldd /bin/date
  linux-vdso.so.1 =>  (0x00007fff6ffff000)
  librt.so.1 => /lib64/librt.so.1 (0x00007f54ba710000)
  libc.so.6 => /lib64/libc.so.6 (0x00007f54ba384000)
  libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f54ba167000)
  /lib64/ld-linux-x86-64.so.2 (0x00007f54ba919000)

Those are all libraries that are already loaded somewhere that you don't have to have in your application. There can be some savings in disk space size because you don't need to put a full copy of libc or any other library as part of your application.

System patching becomes easier. Instead of needing to push out a patch for everything in /bin because something changed (you need to do this for /sbin), you just push out a new shared library object and update the symbolic link chain in /lib.

Drop in replacements become possible. Just provide the same API and symbols, drop in the new library and update the symbolic link chain and all should be good.

On a system that runs multiple processes (almost all of them these days... but it was a significant distinction back in old times) static libraries meant that each application running had a full copy of its libraries taking up memory resources. Shared libraries means that they can all just point to the same spot in already loaded memory.

Statically linking an application can be considered a derivative work of the libraries. This becomes an issue with GPL software. There are differing opinions on if dynamically linking a GPL licensed library creates a derivative work.

Dynamic linking allows for plugins. The application loads the plugins and dynamically calls the functions available to it.

Multiple languages can use the same calling conventions and call a dynamic library. Look at Java for an example there - dynamic linking means that Clojure, Scala, Groovy, etc... with dynamic linking they can all use the same shared libraries. Alternatively look at all the different languages that can invoke a .DLL on windows.

Related reading: