使用CMake部署Qt應用程式

2021-02-20 軟體工程師之路

Qt應用程式在運行時依賴於動態連結庫以及資源文件,在調試和生成Qt安裝包時都需要進行處理,否則經常出現本地運行可以,而在客戶電腦上不行的場景.

這時,保持開發者本地環境和真實運行環境一致是比較好的實踐.即:

不使用專門的IDE及插件(例如Qt Visual Studio Tools).

這種情況下CMake是比較好的選擇,這時就需要解決調試時部署Qt運行時的問題:

好在Qt在Windows上提供了windeployqt來幫助開發者.那麼如何整合到CMakeLists中呢?

工程構建結果的部署

工程構建結果包含構造出來的exe、dll、qm以及其它資源文件.CMake默認會配置exe、dll等內容的輸出目錄,而資源文件是需要開發者自行處理的.這裡也分兩種場景來處理:

調整運行時輸出位置

在CMake中 exe、dll等被成為運行時(runtime),通過指定CMAKE_RUNTIME_OUTPUT_DIRECTORY可以調整其輸出位置,假設要根據不同的配置(Debug、Release等)輸出到構建目錄,則在工程的主CMakeLists.txt中通過這種方式定義:

if(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>")
endif()

拷貝資源到輸出位置

要執行這一操作,首先要獲取輸出位置,假設你為庫或者應用程式定義的target名稱為TARGET_NAME,通過如下指令可以獲取輸出位置:

$<TARGET_FILE_DIR:TARGET_NAME>

qm文件的路徑存儲在TARGET_NAME_QM_FILE變量中,那麼可以以如下命令完成目錄創建、翻譯文件拷貝動作:

## 複製資源文件
add_custom_command(TARGET TARGET_NAME POST_BUILD
## 創建翻譯文件目錄
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:TARGET_NAME>/translations/
## 翻譯文件
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TARGET_NAME_QM_FILE} $<TARGET_FILE_DIR:TARGET_NAME>/translations/
)

拷貝資源文件也是相同的處理方式,假設在CMakeLists.txt同目錄下有data文件夾存儲了運行時資源,拷貝命令為:

## 複製資源文件
add_custom_command(TARGET TARGET_NAME POST_BUILD
## 複製數據
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/data/ $<TARGET_FILE_DIR:TARGET_NAME>/
)

這裡建議你將庫、應用程式的name定義為變量,這樣碰見相同場景直接複製上述代碼即可,例如:

## 複製資源文件
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
## 複製數據
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/data/ $<TARGET_FILE_DIR:${TARGET_NAME}>/
## 創建翻譯文件目錄
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${TARGET_NAME}>/translations/
## 翻譯文件
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${${TARGET_NAME}_QM_FILE} $<TARGET_FILE_DIR:${TARGET_NAME}>/translations/
)

另外,TS以及QM文件均可以自動生成,CMake中寫法如下:

