How do I statically compile boost_iostreams? - c++

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.

Related

How can I change the following static linked program into dynamic linked program?

I have already figure out how to staticly link v8 with my own GLIBC/STDC++.
$(GCC_ROOT)/bin/g++ samples/bench.cpp -o bench -isystem$(GLIBC_ROOT)/include/ -I. -Iinclude -isystem$(GLIBC) -nodefaultlibs -DV8_COMPRESS_POINTERS -static $(V8_OBJ)/libv8_monolith.a -Wl,--start-group $(GCC_ROOT)/lib64/libstdc++.a $(GLIBC_ROOT)/lib/libpthread.a $(GLIBC_ROOT)/lib/libdl.a $(GLIBC_ROOT)/lib/libm.a $(GLIBC_ROOT)/lib/librt.a $(GCC_GCC)/libgcc.a $(GCC_GCC)/libgcc_eh.a $(GCC_GCC)/libcommon.a $(GLIBC_ROOT)/lib/libc.a -Wl,--end-group
However, I find it not good to link all stuff staticly, and I want to GLIBC/STDC++ dynamicly, and my strategy is:
For all .a which is staticly linked, I use -Wl,-rpath= to specify its path.
For those .a which has no corresponding .so, such as libgcc.a, I still link them staticly.
So I write the following command
$(GCC_ROOT)/bin/g++ samples/bench.cpp -isystem$(GLIBC_ROOT)/include/ -I. -Iinclude -isystem$(GLIBC_ROOT)/ -o bench_dyn -nodefaultlibs -DV8_COMPRESS_POINTERS -Wl,--start-group $(V8_OBJ)/libv8_monolith.a -Wl,-rpath=$(GCC_ROOT)/lib64/ $(GCC_GCC)/libgcc.a $(GCC_GCC)/libgcc_eh.a $(GCC_GCC)/libcommon.a -Wl,-rpath=$(GLIBC_ROOT)/lib -Wl,--end-group
However, this strategy won't work, because lots of symbols are not found, such as
pthread_mutex_*
std::ostream::operator<<(int)
I think these are all GLIBC/STDC++ symbols, and I linked them dynamicly, so they should not remain undefined?
What's wrong here?

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

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.

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

GCC Shared Library Problems

I'm trying to create a shared library on ubuntu using gcc
I just have one simple class(shared.h and shared.cpp) and one client to use it (main.cpp)
This is my makefile and I'm still not able to to get the program to compile.
all:
#compile object(fPIC: creates position independent code)
gcc -fPIC -Wall -g -c shared.cpp
#compile shared library
gcc -shared -Wl,-soname,libshared.so.1 -o libshared.so.1.0.1 shared.o -lc
#link shared library
gcc -g -o main main.cpp -L. -lshared
I'm confident the first line is correct
I am unsure what "-lc" does. I think it passes something to the linker?
I don't want to install the library, I just want to be able to link it from the current directory. I have tried: export LD_LIBRARY_PATH=.
but it does not seem to make a difference. Everything is in the current directory.
ERROR: /usr/bin/ld: cannot find -lshared
how do I get the compiler to check the current directory for my library?
The problem is not that it's not looking in the directory, the problem is that you've named the library "libshared.so.1.0.1". When you use -lshared, it's looking for a file named 'libshared.so' or 'libshared.a' in the library search path.
Most of the time, when using versioned system libraries, you'll provide a link to the latest one as 'libshared.so', even if you have installed 'libshared.so.1' or 'libshared.so.1.0.1'.
In your case, if you continue to leave the file named 'libshared.so.1.0.1', you'll want to create 2 symbolic links:
libshared.so - So that the library can be found using ld
libshared.so.1 - Since you declared the SO name as libshared.so.1 when building it, you need to provide this link, otherwise, the executable will not be able to find the proper shared library at runtime.
You don't write any dependencies, which is the purpose of Makefile-s. And you probably need to force the run path Perhaps something like
.PHONY: all clean
CXX=g++
CXXFLAGS=-g -Wall
all: main
main: main.o libshared.so
$(LINK.cpp) -o $# $< -Wl,-rpath,. -L. -lshared
libshared.so: shared.pic.o
$(LINK.cpp) -shared -o $^ $<
main.o: main.cc shared.hh
%.pic.o: %.cc
$(CXX) $(CXXFLAGS) -fPIC -c -o $# $<
#
clean:
rm -f *.o *.so main *~

