Linking against a c/c++ library - c++

I have some basic questions regarding linking against a C/C++ library. I am trying to understand the difference in using the two different usages -L/usr/local/lib -lm usage and /usr/local/lib/libm.a usage. E.g., when I compile and link an example from the [SUNDIALS] library, both of the following work
gcc -Wall cvRoberts_dns.c -o cvRoberts_dns.exe -I/usr/local/include -L/usr/local/lib/ -lsundials_cvode -lsundials_nvecserial -lm
OR
gcc -Wall cvRoberts_dns.c -o cvRoberts_dns.exe /usr/local/lib/libsundials_cvode.a /usr/local/lib/libsundials_nvecserial.a
However, to compile and link an example from the library [libsbml], the following works
g++ -Wall readSBML.cpp -o readSBML.exe -I/usr/local/include -L/usr/local/lib -lsbml
but the this does not
g++ -Wall readSBML.cpp -o readSBML.exe /usr/local/lib/libsbml.a
If required, I can post the complete error message I get, but the last line of the message is as follows
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
My questions are as follows:
In the second style of linking (of the first example), there is no information regarding where to find the include files (header files), how does the compiler know the information supplied in -I/usr/local/include which is provided in the first style of the first example?
In the second style of first example there is no /usr/local/lib/libm.a (it actually gives an error message that libm.a cannot be found if I try to include it), then why -lm is required in the first style?
How do I compile the second example in the second style (i.e., using /usr/local/lib/libsbml.a)? I do see that there are files - libsbml.a and libsbml-static.a in the /usr/local/lib folder, but none of them work.
If it helps, I am on an OS X machine.
I would be very thankful if any one could help in this regard.
Just an update - I tried
g++ -Wall readSBML.cpp -o readSBML.exe /usr/local/lib/libsbml.5.dylib
and that compiled and linked just fine.
Thanks
SN

In general
The -L option is meant to find where the libraries themselves are. Each library is a collection of one or more object code (machine language) files. There is no need to find the include files.
The -I option has nothing to with linker, it helps the compiler resolve the header files used in your driver programme( eg Roberts_dns.c). This happens during the pre-processing stage.
In the second style of linking (of the first example), there is no
information regarding where to find the include files (header files),..
If the compilation worked as you expected,it may be because /usr/local/include is in the default include path for gcc. To check the default include path for gcc do gcc -xc -E -v -.
In the second style of first example there is no
/usr/local/lib/libm.a(it actually gives an error message that libm.a
cannot be found if I try to include it), then why -lm is required in
the first style?
In Linux, some libraries like libc.a are directly linked to your execultable by default while libm.a is not. In Mac (your environment), though, libm is directly link to the executable by default. So you don't have to explicitly link it. It is less likely that libm.a is located in /usr/local/lib/. So you got an error. But why link it in the first place?

Related

Cross compilation for gpsd shows "unrecognized option"

