3

I want to build an executable file that looks for its dependencies in a determined relative path. In other words, I want to distribute a zip that contains 2 elements: An executable file and a folder with shared libraries. The executable must be able to find those shared libraries at runtime.

What I've tested

For now, I have the project compiled with cmake. I'm using the cmake's command find_library to find the abs. path to the dependencies.

Here is the CMakeLists.txt file:

cmake_minimum_required(VERSION 2.8)
project( flowers )

find_library( VFC_LIB1 NAMES opencv_calib3d PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib )
find_library( VFC_LIB2 NAMES opencv_core PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib )
...
find_library( VFC_LIB16 NAMES opencv_videostab PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib )

SET(VFC_LIBS ${VFC_LIB1} ${VFC_LIB2} ... ${VFC_LIB16} )

SET(VFC_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/opencv)

IF (VFC_LIB1 AND VFC_LIB2 AND ...  AND VFC_LIB16)

    include_directories( ${VFC_INCLUDE} )
    include_directories( FlowersDetector NeuronalNet )
    add_executable( flowers FlowersDetector/Flowers.cpp FlowersDetector/FlowersDetector.cpp )
    add_definitions(-std=c++11)
    add_definitions(-D_DEBUG) # TODO remove this for release
    target_link_libraries( flowers ${VFC_LIBS} )

ELSE (VFC_LIB1 AND VFC_LIB2 AND ...  AND VFC_LIB16)

    MESSAGE(FATAL_ERROR "OpenCV libraries not found")

ENDIF(VFC_LIB1 AND VFC_LIB2 AND ...  AND VFC_LIB16)

The ... indicates that the rest is the same as the previous, but changin the sequence number.

For example, VFC_LIB1 AND VFC_LIB2 ... AND VFC_LIB16 means that is alwais VFC_LIBx, where x is from 3 to 15.

The probem

The problem is that find_library is used to get the absolute path (I have read that), so that does not allow me to copy-paste the executable to other computer and still be able to run it.

What I need is to find the libraries with a relative path, or other equivalent solution.

EDIT