Static linking failed although the name exists

I'm trying to link to a static library, libcovis.a. Everything looks fine but I still have
undefined reference to `CoViG_PublicDemo::MoInS::reset()'
I checked that the name exists in the library
$nm libcovis.a | grep reset
...
_ZN16CoViG_PublicDemo5MoInS5resetEv
...
I'm using linking arguments -L/path/to/libcovis.a -lcovis
What am I doing wrong ?
Edit:
The error might be something else, if do
gcc main.cpp -I/usr/include/opencv -I/usr/include/cairo -I../../Source -o slam -rdynamic -lGLU -lGL -lSM -lICE -lX11 -lXext -lglut -lXi -lxml2 -lboost_filesystem-mt -llapack -lblas -lcv -lcxcore -lcvaux -lhighgui -lcairo ../../Source/libcovis.a ../../Source/contrib/gnuplot_i/libcovis_contrib_gnuplot_i.a -lgl2ps
It works !
But when I'm in KDevelop using cmake, I doesn't work anymore. I use
CMAKE_EXE_LINKER_FLAGS:STRING=-rdynamic -lGLU -lGL -lSM -lICE -lX11 -lXext -lglut -lXi -lxml2 -lboost_filesystem-mt -llapack -lblas -lcv -lcxcore -lcvaux -lhighgui -lcairo /usr/local/src/CoViS-0.0.0-1/Source/libcovis.a /usr/local/src/CoViS-0.0.0-1/Source/contrib/gnuplot_i/libcovis_contrib_gnuplot_i.a -lgl2ps
CMAKE_CXX_FLAGS:STRING=-I/usr/local/src/CoViS-0.0.0-1/Source -I/usr/include/opencv -I/usr/include/cairo
The only difference I can see is that the paths are absolute and not relative, but if he couldn't find the libs, he would say it...
There are two different issues there, the first of which is the simplest, you have used the wrong compiler options. The -L option tells the linker to also look in the directory when looking for a library. The -l tells it to link the specific library. To link you would then use:
g++ -o test test.o -L/path/to -lcovis
or
g++ -o test test.o -l/path/to/libcovis.a
To force static linking if the same library is present as a dynamic library in the same directory.
The second potential issue is that the order of static libraries in the linker command line does matter, so that might also be an issue if there is a dependency on different static libs.
g++ -o test tests.o -ldependent -lprovider
The linker will process the libraries in order as they are in the command line, and from each static lib it will only pull those symbols that are required (with as much information as the linker has at that time). In the command line above, the linker will extract from dependent the symbols it needs for test.o, and that might in turn add new undefined symbols to the program (the dependencies of dependent). When it processes provider it will fill in those symbols. If the order was reversed in the command line, the symbols that are required by dependent but not by test.o would not be added to the executable, as the linker does not know that those symbols will be needed when processing provider.
Should the arguments be like -L/path/to/ -lcovis?
Besides, object files should be placed before libs, for example
g++ obj1.o obj2.o -L/path/to/ -lcovis.
If you see the link succeeding in one context but not another, I suspect the problem may be caused by the order in which the link operation is executed as the linker will discard symbols in a library if they're not needed at the point in which the library is referenced.
Here is a link explaining: http://www.network-theory.co.uk/docs/gccintro/gccintro_18.html
I've run into similar situations in the past the linking order was found to be the cause of the problem.