g++ linking static and non-static libraries at the same time - c++

I have a makefile project in which I include a few different libraries. One of them is the boost library which I statically link in order to make my program portable. This is how my makefile command looks like:
g++ -O0 -g test.cpp testObject.o -pthread -I/home/user/devel/lmx-sdk-4.7.1/include/ -L/home/user/devel/lmx-sdk-4.7.1/linux_x64 -llmxclient -lrt -ldl -lboost_filesystem -lboost_system -static -static-libgcc -o $#
I have also linked lmx-sdk library to my project in order to use the licensing functionality; however, it seems to be that lmx-sdk doesn't seem to like static link as it gives an error "Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking".
How can I make it possible to link some libraries statically and the other ones dynamically ?
Thanks in advance
P.S. I have checked some of similar topics and tried a few methods which didn't work out for me.

Using -Wl,-Bdynamic and -Wl,-Bstatic instead of just using -Bdynamic and -Bstatic solved the problem.
The full link line looks like this now:
g++ -O0 -g test.cpp testObject.o -pthread -Bdynamic -I/home/user/devel/lmx-sdk-4.7.1/include/ -L/home/user/devel/lmx-sdk-4.7.1/linux_x64 -llmxclient -lrt -ldl -Wl,-Bstatic -lboost_filesystem -lboost_system -o $#

You can use -Bstatic to statically link what comes after it, then -Bdynamic to do the opposite. As many times as you need on the command line.

Related

Why would I need to list -ldl before a library that calls dlopen/dlclose/dlerror when linking

