构建一个可移植的可执行文件及其依赖项
Build a portable executable with its dependencies
我想构建一个可执行文件,在确定的相对路径中查找其依赖项。换句话说,我想分发一个包含 2 个元素的 zip:一个可执行文件和一个包含共享库的文件夹。可执行文件必须能够在 运行 时找到那些共享库。
我测试了什么
现在,我用 cmake
编译了项目。我正在使用 cmake 的命令 find_library
来查找 abs。依赖项的路径。
这是 CMakeLists.txt 文件:
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)
...
表示其余同上,只是序号变了
例如,VFC_LIB1 AND VFC_LIB2 ... AND VFC_LIB16
表示总是 VFC_LIBx
,其中 x
是从 3 到 15。
探测器
问题是 find_library
用于获取绝对路径(我已经读过),所以这不允许我将可执行文件复制粘贴到其他计算机并且仍然能够 运行它。
我需要的是找到具有相对路径的库,或其他等效解决方案。
编辑
我试图用所有库 "inside it" 制作一个 "big" 可执行文件。为此,我读到我必须 link 静态库。我重新编译了构建静态库的 OpenCV(现在我有了 *.a 文件和 *.so 文件。
我更改了 CMakeLists.txt 以添加这些静态库:
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} )
cmake
命令 运行 没问题,但是当我尝试 make
项目时,我遇到了很多错误。实际上,这似乎只是一个错误,但已多次回复。这个错误是:statically linked applications requires at runtime the shared libraries from the glibc version used for linking
这是错误列表,避免了类似的错误:(如果完整列表可能有帮助,请告诉我,我会上传)
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
编辑 2
我已经测试了仅使用静态库 (*.a) 重新安装 OpenCV 并使用默认的 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} )
我可以全部编译,甚至可以执行程序,但是当程序试图显示图像时出现以下错误:
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)
我安装了 apt-get install
libgtk2.0-dev
和 pkg-config
,我还下载并安装了 ATK 库(来自 http://www.linuxfromscratch.org/blfs/view/svn/x/atk.html)。
之后,我重新启动并重新运行 cmake
和make
。当我执行程序时,错误仍然存在。
在可执行文件 运行 之前,您需要一种设置库搜索路径的方法。在 Linux/Unix 上,最简单的解决方案是 shell 脚本,您可以在其中相应地设置 LD_LIBRARY_PATH。 Windows 可能有类似的机制,但我没有这方面的经验。
在这两种情况下,CMake 只会帮助您构建程序和库,它无法为您找到其他计算机上的东西。
这不是您问题的确切答案,但在您的特定情况下,我会在运行时加载库,以避免弄乱路径和加载错误的库。
在 Linux/Mac,这可以通过 dlopen(), on Windows via LoadLibrary() 完成。
在 Linux 上,可执行文件使用 RPATH 机制存储有关其库路径的信息。链接器在将可执行文件加载到内存时使用此信息。
对于库的路径 relative,有一个特殊的路径组件 $ORIGIN
,它被评估为具有可执行文件的目录。
在 CMake 中,为构建可执行文件设置 RPATH,使用变量 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})
现在,如果您将可执行文件移动(或安装)到某个目录 <dir>
并将所有库移动到目录 <dir>/lib/
,可执行文件可以是 运行.
有关 CMake 中 RPATH 处理的更多信息,请参阅 CMake wiki。
我想构建一个可执行文件,在确定的相对路径中查找其依赖项。换句话说,我想分发一个包含 2 个元素的 zip:一个可执行文件和一个包含共享库的文件夹。可执行文件必须能够在 运行 时找到那些共享库。
我测试了什么
现在,我用 cmake
编译了项目。我正在使用 cmake 的命令 find_library
来查找 abs。依赖项的路径。
这是 CMakeLists.txt 文件:
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)
...
表示其余同上,只是序号变了
例如,VFC_LIB1 AND VFC_LIB2 ... AND VFC_LIB16
表示总是 VFC_LIBx
,其中 x
是从 3 到 15。
探测器
问题是 find_library
用于获取绝对路径(我已经读过),所以这不允许我将可执行文件复制粘贴到其他计算机并且仍然能够 运行它。
我需要的是找到具有相对路径的库,或其他等效解决方案。
编辑
我试图用所有库 "inside it" 制作一个 "big" 可执行文件。为此,我读到我必须 link 静态库。我重新编译了构建静态库的 OpenCV(现在我有了 *.a 文件和 *.so 文件。
我更改了 CMakeLists.txt 以添加这些静态库:
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} )
cmake
命令 运行 没问题,但是当我尝试 make
项目时,我遇到了很多错误。实际上,这似乎只是一个错误,但已多次回复。这个错误是:statically linked applications requires at runtime the shared libraries from the glibc version used for linking
这是错误列表,避免了类似的错误:(如果完整列表可能有帮助,请告诉我,我会上传)
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
编辑 2
我已经测试了仅使用静态库 (*.a) 重新安装 OpenCV 并使用默认的 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} )
我可以全部编译,甚至可以执行程序,但是当程序试图显示图像时出现以下错误:
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)
我安装了 apt-get install
libgtk2.0-dev
和 pkg-config
,我还下载并安装了 ATK 库(来自 http://www.linuxfromscratch.org/blfs/view/svn/x/atk.html)。
之后,我重新启动并重新运行 cmake
和make
。当我执行程序时,错误仍然存在。
在可执行文件 运行 之前,您需要一种设置库搜索路径的方法。在 Linux/Unix 上,最简单的解决方案是 shell 脚本,您可以在其中相应地设置 LD_LIBRARY_PATH。 Windows 可能有类似的机制,但我没有这方面的经验。
在这两种情况下,CMake 只会帮助您构建程序和库,它无法为您找到其他计算机上的东西。
这不是您问题的确切答案,但在您的特定情况下,我会在运行时加载库,以避免弄乱路径和加载错误的库。
在 Linux/Mac,这可以通过 dlopen(), on Windows via LoadLibrary() 完成。
在 Linux 上,可执行文件使用 RPATH 机制存储有关其库路径的信息。链接器在将可执行文件加载到内存时使用此信息。
对于库的路径 relative,有一个特殊的路径组件 $ORIGIN
,它被评估为具有可执行文件的目录。
在 CMake 中,为构建可执行文件设置 RPATH,使用变量 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})
现在,如果您将可执行文件移动(或安装)到某个目录 <dir>
并将所有库移动到目录 <dir>/lib/
,可执行文件可以是 运行.
有关 CMake 中 RPATH 处理的更多信息,请参阅 CMake wiki。