Linking to libraries in gcc - c

I have a collection of dynamic libraries that I want to link to in /usr/local/lib, how can I do this using gcc without setting my LD_LIBRARY_PATH (i have heard it is bad to do this fora number of reasons).
I have spent an hour looking at this on the internet, and fiddling with command line arguments, the only way I got it to work was using the -static -I/usr/local/lib/ flag, but this converts dynamic libraries to static libraries, and the compiler throws up some warnings.
Thanks for your help

Add /usr/local/lib to the loader configuration in /etc/ld.so.conf and run ldconfig.

You can set the system wide search directories for ldd (the dynamic linker) in /etc/ld.so.conf. In many distributions (well, mine) there is a /etc/ld.so.conf.d/ directory, from which the /etc/ld.so.conf includes all *.conf files. You can add the directory directly in ld.so.conf or add a .conf file in the directory.
Of course, you'll need root access to do this.
Oh, yeah: as Ignacio says, run ldconfig after changing these config files.

Related

How can I change the default search paths in GCC?

We have one build machine which has some static libraries at unusual paths, and gcc doesn't find them when via the -l option, all other build machines run fine. But it seems this one configured incorrectly or something.
The solutions we have tried:
Check the host name of the build machine in build script and add the -L command line option if it matches name the problematic build machine (very ugly).
Print the list of search dirs using the -print-search-dirs option
and symlink the problematic library into the first one (too hackish).
What I would like to do is simply add an extra path to search paths system wide to the gcc.
Is there a way to change/configure the default library search paths in GCC? Is there a config file where the list of the defaults are stored?
You can use
-l:<PATH_TO_YOUR_LIBRARY>
Or you can set up the /etc/ld.so.conf with the path to your directory of which you have the shared library installed. You might have to run ldconfig after that.

CMake keeps linking to libraries under /usr/lib64 even full paths to another libraries are given

I am building a package with CMake (3.0.2). This package relies on boost_python and some others. There is an older version in /usr/lib64 and I have another newer version in my own directory /home/x/opt/boost-1.56/lib. There is an symbol link /home/x/opt/boost-1.56/lib64 to deal with the multi-arch gcc.
However, even if I set BOOST_ROOT=/home/x/opt/boost-1.56/lib, and in CMakeCache.txt there is
//Boost python library (release)
Boost_PYTHON_LIBRARY_RELEASE:FILEPATH=/home/x/opt/boost-1.56/lib/libboost_python.a
The generated link.txt contains such a line, instead of the full path:
-Wl,-Bstatic -lboost_python
And when make, it links to the one under /usr/lib64/, which is wrong.
Question:
How to make CMake to use the full path? As documented, only when libraries under system default folders are dealt with -Bstatic, which should not be my case.
Why -Wl,-Bstatic -lboost_python does not work even I have "/home/x/opt/boost-1.56/lib" in LD_LIBRARY_PATH and LIBRARY_PATH? From my limited knowledge they should override the system default.
Information:
gcc --print-search-dir gives:
/home/x/opt/boost-1.56/lib/x86_64-unknown-linux-gnu/4.9.2/
/home/x/opt/boost-1.56/lib/../lib64/
/lib/x86_64-unknown-linux-gnu/4.9.2/
/lib/../lib64/
/usr/lib/x86_64-unknown-linux-gnu/4.9.2/
/usr/lib/../lib64/
/home/x/opt/boost-1.56/lib/
/lib/
/usr/lib/
set(Boost_NO_SYSTEM_PATHS ON)
This will allow it to ignore everything but BOOST_ROOT
Solution (partially only):
CMake uses -Bstatic if there it thinks that the boost libraries it chooses are in the system path, including that related to enviromental variables. Else it use the full path.
I still cannot find why LIBRARY_PATH cannot override the system
So to make it work, REMOVE everything in LIBRARY_PATH and LD_LIBRARY_PATH will do the trick: CMake will use full path in that case.
Add this at the beginn oingf your top level CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
and use cmake 3.3.0 or later.
Interestingly, with cmake 3.11.1 set(Boost_NO_SYSTEM_PATHS ON) did not work for me.

Do I really need to specify library location for linking with automake?

