2 Different LD errors when trying to link static library - c++

I wrote a custom C++ library, which compiled correctly, and am trying to write a test program for some different accuracy checks.
When I compile it this way:
$ c++ -I./include/ -L./lib -lname test.cpp -c -o test.o
....[succeeds ]
$ c++ -I./include/ -L./lib -lname test.o -o test
I get:
ld: 1 duplicate symbol for... for the function I'm testing
But when I compile the test.o the same way & change the executable method:
c++ -I./include -L./lib test.o -o test
it returns: `ld: symbols() not found for ..." for the function I'm testing.
I am 100% sure about the way I compiled & built the library, so I don't understand exactly what I am doing wrong even after I've tried several different ways of compiling test.
Edits:
Fixed typo in test filename.
Removed -L & -l flags from step 1, and it compiled.
Removed -I from step 2, and it gave the error ld: library for -lname not found when compiled as:
c++ -L./lib -lname test.obj -o test

Related

C++ file compiling: -L and -I arguments don't work for boost library

There are similar questions but their answers did not work for my issue.
I have a c++ program with #include <boost/test/unit_test.hpp> on top (among other includes).
To compile correctly, if I understood, I should do the command:
g++ -g -L/path_to_boost_lib -lboost_lib myprog.cpp -o myprog.exe
If i do a locate, I get /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.
Hence I edited my call to g++ by doing:
g++ -g -L/usr/lib/x86_64-linux-gnu -lboost_unit_test_framework myprog.cpp -o myprog.exe
But I still get errors of the type undefined reference to boost::unit_test.
I also tried the option -I/usr/include/ which contains the boost folder, without success.
It's because of the order. The GCC linker goes through the artifacts left-to-right, and every unknown symbol it encounters in an object file must be resolved by an artifact occurring afterwards.
The right command is thus:
g++ -g myprog.cpp -L/usr/lib/x86_64-linux-gnu -lboost_unit_test_framework -o myprog.exe
See this answer for a more thorough explanation.
I suggest using a build tool like CMake that takes care of such low-level details for you.

How to generate shared library(.so) file for a C++ program that contains protobuf library

So I have a C++ file named admv2_api.cc (and admv2_api.h of course). Inside it I #include a lot of generated code from protobuf. Those generated codes are related to some message and gRPC service definitions. I defined some APIs (like .runServer()) in admv2_api.cc so that people who don't know the details of gRPC can still use it to set up server and send messages, etc.
Now I want to generate a .so file for admv2_api.cc so that people can just link their programs against this .so file and use the APIs I defined in admv2_api.cc. Any insights on how to do this?
A complete tree of the files I have is here:
admv2_api.cc
-- #includes transport.grpc.pb.cc(generated file, contains definition of message and service)
-- #includes UX.grpc.pb.cc(generated file, contains definition of message)
One try I had done:
Generate .so file like this:
admv2_api.so: $(OBJS_GRPCS) $(OBJS_CCS) admv2_api.o
g++ -std=c++11 $^ $(LDFLAGS) -fPIC -shared -o $#
%.o: %.cc
g++ -std=c++11 $< -c -fPIC -o $#
Where $(OBJS_GRPCS) is just transport.grpc.pb.o UX.grpc.pb.o and $(OBJS_CCS) is transport.pb.o UX.pb.o. $(LDFLAGS) is flags related to grpc/protobuf, which is -L/usr/local/lib 'pkg-config --libs grpc++' -lgrpc++_reflection -lprotobuf -lpthread
And then I rename admv2_api.so to libadmv2_api.so and put it into /usr/lib.
Then I wrote a simple test program named main.cc. Compile it:
g++ -std=c++11 main.cc -I /path/to/admv2_api.h/ -ladmv2_api -L/usr/local/lib `pkg-config --libs grpc++` -lgrpc++_reflection -lprotobuf -lpthread -ldl -o main
It compiled without error. However, when I ran ./main, it has the following error:
dyld: Library not loaded: admv2_api.so
Referenced from: /Users/some/path/so-test/main/./main
Reason: image not found
Abort trap: 6
Any help is highly appreciated!
After some tries it seems to me that this error
dyld: Library not loaded: admv2_api.so
Referenced from: /Users/some/path/so-test/main/./main
Reason: image not found
Abort trap: 6
is a Mac OS issue. I tested the same code on a linux server and it worked just fine.

Order of libraries in static and dynamic linking

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?
With static linking, you have to also statically link to any libraries depended on by the libraries you are linking to.
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()
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.

Can compile in Ubuntu but not in Mac OS X

I built a dynamic library (.so file) on Ubuntu 12.04. Let's call it test.so. I had a test.cpp file, which calls some library functions. I first compiled test.cpp into test.o by:
g++ test.cpp -o -c test.o
It succeeded. Then I compiled test.o into test.so by:
g++ -shared test.o -o test.so
Also succeeded.
I did the similar thing but on Mac OS X.
I first got test.o by:
g++ test.cpp -o -c test.o
Then
g++ -dynamiclib test.o -o test.dylib
This failed, because I didn't provide the libraries that are used in test.cpp. I modified it:
g++ -dynamiclib test.o -o test.dylib -L/path/to/libraries -lLibraryName
Then it works.
Notice that for the first case, I didn't provide such a path to the libraries and the specific library used in test.cpp. Does someone know why I don't need to in the first case but need to in the second case?
The linker, with default options, does not behave the same on Linux and OSX. To get OSX linking to behave more like what you expect on linux, use the following link flag.
-Wl,-undefined,dynamic_lookup

Why my makefile fails, when I replace g++ with gcc?

I am coding in OS X
Here is my Makefile:
#makefile for stack_5_1
# Yitong Zhou
stack_5 : main.o Stack.o LIFO_Stack.o Peekback_Stack.o
g++ -o stack_5 main.o Stack.o LIFO_Stack.o Peekback_Stack.o
main.o: main.cpp Stack.h LIFO_Stack.h Peekback_Stack.h
g++ -c main.cpp
Stack.o: Stack.cpp Stack.h
g++ -c Stack.cpp
LIFO_Stack.o: LIFO_Stack.cpp LIFO_Stack.h
g++ -c LIFO_Stack.cpp
Peekback_Stack.o: Peekback_Stack.cpp Peekback_Stack.h
g++ -c Peekback_Stack.cpp
clean:
rm -rf *.o stack_5
The error:
..... // very very long
Dwarf Exception Unwind Info (__eh_frame) in Stack.o
Dwarf Exception Unwind Info (__eh_frame) in LIFO_Stack.o
Dwarf Exception Unwind Info (__eh_frame) in Peekback_Stack.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [stack_5] Error 1
What is the difference between gcc and g++? Why does my compile fail when I replace g++ with gcc?
By the way, how could I ensure that my makefile could be run correctly in Cygwin, linux, OS X and maybe other environment.
gcc is for compiling C by default
g++ is for compiling C++ by default
The primary difference is that g++ transparently adds the options -x c++ (use C++) and -lstdc++ (use C++ standard library).
Try this Makefile:
stack_5: main.o Stack.o LIFO_Stack.o Peekback_Stack.o
main.o: main.cpp Stack.h LIFO_Stack.h Peekback_Stack.h
Stack.o: Stack.cpp Stack.h
LIFO_Stack.o: LIFO_Stack.cpp LIFO_Stack.h
Peekback_Stack.o: Peekback_Stack.cpp Peekback_Stack.h
make will automatically fill in the sensible rules based on the file extensions.
Also take a look at the -MM gcc option. It will automatically generate the correct make dependencies (which header files) so you don't need to maintain this list manually. There is more in the make manual and gcc manual about how to use it.
gcc as a linker, IIRC, doesn't link in standard c++ libraries, like -lstdc++. Not sure if it's enough to make sure everything works on all systems, you may need to use autotools or similar.
gcc is meant to compile plain C while g++ accepts (compatible) C and C++ code.
That's probably the reason for your errors.