##查找Qt翻譯家
find_package(Qt5LinguistTools)
##創建TS文件並提供qm生成
qt5_create_translation(${TARGET_NAME}_QM_FILE
${${TARGET_NAME}_HEADER_FILES} #所有頭文件
${${TARGET_NAME}_SRC_FILES} #所有源文件
${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_zh.ts #生成的ts文件完整路徑
)

Qt運行時及資源部署

經過上述操作,應用程式自身內容的部署就已經完成.而Qt的部署鑑於有windeployqt,可以實現得相對簡單且通用.

基本思路

定義DeployQtRuntime.cmake,包含DeployQtRuntime函數,能夠處理各種Qt運行時及資源部署場景.該函數具備如下能力:

函數使用方式如下:

DeployQtRuntime(
TARGET YourTargetName
WebEngine #部署WebEngine
QmlFilesPath "工程qml文件路徑,供windeployqt掃描"
PLUGINS "xml;svg"
)

在工程的主CMakeLists.txt中要將DeployQtRuntime.cmake所在路徑添加到CMAKE_MODULE_PATH中,例如:

## 配置本地cmake腳本路徑
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(DeployQtRuntime)

函數聲明
include(CMakeParseArguments)

## 部署Qt運行時及插件
function(DeployQtRuntime)
set(options WebEngine)
set(oneValueArgs TARGET QmlFilesPath)
set(multiValueArgs PLUGINS)
cmake_parse_arguments(Gen "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

endfunction()

CMakeParseArguments為CMake提供的參數解析輔助函數,上述聲明會將參數解析成為Gen_開頭的變量供後續使用.

查找windeployqt
find_package(Qt5 COMPONENTS Core CONFIG)

#加載Qt5::Core對應的庫配置文件,能夠找到Qt的bin目錄
if(NOT _qt5_install_prefix)
return()
endif()

## message(STATUS "Qt cmake模塊位於:${_qt5_install_prefix}")
## _qt5_install_prefix基本上在lib/cmake位置,需要定位到bin路徑下面找到部署程序
find_program(__qt5_deploy windeployqt PATHS "${_qt5_install_prefix}/../../bin")

## 獲取QTDIR
set(QTDIR "${_qt5_install_prefix}/../../")

插件參數格式處理

Gen_PLUGINS要拆分成一個個插件,然後加上-前綴,並且在WINDOWS下還要調整以下參數樣式:

set(qt_plugins "")
foreach(__plugin ${Gen_PLUGINS})
string(APPEND qt_plugins " -${__plugin}")
endforeach()
separate_arguments(qt_plugins_list WINDOWS_COMMAND ${qt_plugins})

調用windeployqt

qml默認掃描路逕取自target輸出路徑:

set(QmlFilesPath "$<TARGET_FILE_DIR:${Gen_TARGET}>")
if(Gen_QmlFilesPath)
#如果用戶設置了qml文件路徑則直接使用
set(QmlFilesPath "${Gen_QmlFilesPath}")
endif()

add_custom_command(TARGET ${Gen_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env QTDIR="${QTDIR}" "PATH=${QTDIR}/bin" windeployqt.exe --qmldir ${QmlFilesPath} $<TARGET_FILE:${Gen_TARGET}> ${qt_plugins_list}
COMMENT "deploy Qt runtime dependencies"
)

注意上述命令在執行過程中,調整了環境變量QTDIR,這是因為用戶的環境下可能配置了QTDIR,會導致執行了環境變量配置中的windeployqt.exe,從而導致錯誤.

處理WebEngine運行時

由於WebEngine運行需要一些特殊的資源文件以及QtWebEngineProcess,需要專門處理:

## Qt如果部署包含Qt WebEngine的應用,需要處理無法自動部署的資源
if(Gen_WebEngine)
add_custom_command(TARGET ${Gen_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${_qt5_install_prefix}/../../resources/" ##拷貝 resources 目錄下內容
"$<TARGET_FILE_DIR:${Gen_TARGET}>"
COMMENT "deploy Qt WebEngine resources"

COMMAND ${CMAKE_COMMAND} -E copy "${_qt5_install_prefix}/../../bin/$<IF:$<CONFIG:DEBUG>,QtWebEngineProcessd.exe,QtWebEngineProcess.exe>"
"$<TARGET_FILE_DIR:${Gen_TARGET}>/$<IF:$<CONFIG:DEBUG>,QtWebEngineProcessd.exe,QtWebEngineProcess.exe>"
COMMENT "deploy Qt WebEngine process"
)
endif()

相關焦點

  • LibreCAD的CMake構建
    Qt配置方式在根目錄將Qt所在路徑添加到CMAKE_PREFIX_PATH變量中,類似於:##如何使用CMake配置Qt參見以下連結##https://doc.qt.io/qt-5/cmake-get-started.htmllist(APPEND CMAKE_PREFIX_PATH "E:/
  • Qt for MCUs 快速上手實踐
    配置Qt Creator桌面開發環境要在MCUs上構建和運行你的應用程式,你必須創建一個工具包(Kit):Tools這裡使用後者。A: 原因是這樣,QUL在目標MCU上運行並不依賴經典Qt,但是我們需要依賴它來構建主機(Host)環境工具,例如QML編譯器、字體編譯器以及在windows上運行應用預覽的工具等。
  • cmake簡介
    自動構建系統自動構建系統是一種能夠自動完成原始碼的編譯,打包,單元測試,部署等工作的軟體,具體定義可以參考維基百科。通過這種方式,cmake實現了跨平臺。關於cmake支持生成的目標構建文件可以參考官方網站3.1 cmake操作介紹cmake有很多種使用方法,比如說命令行,交互式命令行等等。cmake同時也附帶一個用qt寫的圖形界面工具,在windows和linux下都可以使用,本節將著重介紹圖形工具的使用。
  • 在Visual Studio中進行Qt Quick應用程式的嵌入式開發(一)
    本文我們將展示如何使用此功能在Visual Studio中進行Qt Quick應用程式的嵌入式開發。編譯好Qt庫後,我們就可以在目標板上編譯運行應用程式。選擇「文件」>「新建」>「項目」以打開「 Visual Studio」對話框以創建新項目在項目模板搜索中輸入「 qt」,然後選擇「 Qt Quick Application」按「下一步」;提供項目的名稱和位置,然後按「創建」。Qt Quick應用程式嚮導對話框將打開。按下一步進行配置設置。
  • CMake的安裝及簡單使用
    因此,對於大多數項目,應當考慮使用更自動化一些的 cmake或者autotools來生成makefile,而不是上來就動手編寫。總之,項目構建工具能夠幫我們在不同平臺上更好地組織和管理我們的代碼及其編譯過程,這是我們使用它的主要原因。cmake的主要特點cmake和autotools是不同的項目管理工具,有各自的特點和用戶群。
  • OpenCV開發筆記(〇):使用mingw530_32編譯openCV3.4.1源碼,搭建Qt5.9.3的openCV開發環境
    到官網下載最新版本的CMake:https://cmake.org/download/  因為官網下載太慢,我們到其他地方下一個版本3.10,百度自己下載。  使用命令行,輸入cmake–version查看,顯示版本號表示添加路徑成功。第二步:下載openCV3.4.1。下載源碼,目前最新的版本,我們使用源碼編譯,編譯源碼這是作為使用開源庫的基本技能。
  • Windows 下 Qt creator安裝和使用
    擴展性強、漂亮好用、跨平臺,推薦web開發者做C++一.qt  creator  QT裡面有一個概念非常重要,主要是構建套件。它提供的是一整套的軟體,你可以把它看作一個容器,這個容器裡可以安裝很多個kits,每一套kits對應一個平臺,當你用C++編寫了一個源程序,一個源程序將來用不同的kit可以構建出來不同的程序,這個不同的程序可以到不同的平臺去運行,假如說裝了裝了一個32位windous的kits。
  • 在Visual Studio中進行Qt Quick應用程式的嵌入式開發(二)
    現在,我們將展示如何在嵌入式設備上運行該應用程式。 然後,我們繼續完善該項目。 最後,我們將使用VS調試器對應用程式的C ++和QML代碼在嵌入式設備上運行並進行遠程調試。我們已經展示了如何交叉編譯在Visual Studio中創建的「 hello world」 Qt Quick應用程式。 現在,我們將看到如何在Raspberry Pi上運行該應用程式。
  • Cmake 入門簡介
    CMake自動生成的Makefile不僅可以通過make命令構建項目生成目標文件,還支持安裝(make install)、測試安裝的程序是否能正確執行(make test,或者ctest)、生成當前平臺的安裝包(make package)、生成源碼包(make package_source)、產生Dashboard顯示數據並上傳等高級功能,只要在CMakeLists.txt中簡單配置,就可以完成很多複雜的功能
  • cmake使用指南
    當我們寫C/C++之後,程序必須經過編譯,形成.o或者.obj文件,然後經過連結才能形成可執行文件。常見的編譯器包括gcc等,都可以將C/C++文件進行編譯。但是當工程量比較大的時候,不方便對每個文件都執行編譯。於是就有了很多管理構建工具來幫助你進行編譯連結龐大的項目。
  • Ubuntu 18.04下安裝最新CMake及CMake簡單使用
    ── share    ├── aclocal    ├── applications    ├── cmake-3.9    ├── icons    └── mime12 directories, 5 filesbin下面有各種cmake家族的產品程序。
  • 協程與Qt信號的整合實現
    業務場景這裡要用Qt實現具備如下功能的應用程式:實現思路首先建立開發環境,實現對應的窗體類,提供滑鼠點擊、線創建兩個信號,以及改變顏色、繪製線兩個槽.然後提供協程的Promise-Task類型,用來作為協程的返回值.
  • linux | cmake的快速使用
    開源項目OpenCV就是使用CMake作為項目架構系統的。當項目文件比較多時,相比於手寫makeflie和使用autotools,使用CMake來自動化構建生成makefile方便多了!安裝CMake$ sudo apt-get install cmake#檢測安裝是否成功$ cmake --version  源碼連結:https://github.com/jiejieTop/cmake使用流程CMake工具使用一個名為CMakeLists.txt
  • 為Raspberry Pi開發Qt應用程式
    本教程介紹了如何在Visual Studio中為Raspberry Pi開發Qt應用程式。
  • Qt實現 結合opencv播放視頻
    2、效果圖本項目實現了通過opencv+qt播放視頻的功能。其中用qt製作前端,opencv負責處理視頻的解碼過程。打開cmake,編譯源碼出庫。cmake下載地址:https://cmake.org/download/因為我的vs是2015,然後本次的項目是基於x64編譯的,所以勾選的是以上。
  • 【Qt開發】第一個Qt程序Hello World!
    一:說在前頭我的第一份工作是做生產工具,當時用的MFC,IDE是VC6.0,現在想想真是古董級別,10年至今,微軟也一直沒有對MFC進行升級,冥冥中感覺微軟自己都放棄MFC了,市場上貌似MFC的崗位越來越少了,基本上也都是原先的項目維護,qt
  • Android NDK開發掃盲及最新CMake的編譯使用
    (也是 Android 現在主推的)ABI是什麼ABI(Application binary interface)應用程式二進位接口。不同的 CPU 與指令集的每種組合都有定義的 ABI (應用程式二進位接口),一段程序只有遵循這個接口規範才能在該 CPU 上運行,所以同樣的程序代碼為了兼容多個不同的 CPU,需要為不同的 ABI 構建不同的庫文件。當然對於 CPU 來說,不同的架構並不意味著一定互不兼容。
  • 使用 K8S、Docker 測試和部署 Node.js 應用程式
    作者:Joyce Lin編譯:小君君(才雲)技術校對:星空下的文仔(才雲)、bot(才雲)如今,隨著雲應用程式複雜性的增加,很多研發團隊開始將應用程式部署為分布式微服務架構,以此來加快軟體交付。工程師們也在一直尋找簡化和自動化持續部署代碼的方法。
  • CMakeList.txt在SLAM常用庫中應用
    2)利用現成的庫:只需要建立頭文件,說明怎麼使用即可.OpenCV_LIBS} ) #連結OpenCV庫二、大型文件1、我們的目標是:寫一個VO庫myslam庫,這個庫需要自己寫在include裡的.cpp五大類以及一些第三方庫Eigen、OpenCV、Sophus、G2O之後需要測試程序生成執行文件
  • CMake基礎入門和使用
    在 linux 平臺下使用 CMake 生成 Makefile 並編譯的流程如下: 1)編寫 CmakeLists.txt。 2)執行命令「cmake PATH」或者「ccmake PATH」生成 Makefile ( PATH 是 CMakeLists.txt 所在的目錄 )。 3)使用 make 命令進行編譯。