I am working on a multi-platform C program. The makefile has become pretty complicated because of all the different compilers, library locations, etc. on each machine. I figured Autoconf/Automake would be a good solution, though my previous experience using those tools was minimal.
My Makefile.am has the line LIBS=-lX11, but linking fails with the error "/usr/bin/ld: cannot find -lX11". I can work around this by adding "-L/usr/X11R6/lib/" to the definition of LIBS, but should I really need to do that? When I run ./configure, it says:
checking for X... libraries /usr/X11R6/lib, headers /usr/X11R6/include
So it seems like Automake should know where to find it. Is there a way I can reference its location in Makefile.am without having to hardcode it, since the X11 libs will be in a different place on each machine?
Your Makefile.am should not set LIBS. If you need to link with a library, configure.ac should include a check for the library and the configure script will set LIBS accordingly. Also, Makefile.am should not specify paths to libraries. Each system should be configured so that the precompiler can find the headers and the linker can find the libraries. If the system is not set up so that the linker can find a library, the correct solution is for the user to specify the location in LDFLAGS rather than hard coding something in Makefile.am. (eg, rather than adding -L/p/a/t/h to a Makefile, you should add LDFLAGS=-L/p/a/t/h to the invocation of configure.)

Substitute for LD_PRELOAD or LD_LIBRARY_PATH

I'm doing some C programming on a machine for which I don't have root access. I've compiled some shared libraries that I'm linking to, but because I cannot install the libraries in the typical location (/usr/local/lib) I have to explicitly specify the location of the libraries each time I compile and run. When compiling, this simply means adding the -L flag to the gcc command, but for program execution it's a lot more annoying. Either I must add the non-standard directory to LD_LIBRARY_PATH in each session, or I must add LD_PRELOAD=/path/to/libs to the beginning of the execute command.
Is there a better way to do this on a machine for which I don't have root access?
BTW, the machine is running Red Hat 4.1.
There are several solutions, from better to worse:
Use $ORIGIN, e.g. gcc main.o -L../lib -lfoo -Wl,-rpath='$ORIGIN'/../lib
Use target RPATH, e.g. gcc main.o -L../LIB -lfoo -Wl,-rpath=/home/user/lib
Set LD_LIBRARY_PATH from your .bashrc or .profile
Solution 1 allows you to install the binary anywhere, so long as you move the binary and the libraries together, e.g. my-app/bin/a.out and my-app/lib/{needed-shared-libs}.so. It also allows for multiple versions of the application and their set of shared libs.
Solution 2 works fine if you only need one set of shared libs, and never wish to move them around.
Solution 3 affects every application you run, and may cause some of them to bind to your shared libraries instead of the system ones. That may cause them to crash, fail with unresolved symbols, or cause you other pain. To exacerbate, the problem will only happen to you and nobody else, so you'll have hard time getting help for it.
You can add the environment variables to your .bashrc (or whatever file your shell sources when you log-in).
If you set the environment variable LD_RUN_PATH when you compile and link your program, then that search path will be baked in to the executable, and the dynamic linker will search it at runtime.
Using LD_LIBRARY_PATH or LD_PRELOAD is pretty much how to do this. To fix this, rename your program from myprog to myprog-exe, and create a shell script that looks like this called myprog:
#!/bin/sh
export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH
`dirname $0`/myprog-exe
This way, when someone runs myprog, it will really run the shell script which then runs myprog.

How do you actually use a C library?

