13
votes

I have written a simple c++ program which use boost that I want to deploy on machines of same architecture with any linux flavor (for the time being) that may or may not have some boost versions installed. I'm new to deployment but tried to read docs and come up with a CMakeLists.txt which looks like :

cmake_minimum_required(VERSION 2.8)
project( myprog )
FIND_PACKAGE( Boost 1.50 COMPONENTS thread system chrono program_options REQUIRED )
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )
add_executable( myprog myprog.cpp )
target_link_libraries( myprog -lpthread -lboost_system -lboost_chrono -lboost_program_options )

INSTALL( TARGETS myprog DESTINATION . )
SET( CPACK_GENERATOR "TGZ")
INCLUDE( CPack )

Everything compile and run fine, but packaging (make package) only package the executable and not the dependent boost libraries ".so"

When I run : ldd myprog it tells me it depends on : linux-vdso.so, libpthread.so, libboost_system.so, libboost_chrono.so, libboost_program_options.so libstdc++.so libgcc_s.so libc.so librt.so libm.so

Those are the shared libraries I want to pack (maybe I don't need to pack the standard ones)

How can I tell cmake to grab the correct shared object libraries, and put them next to the executable so that the user only has to untar the folder and launch executable without any installation ?

Static linking is not an option here as I will have a bunch of executables that will use the same boost libraries, and there may also be some license issues with statically linking against libgcc.

2
I have found a script to copy the needed dependencies h3manth.com/content/copying-shared-library-dependencies Manually deployed (putting the so next to the executable), but launching is not easy. First we must remove the standard dependencies, then chmod 711 *, then setting the ld_library_path to the folder where there is the application and the shared libraries. In the end program runs but it's not user friendly. Can anyone advice for user-friendly deployment?darkblue
Answering partly my own comment, by using set( CMAKE_EXE_LINKER_FLAGS "-Wl,-rpath='$ORIGIN' ") it seems there is no longer the need to set the ld_library_path I still need to remove linux-vdso.so, libpthread.so, libstdc++.so libgcc_s.so libc.so librt.so libm.so to get it to run. Though it works on my machines (ubuntu 12.04 and ubuntu 14.04), I 'm not sure it will work on any same architecture linux flavor.darkblue
It seems that the line set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) is also necessary in addition to set( CMAKE_EXE_LINKER_FLAGS "-Wl,-rpath='$ORIGIN' ")Guillaume Pascal

2 Answers

1
votes

on Ubuntu, perhaps standard way to packaging is following the DEBIAN rules:

Instead of re-distribute so files, specify dependency by setting CPACK_DEBIAN_PACKAGE_DEPENDS before include CPack, take look at this example:

https://github.com/thomas-moulard/visp-deb/blob/master/CMakeModules/CPackConfigDeb.cmake

dpkg will install dependent packages automatically for you.

0
votes

It is perfectly valid to try to include the needed libraries inside the distribution package.

The way I do this, in the cmake file, is by extracting the libraries names from the executable with ldd, then resolving links and then copying the results into my package:

Extract library names from executable

execute_process(  # Get interesting dynamic libraries from binary
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin
    COMMAND ldd ${APPLICATION_NAME}
    COMMAND nawk "{print $3}"
    COMMAND sort -u
    COMMAND egrep "std|boost|ssl|crypto|z|mysql|sqlite" # Only libs I want to copy
    OUTPUT_VARIABLE INSTALL_FILES
    ERROR_VARIABLE INSTALL_FILES_ERROR
    OUTPUT_STRIP_TRAILING_WHITESPACE
    )

string(REGEX REPLACE "\n" ";" INSTALL_FILES "${INSTALL_FILES}") # Convert into list

message(" ----> ${INSTALL_FILES}")

if (${INSTALL_FILES_ERROR})
    message("----> ${INSTALL_FILES_ERROR}")
endif (${INSTALL_FILES_ERROR})

Resolve links

foreach (_file ${INSTALL_FILES}) # Resolve links
    get_filename_component(_resolvedFile "${_file}" REALPATH)
    list (APPEND INSTALL_RESOLVED_FILES ${_resolvedFile} )
endforeach()

Copy libraries into package

install(FILES                               # Copy all libraries and symlinks pointing to real paths
    ${INSTALL_FILES}
    DESTINATION "${PROJECT_VERSION}/lib/"
    COMPONENT core
    )
install(FILES                               # Copy all libraries real paths
    ${INSTALL_RESOLVED_FILES}
    DESTINATION "${PROJECT_VERSION}/lib/"
    COMPONENT core
    )