I am cross-compiling gpsd3.20 on my Ubuntu 16.04 for the ARM architecture. As you may know, gpsd uses Sconsctruct to compile the source codes. During my cross-compilation, the moment when it needs to create the libgps.so it shows an error unrecognized option '-Wl, -Bsymbolic'.
Before posting the question here, I have tried t check my toolchain binaries and I found out that if I run this line manually:
sudo ./arm-v7a-linux-gnueabihf-ld -o test/gpsd-3.20/libgps.so.25.0.0 -pthread -shared -Wl,-Bsymbolic-functions -Wl,-soname=libgps.so.25 test/gpsd-3.20/os_compat.os test/gpsd-3.20/rtcm2_json.os test/rtcm3_json.os test/gpsd-3.20/shared_json.os test/gpsd-3.20/timespec_str.os test/gpsd-3.20/libgpsmm.os -L. -lrt -lm -lrt
The above commands print out the exact error as I mentioned previously. However, if I run the exact command replacing ld with gcc, then there is no any errors.
sudo ./arm-v7a-linux-gnueabihf-gcc -o test/gpsd-3.20/libgps.so.25.0.0 -pthread -shared -Wl,-Bsymbolic-functions -Wl,-soname=libgps.so.25 test/gpsd-3.20/os_compat.os test/gpsd-3.20/rtcm2_json.os test/rtcm3_json.os test/gpsd-3.20/shared_json.os test/gpsd-3.20/timespec_str.os test/gpsd-3.20/libgpsmm.os -L. -lrt -lm -lrt
Upon checking the arm-v7a-linux-gnueabihf-gcc --help, I found out that, gcc support -Wloptions whereas in the arm-v7a-linux-gnueabihf-ld it doesn't support the -Wl options. So now I am not sure how to change the SConstruct file so that it doesn't execute ld instead I want it to execute gcc especially for the libgps.so part.
(can't comment), so as answer: have you tried to set the env.-var.:
export LD=arm-v7a-linux-gnuabihf-gcc
Gcc takes -Wl,XXX and passes XXX to the linker.
I think you've got two combining problems here, though there's some guessing involved without looking into the build itself. First, scons shouldn't be adding the flag when building a library (https://github.com/SCons/scons/issues/3248 - fixed but, I believe, not part of a release). Second, "linking" should probably be done using gcc. If you call gcc to link, it still calls the linker behind the scenes - after dealing with options that are intended for gcc, which -Wl,-Bsymbolic is, it means pass -Bsymbolic on to the linking phase (indicated by -Wl, the 'l' meaning linker). So I'm supposing that the way you've told scons about the cross toolchain isn't quite right either, if it's calling ld directly you're probably going to have other issues as well.

Compiling an external library on Linux

Good Day Everyone,
N.B - This problem has been solved - I have provided my own solution in the answer section however the solution provided by Jonathan is much shorter. Nevertheless, this was the following question I originally posted:
I am basically trying to compile a serial library (for UART communication) on Linux however I am not really sure how to correctly compile (I have mentioned what I have done so far below), any suggestions would be highly valuable. I am using the serialib library - which is composed of 2 main files (serialib.h and serialib.cpp) , you may directly view the source code of these files here (scroll all the way to the bottom and view the files in new tabs): http://serialib.free.fr/html/classserialib.html
I transferred these files (serialib.h and serialib.cpp) to my BeagleBone Black micro-controller which is running Debian (Wheezy) , g++/gcc (Debian 4.6.3-14) 4.6.3. I wrote my own program (uart.cpp is my file name) to access the functions provided by this library, this is what I wrote:
#include <iostream>
#include "serialib.h"
#ifdef __linux__
#define DEVICE_PORT "/dev/ttyO1"
#endif
int main()
{
serialib LS;
return 0;
}
So as you can see I am trying to access the 'seriallib' class. serialib.h, serialib.cpp and uart.cpp are all in the home directory. I also manually added the iostream library in serialib.cpp as I did not see it being declared in the original source code.
Now I am really unsure of how to compile such external libraries but so far I tried the following steps:
g++ -c -Wall -Werror -fPIC serialib.c to convert to PIC which gives the following error:
distcc[3142] (dcc_parse_hosts) Warning: /home/debian/.distcc/zeroconf/hosts contained no hosts; can't distribute work
distcc[3142] (dcc_zeroconf_add_hosts) CRITICAL! failed to parse host file.
distcc[3142] (dcc_build_somewhere) Warning: failed to distribute, running locally instead
g++ serialib.cpp -L /home/debian/serialib.h which gives the following error:
/usr/lib/gcc/arm-linux-gnueabihf/4.6/../../../arm-linux-gnueabihf/crt1.o: In function _start':
(.text+0x30): undefined reference tomain'
collect2: ld returned 1 exit status
distcc[3210] ERROR: compile serialib.cpp on localhost failed
As of now I am still finding out how to compile this and if I manage to work this out then I'll post my solution here too. Once again any suggestion will be highly valuable. Thank you all :) .
g++ -c -Wall -Werror -fPIC serialib.c to convert to PIC which gives the following error:
The "error" is not an error, it's a warning, telling you that your distcc setup is broken, but that it compiled locally.
That command doesn't "convert to PIC", it compiles the file serialib.c and produces a compiled object file, serialib.o
g++ serialib.cpp -L /home/debian/serialib.h
This is just nonsense. It tries to build a program from serialib.cpp and use the directory /home/debian/serialib.h (which isn't a directory!) to find libraries.
You don't need to "compile a library" you can just compile both the source files and link them together into a program. Either:
g++ -c serialib.cpp
g++ -c uart.cpp
g++ serialib.o uart.o -o uart
Or all in one command:
g++ serialib.cpp uart.cpp -o uart
You should read An Introduction to GCC to understand the commands, not just enter bogus commands without understanding them.
I have found a solution to this problem, hope this helps for all the future readers with similar problems. I have my own source code uart.cpp (Given in the question) which I want to compile, the external library is serialib that contains two main files (serialib.h and serialib.cpp), you will want to replace the following commands with respect to the files you have
Step 1: Compiling with position independent code
g++ -c -Wall -Werror -fpic serialib.cpp
Step 2: Creating a shared library
g++ -shared -o libserialib.so serialib.o , here the library is libserialib.so.
Step 3: Linking your source code with library
g++ -L /home/debian -lserialib uart.cpp -o uart
g++ -L /home/debian -Wall -o test uart.cpp -lserialib
You may save the library at a different path and you may have a different name of course. Suppose you have a library called libabc.so at the directory /home/user/myDir then the commands will be like:
g++ -L /home/user/myDir -labc your_code.cpp -o your_code
g++ -L /home/user/myDir -Wall -o test your_code.cpp -labc
test is out own program, lserialib is actually looking for libserialib.so and not serialib.o as gcc/g++ assumes all libraries start with lib and end with .so or .a and you can see the same goes for labc as it will look for libabc.so thus it is important to make sure your library name begins with lib and ends with .so or .a
Step 4: Making library available at run time
Here we provide the path where the library is actually stored, I saved it in the directory /home/debian which is why my command looks like:
export LD_LIBRARY_PATH=/home/debian:$LD_LIBRARY_PATH
if your library is saved at /path/to/file then the command will look like:
export LD_LIBRARY_PATH=/path/to/file:$LD_LIBRARY_PATH
This is to help the loader find the shared library and to view this path: echo $LD_LIBRARY_PATH and to unset this: unset LD_LIBRARY_PATH
To execute the program type either ./test or ./uart and in case of any modification to the main source code (uart.cpp in this case) , simply repeat step 3. I found the following link very useful: http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html . Thank you to all of you who took time to read this question and especially those who gave me suggestions. If anyone has more or better solutions, feel free to post them here to assist future readers :).

"multiple definition of `atexit'" when linking with DLL

I use MinGW32 more specifically TDM-GCC-32. I have very simple project I link to one custom library but this error pops out:
>g++ -D_WIN32 -D_MINGW -lgdi32 -lgdiplus -Linterception/x86 -linterception main.cpp -o interceptor.exe
interception/x86/libinterception.a(dgnes00125.o):(.text+0x0): multiple definitio
n of `atexit'
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../crt2.o:crt1.c:(.text+0x2c0):
first defined here
interception/x86/libinterception.a(dgnes00109.o):(.text+0x0): multiple definitio
n of `_onexit'
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../crt2.o:crt1.c:(.text+0x2d0):
first defined here
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../../mingw32/bin/ld.exe: C:/TD
M-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../crt2.o: bad reloc address 0x20 in
section `.eh_frame'
collect2.exe: error: ld returned 1 exit status
Commands I use to build the library:
gcc -DINTERCEPTION_EXPORT -D_WIN32 -D_MINGW -shared -o interception.dll interception.c
dlltool -z interception.def --export-all-symbol interception.dll
dlltool -d interception.def -l libinterception.a
I guess I have to use different options for compiling the library to avoid redefinitions..
The dlltool method I believe is currently deprecated. I can't fault you here though, as most of the available documentation still says to do it this way.
Gcc will link directly against .dll files, making .a files obsolete (at least for dealing with dll's - the only current reason to use a .a file is for static linking). You don't even have to specify the dll with the -l flag, although you have to specify the path of the dll if it's not in your current directory
C:\Users\burito>gcc main.o opengl32.dll -o main.exe
gcc: error: opengl32.dll: No such file or directory
C:\Users\burito>gcc main.o c:\Windows\system32\opengl32.dll -o main.exe
C:\Users\burito>
Ok, opengl32.dll is perhaps not a great example, but I hope I've given you the general idea.
I believe MSVC still needs its .lib files to use a .dll, for which there are several ways of making them if the library doesn't come with one.
In your specific case, the command that should work would be...
g++ -D_WIN32 -D_MINGW -lgdi32 -lgdiplus interception/x86/interception.dll main.cpp -o interceptor.exe
If for whatever reason you really do need to create a .a file from a .dll, the command that has worked for me is...
gendef interception.dll
dlltool -l interception.a -d interception.def -k -A
As the repository you linked does provide .dll files in its releases, you shouldn't have to build them yourself

Compiling C++ code on a system with two different Boost versions installed

I am trying to compile on a Ubuntu system where I have two different versions of boost instaled: 1.46.1 in /usr/lib/ and 1.61.0 in /usr/local/lib/.
I have stated that 1.61.0 is giving me some compilation issues, but I prefer not removing it to study the problem when I have more time. I supposed I could refer at the makefile to 1.46.1, using -I"/usr/include/boost" for 1.46.1 source, and then -L /usr/lib for the libraries. But still not working.
My suspicion is that the usage of -lboost_filesystem -lboost_system -lboost_date_time are somehow referencing to 1.61.0, even when used together with -L /usr/lib (which points to 1.46.1). But I have been unable to find information about this compilation flags for the linker.
How can I make sure those -l are referenced to the Boost version I want?
Here is an example of what the makefile is doing while linking (the part where it is failing):
Invoking: Cygwin C++ Linker
g++ -O0 -g3 -Wall -Wextra -o"../bin/MY_APP.exe" ../bin/objs/main.o ../bin/objs/FileLoad.o ../bin/objs/DatabaseLoad.o -L /usr/lib/mysql -L /usr/lib -lmysqlclient -lboost_filesystem -lboost_system -lboost_date_time
You can confirm or disprove your suspicions by getting the linker to confess which libraries it is actually using. Add the option -Wl,--verbose to your g++ link command line (in the makefile or try this directly). The linker will then spit out which exact file was matched for everything it was trying to link, including your boost libraries.
If it turns out it is in fact linking the wrong versions, it also gives you a clue as to why exactly, by specifying the exact order of paths which the linker tries in locating a given library. This should give you some ammo should you need to change around some of your options (e.g. ordering and/or content of -L... and -l... options)
Should this fail, you can also use the option -l:/path/to/exact/libboost_whatever.so. This will force to use the linker the given version. I would try this last though.

ld can't link with a main executable

On OSX 10.6.4 with i686-apple-darwin10-g++-4.2.1 compiling using TextMate and a Makefile which in the first place has been made für a Linux and I am trying to translate for OSX.
When compiling a c++ project I get the "can't link with a main executable" error:
g++ -Wall -g -I ~/svnX-Repository/axp-Projekte/xrlfupa/trunk/src/ -I ~/svnX-Repository/boost_1_44_0 -I /opt/local/var/macports/software/boost/1.44.0_0/opt/local/lib/ -I /opt/local/var/macports/software/gsl/1.14_0/opt/local/include/ -o xrfLibTest xrfLibTest.o excitFunctions.o xrfFunctions.o filterFunctions.o detectorFunctions.o -L/opt/local/var/macports/software/boost/1.44.0_0/opt/local/lib/ -L/opt/local/var/macports/software/gsl/1.14_0/opt/local/lib/ -lm -lxrlTUB -lboost_serialization -lgsl -lgslcblas # Debug 1
ld: in /usr/local/lib/libxrlTUB.so, can't link with a main executable
collect2: ld returned 1 exit status
make: *** [prog] Error 1
The library that is mentioned (libxrlTUB.so) is in its place (/usr/local/lib/libxrlTUB.so) but, possibly that is where the problem came from, the libxrlTUB.so has been compiled by myself beforehand as well.
The compile process went through, it was generated by swig, though there was a warning:
g++ -arch x86_64 -m32 -g -fpic -I /usr/include/python2.6 -c PyXrl_wrap.cxx
In function 'void SWIG_Python_AddErrorMsg(const char*)':
warning: format not a string literal and no format arguments
which, as far as I could find out, shouldnt be a problem. (Or is it?)
Unfortunately this whole thing is part of a project from the university. Actually I am supposed to write an X-ray-analysis script in python, which would be fine, if... well if I wouldn't be expected to use the librarys that are meant to result from this c++ project.
(Afterwards they should be used via import in python.)
I am not really experienced with c++, neither with compiling on OSX systems. So far I have been bothering with scipting (python, bash, etc). So Maybe I am just missing something simple. Hopefully someone can give me an hint where I can continue reading in order to deal with the above "can't link with a main executable" error...
Thanx in advance,
Liam
The error message is telling you the problem—it is that /usr/local/lib/libxrlTUB.so is not a shared library; it's an executable. You can't link against an executable. Probably whatever build process you used for libxrlTUB.so didn't understand how to build shared libraries on the Mac (it's more suspect because .dylib is the correct extension to use.)
Take a look at Apple's documentation on compiling dynamic libraries. You can use file to make sure your output is of the correct type, for example:
% gcc -c foo.c
% gcc -dynamiclib foo.o -o foo.dylib
% file foo.dylib
foo.dylib: Mach-O 64-bit dynamically linked shared library x86_64
Without -dynamiclib you end up with an executable, which may be the problem you've run into.