I'm sure this question has been asked many times, but I can't figure this out. Bear with me.
So when you download a library, you get a bunch of .c and .h files, plus a lot of other stuff. Now say you want to write a program using this library.
I copy all the .h files into my project directory. It just doesn't compile.
Great, so then I get the library as a bunch of .dll's, and i copy the dlls into my project directory. Still doesn't compile.
How does this work?
What do you do, like right after creating the folder for your project? What parts of the library package do you copy/paste into the folder? How do you make it so that it can compile? Go through the steps with me please.
Where to put the .h files?
Where to put the .dll files?
How to compile?
Thanks.
(the library I'm trying to get working is libpng, I'm in windows with MinGW, and i'm looking to compile from command-line like usual.)
(from what i gather, you put the .h files in directory A and the .dll files in directory B and you can use -l and -L compiler options to tell the compiler where to find them, is this correct?)
Here's a brief guide to what happens when you compile and build a basic C project:
The first stage compiles all your source files - this takes the source files you've written and translates them into what are called object files. At this stage the compiler needs to know the declaration of all functions you use in your code, even in external libraries, so you need to use #include to include the header files of whatever libraries you use. This also means that you need to tell the compiler the location of those header files. With GCC you can use the -I command line to feed in directories to be searched for header files.
The next stage is to link all the object files together into one executable. At this stage the linker needs to resolve the calls to external libraries. This means you need the library in object form. Most libraries will give you instructions on how to generate this or might supply it ready built. Under Linux the library file is often a .a or .so file, though it might just be a .o. Again you can feed the location of the library's object file to GCC with the -L option.
Thus your command line would look like this:
gcc myProg.c -I/path/to/libpng/include -L/path/to/libpng/lib -lpng -o myProg.exe
(Note that when using the -l command line GCC automatically adds lib to the start of the library, so -lpng causes libpng.a to be linked in.)
Hope that helps.
Doing it under windows (supposing you user Visual Studio)
After unpacking add the library include directories to your projects' settings (Project -> Properties -> C/C++ -> Additional Include Directories)
Do the same thing for the Libraries Directory (Project -> Properties -> Linker -> Additional Library Directories)
Specify the name of the library in your Linker Input: Project -> Properties -> Linker -> Input -> Additional Dependencies
After this hopefully should compile.
I don't recommend adding the directories above to the Global settings in Visual Studio (Tools -> Options -> Project and Solutions) since it will create and environment where something compiles on your computer and does NOT compile on another one.
Now, the hard way, doing it for a Makefile based build system:
Unpack your stuff
Specify the include directory under the -I g++ flag
Specify the Library directory under the -L g++ flag
Specify the libraries to use like: -llibrary name (for example: -lxml2 for libxml2.so)
Specify the static libraries like: library name.a
at the end you should have a command which is ugly and looks like:
g++ -I/work/my_library/include -L/work/my_library/lib -lmylib my_static.a -o appname_exe MYFILE.CPP
(the line above is not really tested just a general idea)
I recommend go, grab a template makefile from somewhere and add in all your stuff.
You must link against a .lib or something equivalent i.e. add the ".lib" to the libraries read by the linker. At least that's how it works under Linux... haven't done Windows so a long while.
The ".lib" contains symbols to data/functions inside the .dll shared library.
It depends on the library. For examples, some libraries contain precompiled binaries (e.g. dlls) and others you need to compile them yourself. You'd better see the library's documentation.
Basically, to compile you should:
(1) have the library's include (.h) file location in the compiler's include path,
(2) have the library stubs (.lib) location in the linker's library path, and have the linker reference the relevant library file.
In order to run the program you need to have the shared libraries (dlls) where the loader can see them, for example in your system32 directory.
There are two kinds of libraries: static and dynamic (or shared.)
Static libraries come in an object format and you link them directly into your application.
Shared or dynamic libraries reside in a seperate file (.dll or .so) which must be present at the time your application is run. They also come with object files you must link against your application, but in this case they contain nothing more than stubs that find and call the runtime binary (the .dll or the .so).
In either case, you must have some header files containing the signatures (declarations) of the library functions, else your code won't compile.
Some 'libraries' are header-only and you need do nothing more than include them. Some consist of header and source files. In that case you should compile and link the sources against your application just as you would do with a source file you wrote.
When you compile, assuming you have the libs and the headers in the same folder as the sources you are compiling, you need to add to your compile line -L . -I . -lpng. -L tells the linker where to look for the library, -I tells the compiler where to look for the headers and -lpng tells the linker to link with the png library.
[Edit]
Normal projects would have some sort of hierarchy where the headers are in an /include folder and the 3rd party libs are in a /libs folder. In this case, you'd put -I ./include and -L ./libs instead of -I . and -L.
[Edit2] Most projects make use of makefile in order to compile from the command line. You can only compile manually for a small number of files, it gets quite hectic after that
Also,
you may want to look over Dynamic Loading support in various languages and on various
platforms.
This support is very handy in cases when you want to use a library optionally and you don't want your program to fail in case that library is not available.

Resources