0

I'm trying to build some example c++ code that use boost library. I use this as reference example of static linking.

And everything is fine when I build with dynamic libs.

g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/main.o src/main.cpp g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/ThreadExample.o src/ThreadExample.cpp g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/Utils.o src/Utils.cpp g++ src/main.o src/ThreadExample.o src/Utils.o -lboost_thread -lboost_filesystem -lboost_system -lboost_timer -o ThreadExampleBinary 

But when I use static libs I get lots of undefined reference errors:

g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/main.o src/main.cpp g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/ThreadExample.o src/ThreadExample.cpp g++ -Wall -std=c++0x -O3 -Wfatal-errors -I/usr/include/boost/include -c -o src/Utils.o src/Utils.cpp g++ -static src/main.o src/ThreadExample.o src/Utils.o -lboost_thread -lboost_filesystem -lboost_system -lboost_timer -o ThreadExampleBinary /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::start()': (.text+0x7fd): undefined reference to `boost::chrono::steady_clock::now()' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::stop()': (.text+0x94c): undefined reference to `boost::chrono::steady_clock::now()' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::elapsed() const': (.text+0xa59): undefined reference to `boost::chrono::steady_clock::now()' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::cpu_timer::resume()': (.text+0xb60): undefined reference to `boost::chrono::steady_clock::now()' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o): In function `boost::timer::auto_cpu_timer::auto_cpu_timer(std::ostream&, short)': (.text+0xca5): undefined reference to `boost::chrono::steady_clock::now()' /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libboost_timer.a(cpu_timer.o):(.text+0xd4e): more undefined references to `boost::chrono::steady_clock::now()' follow collect2: error: ld returned 1 exit status make: *** [ThreadExampleBinary] Error 1 

Seems this can be fixed adding additional -lboost_chrono library. But why it works in dinamic setting?

3 Answers 3

3

With static linking, you have to also statically link to any libraries depended on by the libraries you are linking to.

Sign up to request clarification or add additional context in comments.

3 Comments

How to automate this process? It's not obvious how to find static lib that needed by inspecting the error, for example: /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libopencv_core.a(gl_core_3_1.cpp.o): In function IntGetProcAddress(char const*)': (.text._ZL17IntGetProcAddressPKc+0x15): undefined reference to glXGetProcAddressARB'
Correct answer, but I think it could be improved with a bit more details on library dependency chains.
@mrgloom, there is no universal automation. You either repeat the process until it succeedes (adding more libraries, or use libtool to link your files - it depends on .la files present, and I am not sure if boost provides them.
2

The difference is that shared libraries have an entry in the ELF header, called NEEDED that lists other shared libraries that are to be included when you link in this one.

You can see them with this command:

$ objdump -p /usr/lib/libboost_timer.so | grep NEEDED NEEDED libboost_chrono.so.1.60.0 NEEDED libboost_system.so.1.60.0 NEEDED librt.so.1 NEEDED libstdc++.so.6 NEEDED libgcc_s.so.1 NEEDED libc.so.6 

But for static libraries there is no such system, as they are simply collection of object files.

It is worth noting that the NEEDED entry in the shared objects are entirely optional, and if they are not available, then they will behave exactly like the static ones. But most shared libraries include them.

Many libraries use the pkg-config infrastructure to provide the full command line needed, but AFAIK boost is not one of them.

How to automate this process? Well, you do not. You just include what is needed and follow the linker errors to discover further needs.

You can find which static library includes a symbol with something like:

$ nm --print-file-name --defined-only --demangle /usr/lib/*.a 2> /dev/null | \ grep -q 'boost::chrono::steady_clock::now()' /usr/lib/libboost_chrono.a:chrono.o:0000000000000090 T boost::chrono::steady_clock::now() 

Comments

0

But why it works in dinamic setting?

Most of my make files have the following notes (from when I found the answer back when I needed it ... sorry, I don't know where I found it.)


Note - when a build using '-l' finds the .so version of that library (so - shared object) and the same .a archive is also there, g++ prefers the .so over the .a.


However, you can still achieve static link by fully specifying the path to .a.

Example:

$(CC) $(CC_FLAGS) $< /usr/local/lib/libboost_chrono.a -o $@ ... # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Sometimes, archive code refers to symbols in yet another archive.

i.e. -lyyy_i686 uses some function from -lxxx_i686, and xxx was listed first in the build command. It is possible that a symbol might remain unresolved and the linker fails.

When this happens, try adding xxx a second time to the end of the archive list

 from: -lxxx_i686 -lyyy_i686 -lrt -pthread becomes -lxxx_i686 -lyyy_i686 -lrt -pthread -lxxx_i686 ^^^^^^^^^_____________________________^^^^^^^^^^ 

The preceeding presumes only .a libraries are findable (no xxx.so)


Another alternative, you can command the linker to search an archive multiple times

 -lyyy_i686 -lrt -pthread -(-lxxx_i686-) tell gcc to link this library as many times as needed __^^__________^^ 

Again, only .a is findable


Finally, if you choose to link with the .so, note that this does not pull in the entire lib into the current build target. Instead, at runtime, the .so is loaded into memory, if it is not already there. This happens after the program starts. For most applications, this is considered a 'small' start-up performance hit as the program adjusts its memory map (automagically behind the scenes). I believe I once found that the app itself can control when to load the .so.


The use of .so pulls in the entire library to memory (if not already installed). Thus, there would not be any missing symbols, in my xxx vs yyy scenario above, the .so pulls all the symbols, whether used or not.

And once again, when trying to load xxx using "-lxxx_i686", the linker prefers to pull in libxxx_i686.so even when the libxxx_i686.a is in the same directory.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.