I am building an executable (foo.exe let's call it) on RHEL with gcc 6.2. It links against a few third-party libraries, libzzdesign.so, libyydesign.so. Yydesign uses dlopen/dlclose/dlerror. I would expect this command-line to work:
g++ -Wall -fcheck-new -fno-strict-aliasing -msse2 -fno-omit-frame-pointer -pthread -O3 -Wl,--export-dynamic -o foo.exe foo.o -L/path/to/zzdesign -Wl,-rpath=/path/to/zzdesign -lzzdesign -L/path/to/yydesign -Wl,-rpath=/path/to/yydesign -lyydesign -ldl
(I'm listing all the options used in case it matters)
It produces the errors,
/path/to/yydesign/libyydesign.so: undefined reference to 'dlclose'
/path/to/yydesign/libyydesign.so: undefined reference to 'dlerror'
If I change the command line to put -ldl before -lyydesign:
g++ -Wall -fcheck-new -fno-strict-aliasing -msse2 -fno-omit-frame-pointer -pthread -O3 -Wl,--export-dynamic -o foo.exe foo.o -L/path/to/zzdesign -Wl,-rpath=/path/to/zzdesign -lzzdesign -L/path/to/yydesign -Wl,-rpath=/path/to/yydesign -ldl -lyydesign
... it works without error.
This is the opposite of everything I thought I knew about order of libraries on the command line when linking.
Why does -ldl have to come before -lyydesign?
Other than dumb luck to stumble across this solution, how could I troubleshoot the original error to understand what's going on?
And since changing the build system to move -ldl first in all the places it's needed is kind of a pain, is there a way I can avoid having to put -ldl first?
Order of libs for LD does matter. Lib yydesign use dlclose and dlerror that's why lib dl need to be passed before yydesign.

Failure to link v8 in a native Dart extension

I am trying to use v8 in a Dart native extension.
The v8 getting started guide says to compile the hello world example like this.
g++ -I. -Iinclude samples/hello-world.cc -o hello-world -Wl,--start-group \
out.gn/x64.release/obj/{libv8_{base,libbase,external_snapshot,libplatform,libsampler},\
third_party/icu/libicu{uc,i18n},src/inspector/libinspector}.a \
-Wl,--end-group -lrt -ldl -pthread -std=c++0x
Dart says to compile native extensions like so:
g++ -fPIC -I{path to SDK include directory} -DDART_SHARED_LIB -c sample_extension.cc
gcc -shared -m32 -Wl,-soname,libsample_extension.so -o libsample_extension.so sample_extension.o
This is the hybrid I came up with
g++ -fPIC -I{path to SDK include directory} -Iinclude -DDART_SHARED_LIB -c sample_extension.cc -std=c++0x
gcc -shared -Wl,-soname,libsample_extension.so -Wl,--start-group out.gn/x64.release/obj/{libv8_{base,libbase,external_snapshot,libplatform,libsampler},third_party/icu/libicu{uc,i18n},src/inspector/libinspector}.a -Wl,--end-group -o libsample_extension.so sample_extension.o -lrt -ldl -pthread -std=c++0x
However, while trying to run my application, I get an error stating that v8 is not linked properly.
dart: symbol lookup error: /mnt/c/Users/zvacu/Documents/Code/Dart/require/libsample_extension.so: undefined symbol: _ZN2v82V828InitializeICUDefaultLocationEPKcS2_
I can manage to link it properly when using the hello world example provided.
Doing a little research it seems like the problem it is on the -shared property on the second command. You need to pay attention with C++ and shared libraries, so check if your library get's all its dependencies by:
ldd /mnt/c/Users/zvacu/Documents/Code/Dart/require/libsample_extension.so
After this you will get a list of all dependencies, then you will need to search if there is anyone missing.
If this does not answer your question, see this related answer:
Undefined symbol when loading a shared library

How do I statically compile boost_iostreams?

I'm new to creating Makefiles. I can successfully compile my program when using dynamic linking, but I get "undefined reference to" errors when trying to compile statically.
CC=g++
CXXFLAGS= -g -Wall -Wextra
#LDFLAGS= -g -l boost_iostreams #this works for dynamic linking
LDFLAGS= -Wl,-Bstatic -lboost_iostreams -Wl,-Bdynamic
default: zoneParserTester
zoneParser:
$(CC) $(CXXFLAGS) $(LDFLAGS) $#.cpp
zoneParserTester: zoneParser.o
$(CC) $(CXXFLAGS) $(LDFLAGS) zoneParser.o -o $# $#.cpp
gzExample:
$(CC) $(CXXFLAGS) $(LDFLAGS) -o $# $#.cpp
After searching online it seemed that the correct arguments to use are: "-Wl,-Bstatic -lboost_iostreams -Wl,-Bdynamic". Can anyone show me what I am doing wrong?
You are missing an important distinction between static and dynamic linking. Dynamically linking your applications A to a library B will pull in all dependencies of library B at runtime without you needing to specify them explicitly. When statically linking your application you also need to include all dependencies of library B (and the dependencies of the dependencies, and so on) at link-time in the same order as the dependency chain (so if application A depends on library B, and library B depends on library C, you must specify the libraries in that order; this is also true for .o files).
To figure out the whole dependency chain (and it's order) of a specific library can be a bit of a hassle. Sometimes the error messages during linking can give you some hints. If that doesn't help, there are several other ways:
Make an informed guess: one way to guess what libboost_iostreams depends on is by looking at what the dynamic version of the library depends on. You can do this with the ldd tool:
$ ldd /usr/lib/libboost_iostreams.so.1.46.1
On my computer it depends on libz and libbz2. So I'm pretty sure that your application will link if you just add
-lbz2 -lz
To the line where you link your application. I'm not sure if the -Wl,-Bstatic is necessary. For me, just specifying -static is sufficient:
$ gcc -static -o test test.cpp -lboost_iostreams -lbz2 -lz
Use pkg-config: most packages (unfortunately not boost) will install pkg-config files which keeps track of exactly how you must link your program to use a specific library. For example, say you would like to statically link to libcairo:
$ pkg-config --static --libs cairo
-pthread -lcairo -lgobject-2.0 -lffi -lpixman-1 -lfontconfig -lexpat -lfreetype -lpng12 -lz -lm -lxcb-shm -lxcb-render -lXrender -lglib-2.0 -lrt -lpcre -lX11 -lpthread -lxcb -lXau -lXdmcp
Use .la files and libtool: this is a somewhat deprecated method and increasingly not used anymore so the availability of .la files will depend on your distribution. libtool is yet another tool to get around this problem. When linking, instead of using g++ directly, you use a wrapper called libtool:
$ libtool --mode=link gcc -static -o my_app -lboost_iostreams
libtool will try to add the necessary libs and pass them automatically to gcc. It does this by searching for a file with the same name as the library (in your case libboost_iostreams), but with the suffix .la (instead of .a). If you open the .la file in a text editor you will see that it lists the dependencies of libboost_iostreams. I personally don't like libtool, it's a bit tricky to setup and is increasingly not used anymore. I'd probably just look at the .la file and add the dependencies manually.

Link error with my own C++ library

This is my first time trying to make a simple library. I worked in Ubuntu 12.04 with g++ 4.6.3. Here is the problem:
[[mylib.cpp]]
#include<sqlite3.h>
void Mylib::blahblah() {...}
void Mylib::evenmoreblah() {...}
...
[[mylib.h]]
#include <...>
class Mylib {
...
};
Then I made the lib by:
gcc -c -Wall -fpic mylib.cpp
gcc -shared -o libmylib.so mylib.o
I used the library in a single test.cpp which contains only the main(). I put libmylib.so in ./libdir, and compiled by using:
g++ -g test.cpp -o test -lpthread -L/usr/local/lib -lsqlite3 -L./libdir -lmylib
The error I got:
./libdir/libmylib.so: undefined reference to `sqlite3_close'
./libdir/libmylib.so: undefined reference to `sqlite3_exec'
./libdir/libmylib.so: undefined reference to `sqlite3_free'
./libdir/libmylib.so: undefined reference to `sqlite3_open'
You could link -lsqlite3 into your shared library with
gcc -shared mylib.o -o libmylib.so -lsqlite3
If you do that, you don't need to explicitly link -lsqlite3 to your program, but that won't harm.
and the order of linking arguments for your program is important:
g++ -Wall -g test.cpp -o mytest \
-L./libdir -lmylib -L/usr/local/lib -lsqlite3 -lpthread
it should go from higher-level libraries to lower-level (i.e. system) ones. And don't forget -Wall to get almost all warnings from the compiler, which is very useful.
Read the Program Library HowTo.
PS. Don't call your program test which is a shell builtin (and the standard /usr/bin/test). Use some other name.
If your library make references to sqlite3, you should link sqlite after linking your library :
g++ -g test.cpp -o test -lpthread -L/usr/local/lib -L./libdir -lmylib -lsqlite3
Otherwise ld won't find anything useful in libsqlite3 before linking your library and won't be able to find the requested symbols after that.
Since your library uses sqlite3, you need to add that AFTER your own library in the linker command. I think you could add it to the linking of your shared library too, but not certain.
The linker resolves libraries and their references in the order you list them, so the order is important.

Add .so and .a libraries to Makefile

I have a makefile which looks like this .
DEFINES=-std=c++0x
INCS_GTK=-I/usr/include/gtk-2.0 -I/usr/include/glib-2.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/gtk-2.0/gdk -I/usr/include/pango-1.0 -I/usr/lib/gtk-2.0/include -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include
INCS=-I/usr/include/freetype2 -I/usr/include/mysql -Iframeworks ${INCS_GTK}
LDLIBS=-lconfig++ -lcxcore -lcv -lGL -lGLU -lglut -lhighgui -lSDL -lftgl -lueye_api -lboost_filesystem -lboost_system -lann -lpthread -lflycapture -lglog -lmysqlpp -lmysqlclient -lunittest++
DEBUG=-g -pg
WARNINGS=-Wall -Wextra -pedantic -Wno-long-long #-O3 -Weffc++
BUILDDIR=build
BINDIR=dist
MAINCXX=${shell find -name '*.cxx'}
TARGETS=${MAINCXX:%.cxx=%}
CXXFLAGS=${DEBUG} ${WARNINGS} ${DEFINES} ${INCS}
LDFLAGS=${DEBUG} ${WARNINGS} ${DEFINES}
include IDEconfigs/Makefile/generic.mk
I want to add the following paths of static libraries to the makefile .
/usr/local/lib/libYARP_OS.a /usr/local/lib/libYARP_sig.a /usr/local/lib/libYARP_math.a /usr/local/lib/libYARP_dev.a /usr/local/lib/libYARP_name.a /usr/local/lib/libYARP_init.a
how do i go about doing this .
Lets consider your /usr/local/lib/libYARP_OS.a.
What you can do is, have -L/usr/local/lib/ in your makefile as one of the variables. And then you can have -lYARP_OS appended to the LDLIBS.
-L is for path to the lib and -l is the lib name here libYARP_OS.a will be passed as -lYARP_OS.
On the command line you would do something like: gcc -o main main.c -L/usr/local/lib/ -lYARP_OS. This should give you an idea.
You can either use an -L<path> flag to tell GCC about the location of any library, and then include it with -l<libname>. For example this would be
$ gcc -o main main.c -L/usr/local/lib/ -lYARP_SO
as noted by swair.
Alternatively, you can also supply the full path of the static library and compile directly, like
$ gcc -o main main.c /usr/local/lib/libYARP_OS.a
See 'Shared libraries and static libraries' for details.
In your specific case I would add them to the LDLIBS= line.
NB: Be careful about linking order, this is relevant when linking programs together. See 'Link order of libraries' for details. For example:
$ gcc -Wall calc.c -lm -o calc (correct order)
works
$ cc -Wall -lm calc.c -o calc (incorrect order)
main.o: In function `main':
main.o(.text+0xf): undefined reference to `sqrt'
Also see this similar question: How to link to a static library in C?
Append -lYARP_OS -lYARP_sig -lYARP_math -lYARP_dev -lYARP_name -lYARP_init to LDLIBS.
Warning: the linking order may matter.
Also, be sure that the linker knows that /usr/local/lib is a place where to look for libraries, otherwise instruct it with -L/usr/local/lib (you could add another makefile variable, e.g. LIBPATHS or something similar, to contain the libraries paths).
As a general synopsis, if you have a library libMyLib.a in folder /my/path, the gcc (or g++) can be invoked with the following parameters:
gcc -L/my/path -lMyLib [...]
-L is used to include paths where the linker will look for libraries
-l is used to link a library, which must be passed without the lib prefix and the extension
This question may be useful for a general understanding of libraries usage in C and C++: How to use Libraries
In Makefile , add like this
USER_LIBS = -lYARP_OS -lYARP_sig -lYARP_math -lYARP_dev -lYARP_name -lYARP_init
This will link the libraries you required