Why compile statically?

This allows for ease of deployment, at the expense of a larger binary executable.

You don’t have to copy the libraries that you use manually to the target system

CMake link_libraries() Magic

I use CLion, which (currently) enforces the use of CMake in compiling C/C++ projects. In your CMakeLists.txt file, first make sure you link the directory to find your files:

link_directories("/usr/local/lib")

CMake has a magic link_libraries() function which takes in the library specified and determines how you want it to be compiled (statically or dynamically linked).

If you type

link_libraries(ev)

It is interpreted as a dynamic linked library.

link_libraries(libev.a)

Tells CMake to look for this static library file in the linked directories, and build it statically into your binary.

Order of Static Linking Matters

Doing

link_libraries(libPocoFoundation.a) link_libraries(libPocoXML.a)

I met this error.

/usr/local/lib/libPocoXML.a(XMLWriter.o): In function `Poco::XML::XMLWriter::XMLWriter(std::ostream&, int)':XMLWriter.cpp:(.text+0x28b3): undefined reference to `Poco::UTF8Encoding::UTF8Encoding()'XMLWriter.cpp:(.text+0x28cc): undefined reference to `Poco::UTF8Encoding::UTF8Encoding()' ......

It seems that the libPocoXML.a static library is trying to call functions in libPocoFoundation.a but can’t find them.

Reversing the order of linking the libraries helps.

link_libraries(libPocoXML.a) link_libraries(libPocoFoundation.a)

This is because when CMake links the libPocoXML.a library, it makes a note of the external functions that are called and looks for them to be linked in the subsequent libraries. One example here is the Poco::UTF8Encoding::UTF8Encoding() function.

What is happening here is that CMake links the libPocoXML.a, looks for the function in subsequent libraries that are linked and finds nothing. Reversing the order allows libPocoXML.a to find the desired function later on in libPocoFoundation.a.

This only happens for static library compilation due to how CMake interprets it.

Check your binary using ldd :

ldd DSPBox

linux-vdso.so.1 => (0x00007fff2eb46000) libippi.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libippi.so.9.0 (0x00007f4a209cd000) libipps.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libipps.so.9.0 (0x00007f4a2078c000) libippcore.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libippcore.so.9.0 (0x00007f4a20580000) libippvm.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libippvm.so.9.0 (0x00007f4a2036a000) libcufft.so.7.5 => /usr/local/cuda/lib64/libcufft.so.7.5 (0x00007f4a1972f000) libtiff.so.3 => /usr/local/lib/libtiff.so.3 (0x00007f4a194d3000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f4a19299000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f4a19094000) librt.so.1 => /lib64/librt.so.1 (0x00007f4a18e8c000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f4a18b84000) libm.so.6 => /lib64/libm.so.6 (0x00007f4a18881000) libgomp.so.1 => /lib64/libgomp.so.1 (0x00007f4a1866a000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f4a18454000) libc.so.6 => /lib64/libc.so.6 (0x00007f4a18091000) libjpeg.so.62 => /lib64/libjpeg.so.62 (0x00007f4a17e3c000) libz.so.1 => /lib64/libz.so.1 (0x00007f4a17c25000) /lib64/ld-linux-x86-64.so.2 (0x00007f4a20c53000)

Statically linking a file which has dynamic file dependencies.

This worked

link_libraries(tiff)

but not the static version.

link_libraries(libtiff.a)

/usr/local/lib/libtiff.a(tif_jpeg.o): In function `TIFFjpeg_destroy’:/home/pier/Software/Development/tiff-3.8.2/libtiff/tif_jpeg.c:377: undefined reference to `jpeg_destroy’/usr/local/lib/libtiff.a(tif_jpeg.o): In function `TIFFjpeg_write_raw_data’:/home/pier/Software/Development/tiff-3.8.2/libtiff/tif_jpeg.c:320: undefined reference to `jpeg_write_raw_data’/usr/local/lib/libtiff.a(tif_jpeg.o): In function `TIFFjpeg_finish_compress’:…..

If you dig in deeper, you are able to find the dependancies using readelf

cd /usr/local/

libreadelf -d libtiff.so | grep 'NEEDED'

0x0000000000000001 (NEEDED) Shared library:

[libjpeg.so.62] 0x0000000000000001 (NEEDED) Shared library:

[libz.so.1] 0x0000000000000001 (NEEDED) Shared library:

[libm.so.6] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]

So apparently we still need the above dynamic libraries even for libtiff.a. Fortunately these files come preinstalled in CentOS and most distributions.

So all you need to do now is :

link_libraries(libtiff.a jpeg z)

libc and libm are linked by default by gcc. CMake interprets this as : compile libtiff.a statically into the binary, but its dependancies libjpeg and libz are still dynamically linked. Get them dynamically from the linked system folders.

To be sure, check using ldd again:

ldd DSPBox

linux-vdso.so.1 => (0x00007ffdfc5ee000) libippi.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libippi.so.9.0 (0x00007fa41cf23000) libipps.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libipps.so.9.0 (0x00007fa41cce2000) libippcore.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libippcore.so.9.0 (0x00007fa41cad6000) libippvm.so.9.0 => /opt/intel/compilers_and_libraries_2016.0.109/linux/ipp/lib/intel64/libippvm.so.9.0 (0x00007fa41c8c0000) libcufft.so.7.5 => /usr/local/cuda/lib64/libcufft.so.7.5 (0x00007fa415c85000) libjpeg.so.62 => /lib64/libjpeg.so.62 (0x00007fa415a12000) libz.so.1 => /lib64/libz.so.1 (0x00007fa4157fc000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fa4155df000) libdl.so.2 => /lib64/libdl.so.2 (0x00007fa4153db000) librt.so.1 => /lib64/librt.so.1 (0x00007fa4151d3000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fa414eca000) libm.so.6 => /lib64/libm.so.6 (0x00007fa414bc8000) libc.so.6 => /lib64/libc.so.6 (0x00007fa414806000) libgomp.so.1 => /lib64/libgomp.so.1 (0x00007fa4145ee000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fa4143d8000) /lib64/ld-linux-x86-64.so.2 (0x00007fa41d1a9000)

No more dynamic library requirement for libtiff!