CMake 将依赖项复制到可执行输出路径
CMake copy dependencies to executable output path
我有以下简单的 CMake 项目。它基本上是一个动态链接到 Qt Widgets 的可执行文件(我以 Qt 为例)。我想弄清楚的是是否可以使用 CMake 将所有链接库(不仅是当前项目构建的链接库)复制到可执行输出目录。
cmake_minimum_required(VERSION 3.12)
project(MyProject)
set(CMAKE_CXX_STANDARD 14)
set(QT_CMAKE_DIR "/Users/huser/Qt/5.11.1/clang_64/lib/cmake")
set(CMAKE_PREFIX_PATH ${CMAKE_MODULE_PATH} ${QT_CMAKE_DIR})
find_package(Qt5 REQUIRED COMPONENTS Widgets)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/build)
问题是输出目录只包含 MyProject 可执行文件(这是预期的行为)。但是,如果我将该可执行文件分发给未安装 Qt 的人,他们将无法打开它。因此,我只想将必要的库/框架与可执行文件捆绑在一起。
运行 otool -L MyProject
列出依赖项:
MyProject:
@rpath/QtWidgets.framework/Versions/5/QtWidgets
@rpath/QtGui.framework/Versions/5/QtGui
@rpath/QtCore.framework/Versions/5/QtCore
/usr/lib/libc++.1.dylib
/usr/lib/libSystem.B.dylib
我正在寻找的是通过 CMake 在构建步骤后立即将这 3 个框架复制到输出目录中的常用方法。这将导致以下目录结构:
build/
MyProject
QtWidgets.framework
QtGui.framework
QtCore.framework
如有任何帮助,我们将不胜感激!
有两个方面需要考虑:
- 构建树
- 安装树
构建树是您作为开发人员使用的,安装树是 "created" 在执行 install
目标或提取包内容后的内容。
要重新分发基于 Qt5 的项目,我建议您利用两个工具:
- CPack:这允许创建可以分发给用户的生成包或存档。其中包括 windows 个安装程序、
.tar,gz
、.dmg
、...
- macdeployqt:Qt 提供的工具允许复制您的应用程序所需的所有库、插件...。
使用 BundleUtilities
仍然需要您明确识别并安装所有 Qt 插件。对于更复杂的应用程序,具有 Qt 以外的依赖项,确实很有帮助,但对于简单的应用程序,我建议使用下面描述的方法。
您将在下面找到示例的修改版本,其中包括一些关于最佳实践以及 CPack 与 macdeployqt
集成的建议。
配置和构建项目后,构建 Package
目标将创建一个 MyProject-0.1.1-Darwin.dmg
包。
请注意,还需要做更多工作,但这应该是一个很好的起点。
阅读以下内容可能也会有所帮助:https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling
要配置项目,请考虑传递变量 -DQt5_DIR:PATH=/path/to/lib/cmake/Qt5
而不是对路径进行硬编码。
假设源代码或项目位于名为 src
的目录中,您将配置项目:
mkdir build
cd build
cmake -DQt5_DIR:PATH=/Volumes/Dashboards/Support/Qt5.9.1/5.9.1/clang_64/lib/cmake/Qt5 ../src/
src/CMakeLists.txt
:
cmake_minimum_required(VERSION 3.12)
project(MyProject)
set(CMAKE_CXX_STANDARD 14)
# Suggestions:
# (1) EXECUTABLE_OUTPUT_PATH is deprecated, consider
# setting the CMAKE_*_OUTPUT_DIRECTORY variables
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_MACOSX_BUNDLE 1)
set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks")
# Suggestions:
# (1) Do not hardcode path to Qt installation
# (2) Configure the project specifying -DQt5_DIR
# See https://blog.kitware.com/cmake-finding-qt5-the-right-way/
# (3) By convention, "REQUIRED" is added at the end
find_package(Qt5 COMPONENTS Widgets REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets)
install(TARGETS ${PROJECT_NAME} DESTINATION . COMPONENT Runtime)
# Get reference to deployqt
get_target_property(uic_location Qt5::uic IMPORTED_LOCATION)
get_filename_component( _dir ${uic_location} DIRECTORY)
set(deployqt "${_dir}/macdeployqt")
if(NOT EXISTS ${deployqt})
message(FATAL_ERROR "Failed to locate deployqt executable: [${deployqt}]")
endif()
# Execute deployqt during package creation
# See https://doc.qt.io/qt-5/osx-deployment.html#macdeploy
install(CODE "set(deployqt \"${deployqt}\")" COMPONENT Runtime)
install(CODE [===[
execute_process(COMMAND "${deployqt}" "${CMAKE_INSTALL_PREFIX}/MyProject.app")
]===] COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
include(CPack)
我有以下简单的 CMake 项目。它基本上是一个动态链接到 Qt Widgets 的可执行文件(我以 Qt 为例)。我想弄清楚的是是否可以使用 CMake 将所有链接库(不仅是当前项目构建的链接库)复制到可执行输出目录。
cmake_minimum_required(VERSION 3.12)
project(MyProject)
set(CMAKE_CXX_STANDARD 14)
set(QT_CMAKE_DIR "/Users/huser/Qt/5.11.1/clang_64/lib/cmake")
set(CMAKE_PREFIX_PATH ${CMAKE_MODULE_PATH} ${QT_CMAKE_DIR})
find_package(Qt5 REQUIRED COMPONENTS Widgets)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_LIST_DIR}/build)
问题是输出目录只包含 MyProject 可执行文件(这是预期的行为)。但是,如果我将该可执行文件分发给未安装 Qt 的人,他们将无法打开它。因此,我只想将必要的库/框架与可执行文件捆绑在一起。
运行 otool -L MyProject
列出依赖项:
MyProject:
@rpath/QtWidgets.framework/Versions/5/QtWidgets
@rpath/QtGui.framework/Versions/5/QtGui
@rpath/QtCore.framework/Versions/5/QtCore
/usr/lib/libc++.1.dylib
/usr/lib/libSystem.B.dylib
我正在寻找的是通过 CMake 在构建步骤后立即将这 3 个框架复制到输出目录中的常用方法。这将导致以下目录结构:
build/
MyProject
QtWidgets.framework
QtGui.framework
QtCore.framework
如有任何帮助,我们将不胜感激!
有两个方面需要考虑:
- 构建树
- 安装树
构建树是您作为开发人员使用的,安装树是 "created" 在执行 install
目标或提取包内容后的内容。
要重新分发基于 Qt5 的项目,我建议您利用两个工具:
- CPack:这允许创建可以分发给用户的生成包或存档。其中包括 windows 个安装程序、
.tar,gz
、.dmg
、... - macdeployqt:Qt 提供的工具允许复制您的应用程序所需的所有库、插件...。
使用 BundleUtilities
仍然需要您明确识别并安装所有 Qt 插件。对于更复杂的应用程序,具有 Qt 以外的依赖项,确实很有帮助,但对于简单的应用程序,我建议使用下面描述的方法。
您将在下面找到示例的修改版本,其中包括一些关于最佳实践以及 CPack 与 macdeployqt
集成的建议。
配置和构建项目后,构建 Package
目标将创建一个 MyProject-0.1.1-Darwin.dmg
包。
请注意,还需要做更多工作,但这应该是一个很好的起点。
阅读以下内容可能也会有所帮助:https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/RPATH-handling
要配置项目,请考虑传递变量 -DQt5_DIR:PATH=/path/to/lib/cmake/Qt5
而不是对路径进行硬编码。
假设源代码或项目位于名为 src
的目录中,您将配置项目:
mkdir build
cd build
cmake -DQt5_DIR:PATH=/Volumes/Dashboards/Support/Qt5.9.1/5.9.1/clang_64/lib/cmake/Qt5 ../src/
src/CMakeLists.txt
:
cmake_minimum_required(VERSION 3.12)
project(MyProject)
set(CMAKE_CXX_STANDARD 14)
# Suggestions:
# (1) EXECUTABLE_OUTPUT_PATH is deprecated, consider
# setting the CMAKE_*_OUTPUT_DIRECTORY variables
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(CMAKE_MACOSX_BUNDLE 1)
set(CMAKE_INSTALL_RPATH "@executable_path/../Frameworks")
# Suggestions:
# (1) Do not hardcode path to Qt installation
# (2) Configure the project specifying -DQt5_DIR
# See https://blog.kitware.com/cmake-finding-qt5-the-right-way/
# (3) By convention, "REQUIRED" is added at the end
find_package(Qt5 COMPONENTS Widgets REQUIRED)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Widgets)
install(TARGETS ${PROJECT_NAME} DESTINATION . COMPONENT Runtime)
# Get reference to deployqt
get_target_property(uic_location Qt5::uic IMPORTED_LOCATION)
get_filename_component( _dir ${uic_location} DIRECTORY)
set(deployqt "${_dir}/macdeployqt")
if(NOT EXISTS ${deployqt})
message(FATAL_ERROR "Failed to locate deployqt executable: [${deployqt}]")
endif()
# Execute deployqt during package creation
# See https://doc.qt.io/qt-5/osx-deployment.html#macdeploy
install(CODE "set(deployqt \"${deployqt}\")" COMPONENT Runtime)
install(CODE [===[
execute_process(COMMAND "${deployqt}" "${CMAKE_INSTALL_PREFIX}/MyProject.app")
]===] COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
include(CPack)