first of all, I hope that I ask the question in the right context here...
I build an application in C++ with Code::Blocks. The application uses static libraries that are provided by a third party and cannot be installed on a system via the package management. Therefore I ship these libraries when I distribute my application.
Here is what my target configuration looks like:
<Target title="Unix_162">
<Option output="bin/my_app" prefix_auto="1" extension_auto="1" />
<Option working_dir="/home/marco/third_party_dist/lib" />
<Option object_output="obj/Unix_162" />
<Option type="1" />
<Option compiler="gcc" />
<Option use_console_runner="0" />
<Option parameters="-c" />
<Compiler>
<Add directory="/home/marco/third_party_dist/include" />
</Compiler>
<Linker>
<Add library="/home/marco/third_party_dist/lib/lib1.so" />
<Add library="/home/marco/third_party_dist/lib/lib2.so" />
<!-- some more included the same way -->
<Add directory="/home/marco/third_party_dist/lib" />
</Linker>
</Target>
I can build this target fine and run it. Everything works.
Today, I tried to run in on Debian Squeeze and just copied a folder which contained both the executable and the libraries from the third party. I thought that as long as everything is in one folder the executable will find the .so files. I was wrong. I get the message:
/home/my_app/my_app: error while loading shared libraries: lib1.so: cannot open shared object file: No such file or directory
I don't get this message on my developement machine because Code::Blocks is able to set a working directory for the executable. I could remove the error message by putting the location of the .so files inside /etc/ld.so.conf.d/my_app.conf...
Is there anyway I can build the executable so it searches the libs in the execution directory? Or this is a problem specific for Debian? Or can I specify the working directory for the process before I execute the executable?
I want to avoid changing the systems configuration / environment before you can start the application...
First point these are not static libraries (they are shared).
So the problem is locating the libraries at runtime.
There are a couple of ways of doing this:
1) set the LD_LIBRARY_PATH environment variable.
This is like PATH but for shared libraries.
2) set the rpath in the executable.
This is a path backed into the executable where is searches for shared libs
-Wl,-rpath,<LIB_INSTALL_PATH>
This can be set to . which will make it look in the current directory.
or you can set to '$ORIGIN' which will make it look in the directory the application is installed in.
3) You can install them into one of the default locations for shared libraries.
Look inside /etc/ld.so.conf but usually /usr/lib and /usr/local/lib
4) You can add more default locations
Modify /etc/ld.so.conf
Yes there is, you have to pass option -rpath <path> to your linker where <path> is the path of your library (similar to option -L).
Also, you are probably talking about shared libraries, not static ones.
I thought that as long as everything is in one folder the executable will find the .so files. I was wrong.
An extra step is required to make Linux dynamic linker look for shared libraries in the same directory as the executable. Link the executable with -Wl,-rpath,'$ORIGIN' option (in the makefile $ needs to be quoted like -Wl,-rpath,'$$ORIGIN'). See $ORIGIN and rpath note for more details.
Related
I have downloaded a ROS2 demo from the examples repository.
Specifically, I have used minimal_subscriber and minimal_publisher.
I have ROS2 installed in /opt/ros2 and when I build these two examples with colcon build, it generates an install/ directory with lib/, shared/ and the other usual directory structure.
I can execute and run these demos perfectly fine with my current setup in my machine, but these executables link to libraries present in /opt/ros2, so when I want to execute them in another machine without ROS2 installed or I move my ROS2 installation in my machine, the executables cannot find the shared objects.
I've added a really simple script that adds all dependencies to install/lib when building but the executables don't seem to care, they aren't looking for shared libraries in the generated lib directory, they keep trying to search in /opt/ros2.
I believe this is something I should solve in CMake and it's not ROS2 specific, so, is there any way I can tell my generated executables to search in a diferent directory? (../lib or ./lib in my case)
If you are building them yourself (assumed since you mention CMake), you can set the RPATH in CMake (docs here). Specifically set the CMAKE_INSTALL_RPATH something like:
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
If you can't rebuild them, you can set LD_LIBRARY_PATH in your environment to where the libraries are located, or you can patch the executables themselves with an updated RPATH by using patchelf.
In order to get a relative RPATH rather than an absolute RPATH, use the $ORIGIN variable in your rpath spec. See "Recommendations" the the link above for more details.
I have a question related to how to install a built executable program with cmake when it relies on some external libraries. Suppose my executable is abc, and it relies on two external libraries: lib1.so and lib2.so. The structure of the codes are as follows:
-.........
|----bin (lib1.so lib2.so)
|----include(lib1.h lib2.h)
|----src(main.cpp)
When the executable program is installed using the following cmake commands:
INSTALL(TARGETS ${Exe_Name}
RUNTIME DESTINATION Path to bin
LIBRARY DESTINATION Path to bin)
I expect that the executable program will be in the same directory with lib1.so and lib2.so. However, when I execute the built program in the installation folder, I met the following error:
error while loading shared libraries: lib1 can not open shared object file No such file or directory
If I use ldd to check the executable, I found lib1.so and lib2.so not found. After searching for possible solutions, I found if I call the executable in this way, then it worked:
LD_LIBRARY_PATH=./ ./my_program_run
Then my question is how I can let my executable program knows the locations of the shared libraries with cmake when it is installed? Thanks.
This is best solved this with the RPATH of the final executable. RPATH is a hardcoded search path for the executable itself, and allows the use of the string $ORIGIN, which expands to the location of the executable at runtime. See this reference: http://man7.org/linux/man-pages/man8/ld.so.8.html
CMake strips the rpath of a binary at installation time, to avoid the binary picking up libraries littered around your development tree. But it also provides a simple way to modify the installation rpath for exactly this reason. Here's the short answer:
IF(UNIX)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/../bin:\$ORIGIN")
ENDIF()
This particular example appends to the existing rpath, and adds . and ../bin to the search path, all relative to the location of the binary.
Some developers claim that adjusting the RPATH of the binary is not a good idea. In the ideal world, all the libraries would live in the system library directories. But if you take this to the extreme, you end up with Windows (at least the older ones), where c:\windows\system32 is full of junk that came from who knows where, and may or may not conflict with other software, etc. Using rpath and installing everything in one place seems like a great solution.
If the application is to be cleanly installed to a standard linux distribution, then you should either install the supporting shared libraries into a standard location (/usr/lib), or you should add the libraries location to the ld.so config, by create an /etc/ld.so.conf.d/myprogram.conf file containing the name of the directory the libraries are in.
If the installation is temporary or more ad-hoc, then a script to set the LD_LIBRARY_PATH is suitable.
The libraries are searched in the predefined locations which includes standard library paths configured with ld.so.conf and LD_LIBRARY_PATH. You can also try to compile your app with -rpath, but it is not recommended by some developers. I suggest you to create a wrapper script which will set LD_LIBRARY_PATH and run the real application like that:
"theapp" script:
#!/bin/sh
dir="`dirname \"$0\"`"
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}"$dir"
exec "$dir/theapp.real" # your real application
The application, script and libraries should be in the same location (under bin/).
After applying patches to JBOSS 6.4 to bring it to 6.4.14, my build breaks.
I am using the various modules in the build path using **/*.jar. (See below for code)
RedHat disables old versions of jars when applying patches red hat doc
This is by design.
When applying a patch to EAP 6.2.0 to build EAP 6.2.x , the Patch tool does not replace the existing files. It will place new files under the folder $JBOSS_HOME/modules/system/layers/base/.overlays/_ and cripple the original files by flipping a bit in the end of central directory record to prevent them from being used.
How can I include all the jars in the modules directory except for the disabled ones?
Relevant portion of my build.xml file.
<property name="jbossmodules" value="${env.JBOSS_HOME}/modules" />
<path id="class.path">
<pathelement path="${class.lib}" />
<pathelement path="${java.class.path}" />
[...]
<fileset dir="${jbossmodules}">
<include name="**/*.jar" />
</fileset>
I worked with Redhat support. If one has the appropriate user type, one can download a directory of jars to compile against. In short Redhat seems to discourage compiling against a live patched version of JBOSS. But neither do they make it easy to get a set of jars one can compile against.
What I have tried
I am working sample application using Caffe model in MAC OSX. I downloaded Caffe source from https://github.com/BVLC/caffe.
Steps:
1.Installed dependencies packages for caffe as said in Caffe Link. Some packages is in /usr/local/lib and some packages /opt/local/lib
2.Builded shared library(SO) file using CMakeLists.txt in CMake GUI.
3.Created sample c++ application
4.Linked all dependencies and caffe library files with c++ application.
Built the application
After I executed the application, It needed library files of dependencies package from /usr/local/lib
What I want
After I installed caffe dependencies, I copied all library files in another location.
How to link specified location of the library files in Cmake.?
In Mac osx, when the application run, It takes the library form /usr/local/lib not in the current folder(application folder).
How do I set the application to take library files from current folder.?
Here is a command from a makefile that I use to make an OSX application (the names have been changed to protect the innocent):
install_name_tool -id "#executable_path/../Resources/libMyLib.dylib" ./libMyLib.dylib
You can also just run install_name_tool on the command line.
The first argument after -id is the destination you want (including the name of the library) and the second is the current path to the library -- ie the binary itself. In this example the library is in the same folder as the makefile.
Then, after I build the app (the linker will include this new path to the desired library in the binary you build) I copy the library to the Resources folder:
cp ./libMyLib.dylib App.app/Contents/Resources/
In OSX-land #executable_path is whatever directory your actual binary is in. The way apps are packaged is like this:
App.app/Contents/MacOS/App. There is also a folder in App.app/Contents called Resources, and this is generally where I stash dependencies if I don't want the user to have to install them him/herself. Thus, in this case, #executable_path/../Resources is a relative path from the app's binary to where the dylib is going to be.
You can used install_name_tool to put the library anywhere you want. I just feel like this is a good place to do it.
By the way, you can check what the current id of the library is with otool -L. Probably, if you run
> otool -L caffe.dylib
it will return something like /usr/local/lib, even if you move it somewhere else. Try to change the id with install_name_tool -id and then run otool -L again, and see what happens. It should make sense at that point.
Probably a newbie's question for those used to package and distribute applications:
when launching my executable on a different computer than the one used for compilation, I need to place several dynamic libraries in the same folder to run it.
I want the executable to look at runtime in a relative lib/ subfolder placed besides it and where I would have placed all these libraries. What do I have to do for this?
I don't know about Win and MacOS, but for Linux, the good solution would be to set the RPATH binary header of the executable during build-time.
For me this article helped a lot to understand the various ways dynamic libraries are looked up.
How to set the RPATH properly depends on your build system, but basically you need to specify the option -rpath=/path/to/lib/folder for the linker - this will have the effect that the specified path will always be searched first for shared libraries.
To check if your program was linked correctly, you can use
readelf --dynamic [executable or shared library] | grep PATH
It would be also possible to use the LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to set the path where the libraries are located, but these would require changes on the system where the program is run.