I have tried to make a "big" executable file with all the libraries "inside it". For that purpose, I have read that I have to link static libraries. I have re-compiled OpenCV building the static libraries (now I have the *.a files plus *.so files.

I have changed the CMakeLists.txt to add these static libraries:

cmake_minimum_required(VERSION 2.8)
project( flowers )
find_package( OpenCV REQUIRED )

SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
SET(BUILD_SHARED_LIBRARIES OFF)
SET(CMAKE_EXE_LINKER_FLAGS "-static")

include_directories( ${OpenCV_INCLUDE_DIRS} )
include_directories( FlowersDetector NeuronalNet )
add_executable( flowers FlowersDetector/Flowers.cpp FlowersDetector/FlowersDetector.cpp )
add_definitions(-std=c++11)
add_definitions(-D_DEBUG)
target_link_libraries( flowers ${OpenCV_LIBS} )

The cmake command runs ok, but when I try to make the project I obtain many errors. Actually, it appears to be only an error, but replied several times. This error is: statically linked applications requires at runtime the shared libraries from the glibc version used for linking

Here is the list of errors, avoiding the similar ones: (if the full list may be helpfull, tell me and I'll upload it)

Linking CXX executable flowers

/usr/bin/ld: cannot find -latk-1.0

/usr/bin/ld: cannot find -lgdk_pixbuf-2.0

/usr/local/lib/libopencv_core.a(opencl_core.cpp.o): In function `(anonymous namespace)::opencl_fn14<41, int, _cl_command_queue*, _cl_mem*, unsigned int, unsigned long const*, unsigned long const*, unsigned long const*, unsigned long, unsigned long, unsigned long, unsigned long, void const*, unsigned int, _cl_event* const*, _cl_event**>::switch_fn(_cl_command_queue*, _cl_mem*, unsigned int, unsigned long const*, unsigned long const*, unsigned long const*, unsigned long, unsigned long, unsigned long, unsigned long, void const*, unsigned int, _cl_event* const*, _cl_event**)':

opencl_core.cpp:(.text._ZN12_GLOBAL__N_111opencl_fn14ILi41EiP17_cl_command_queueP7_cl_memjPKmS6_S6_mmmmPKvjPKP9_cl_eventPSA_E9switch_fnES2_S4_jS6_S6_S6_mmmmS8_jSC_SD_+0x1c0): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libgio-2.0.a(libgio_2_0_la-glocalfileinfo.o): In function `lookup_gid_name':

(.text+0x11a7): warning: Using 'getgrgid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

[And many similar errors]

collect2: error: ld returned 1 exit status

CMakeFiles/flowers.dir/build.make:143: recipe for target 'flowers' failed

make[2]: *** [flowers] Error 1

CMakeFiles/Makefile2:60: recipe for target 'CMakeFiles/flowers.dir/all' failed

make[1]: *** [CMakeFiles/flowers.dir/all] Error 2

Makefile:76: recipe for target 'all' failed

make: *** [all] Error 2

EDIT 2

I've tested the to re-install OpenCV with only the static libraries (*.a) and to use the default OpenCV CMakeLists:

cmake_minimum_required(VERSION 2.8)
project( flowers )
find_package( OpenCV REQUIRED )

include_directories( ${OpenCV_INCLUDE_DIRS} )
include_directories( FlowersDetector NeuronalNet )
add_executable( flowers FlowersDetector/Flowers.cpp FlowersDetector/FlowersDetector.cpp )
add_definitions(-std=c++11)
add_definitions(-D_DEBUG)
target_link_libraries( flowers ${OpenCV_LIBS} )

I can compile all, even I can execute the program, but when the program tries to show an image I have the following error:

OpenCV Error: Unspecified error (The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script) in cvNamedWindow, file /media/ubuntu/67803d44-978a-493e-bdfb-5730e7e9f5a8/opencv-3.1.0/modules/highgui/src/window.cpp, line 527
terminate called after throwing an instance of 'cv::Exception'
  what():  /media/ubuntu/67803d44-978a-493e-bdfb-5730e7e9f5a8/opencv-3.1.0/modules/highgui/src/window.cpp:527: error: (-2) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function cvNamedWindow

Aborted (core dumped)

I have installed with apt-get install libgtk2.0-dev and pkg-config, and also I have downloaded and installed the ATK lib (from http://www.linuxfromscratch.org/blfs/view/svn/x/atk.html).

After that, I have rebooted and re-run cmake and make. When I execute the program, the error persists.

Dan
  • 2,452
  • 20
  • 45
  • The error in "EDIT" section is easily googled. It means, that static linkage is not good for application, which uses `getgrgid_r`, because this function is *target machine-specific* (e.g. it can be changed by the system administrator of that machine). – Tsyvarev Apr 29 '16 at 09:06
  • It is a warning. I suppose that the errors are the missing `atk-1.0` and `gdk-pixbuf`. I've already tried to install them, and the error persists. – Dan Apr 29 '16 at 11:14
  • Just to be sure: do you have `-dev` versions of `atk-1.0` and `gdk-pixbuf` installed on your build machine? – Andrejs Cainikovs Apr 29 '16 at 12:13

3 Answers3

3

On Linux executable stores information about paths to its libraries using RPATH mechanism. This information is used by the linker when it loads executable into memory.

For make paths to libraries relative, there is special path component $ORIGIN, which is evaluated to directory with executable.

In CMake, for set RPATH for executable built, use variable CMAKE_INSTALL_RPATH:

# sets RPATH for *install*ed files
set(CMAKE_INSTALL_RPATH "\$ORIGIN/lib") # Note CMake escaping aroung '$' sign.
# *built* files will also used RPATH which has been set before
set(CMAKE_BUILD_WITH_INSTALL_RPATH on)

# Use 'find_library' calls. They return absolute paths needs for *link* stage.
find_library(...)
...
set(VFC_LIBS ...)
# Create executable and link it using variables filled by 'find_library'
add_executable(flowers ...)
target_link_libraries(flowers ${VFC_LIBS})

Now, if you move(or install) executable into some directory <dir> and all libraries to directory <dir>/lib/, executable can be run.

For more info about RPATH handling in CMake see CMake wiki.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
0

You will need a way to set the library search path before the executable is run. On Linux/Unix the easiest solution would be a shell script in which you set the LD_LIBRARY_PATH accordingly. Windows probably has a similar mechanism but I don't have experience with that.

In both cases CMake will only assist you in building the program and the libraries, it can't find things on other computers for you.

Jan Stephan
  • 403
  • 3
  • 11
0

This is not exact answer to your question, but in your particular scenario I would go with loading the libraries at runtime, to avoid messing up with paths and loading of wrong libraries.

On Linux/Mac, this can be done via dlopen(), on Windows via LoadLibrary().

Community
  • 1
  • 1
Andrejs Cainikovs
  • 27,428
  • 2
  • 75
  • 95
  • 1
    I think you mean `dlopen()`, and it's usually used for optional extras or plugins, rather than fixed dependencies. – Useless Apr 29 '16 at 09:24