Cmake: linking shared library - static

I've done this before a couple of times, but somehow I'm stuck this time. I have an executable "myapp" and a own shared library "mylib". In my cmakelists I have the following:
ADD_LIBRARY(mylib SHARED ${SOURCES_LIB})
INSTALL(TARGETS mylib DESTINATION .)
ADD_EXECUTABLE(myapp ${SOURCES_APP})
TARGET_LINK_LIBRARIES(myapp ${QT_LIBRARIES} mylib)
INSTALL(TARGETS myapp DESTINATION .)
Everything compiles and links correctly, but when I start myapp, I get the following error:
error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directory
The lib and the executable are present in the install directory. When I make my library static by changing the first line of the above cmakelists to:
ADD_LIBRARY(mylib STATIC ${SOURCES_LIB})
then everything works 100%.
Does anyone know what I'm doing wrong?

During the installation of your library and executable, the runtime paths to find the library are stripped from the executable. Therefore your library has to reside in the runtime library search path. For example under Linux, try to set LD_LIBRARY_PATH to the directory that contains the installed library when starting your executable.

This is a very common question about "make install". Actually, there are 3 ways to link a library to your executable file. First, you may use -l -L flags in simple cases. As Benjamin said you may use LD_LIRARY_PATH and write something like: export LD_LIBRARY_PATH=/usr/local/my_lib. In fact this is not a good way. It's much better to use RPATH. There is a very useful doc page about it. Check it out. Well if you write something like this in your top level CMakeLists.txt, it will solve the problem:
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib64")
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib64")

Add the path of the directory containing the library to the LD_LIBRARY_PATH environment variable, by appanding a new path:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/the/library/
You can check the library is correctly found with the 'ldd' tool:
lld ./executable
If the library is not stated as "not found" it is OK and your executable will be executed properly.
Add the 'export' command to your bashrc to properly set the LD_LIBRARY_PATH variable after each system reboot, otherwise you will have to execute again the 'export' command.

Related

Program cannot load shared library GCC

First things first, here is the error message:
./Game: error while loading shared libraries: libEngine.so: cannot open shared object file: No such file or directory
There was no problems while compiling.
Library directories passed to GCC while compiling Game: -L../../bin -L.
Directory tree:
ENGINE
-bin
--Game (executable)
--libEngine.so
-Game
--src
---source code + Game makefile
-Engine
--src
---source code + shared library makefile
I can provide more info on demand.
Setting LD_LIBRARY_PATH is a possible, but usually not the best solution. In particular, dependence on environment produces programs which work for you, but not for your coworkers or your professor (because their environment is different).
Adding -rpath=/path/to/bin to the link line eliminates the need to muck with environment.
Even better: -rpath='$ORIGIN' lets you move the entire installation directory to a different place, and the program will still find its shared libraries in its own bin/ directory.

How to make the dynamic link possible

I am using ssh to do some computing in a server. But I am completely new to unix. I have a .so file needs to be linked to the program. However, when I run the program, it reports the following error
MatMult.so: cannot open shared object file: No such file or directory
Link error: 'MatMult' cannot load dll
Link error: 'MatMult' undefined function
I think I need to change LD_LIBRARY_PATH to make the .so file on the path. But I have no idea how to write it. The original line is
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$OXHOME/bin64:$niqlowHOME/include:$OXDEV
My question is how to modify this line to make the link possible. And is there any resources you would recommend for me to read to understand what does that line do.
If you are compiling some program which requires linking to the said '.so' file, then you can use:
gcc -L[path of the .so file] -o output -l[library name]
And if you are running a program that requires .so library, simply copy the library file to /usr/lib directory.
Otherwise please elaborate your query. Thanks

What is the difference between exporting library paths to LD_LIBRARY_PATH and using the -L flags while linking?

To further explain my situation. I know that when you're using dynamic libraries, you need to export the library paths to LD_LIBRARY_PATH, so that the executable will find the libraries when they're run. If I don't do this, an error will come up, that the shared library could not be found.
Now if I add the following linker flag "-L/path/to/library/ -lthelibrary.so", I can run my executable without exporting the library path to LD_LIBRARY_PATH.
Why is this?
First of all, you do not generally need to set LD_LIBRARY_PATH to run a binary. This environment variable is used by the loader to find additional places to look for .so files to load when the binary is to be executed.
You need to set LD_LIBRARY_PATH if your binary references one or more .so files that are not available in the same location as when it was compiled. It is also needed if any of the directly referenced .so files depend on something that is not available in the same as when the .so file was created.
Use the ldd command to inspect the dependency information in your binary to get a clearer picture of what is saved by the linker when the binary is created.

Linking to libraries in gcc

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.

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