0095630d8b853e8c96f2959a4c1b5ac0.png

前言

使用CMake构建Qt应用十分简单方便,核心的地方是:

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

以上语句实现ui文件自动打包、自动moc预编译以及rc文件的自动打包。

接着是:

find_package(Qt5 COMPONENTS Widgets REQUIRED)

来寻找Qt的库文件,然后在可执行文件中进行链接:

target_link_libraries(RixJsonEditor PRIVATE Qt5::Widgets RixJson)

其中RixJson为之前我们写好的json解析库,而RixJsonEditor为我们要构建的目标名。

项目目录结构

整个项目的树状结构是这样的:

MyQtMultiPlatform0
|- resources
|    |- icon.icns
|    |- icon.ico
|- RixJson
|    |- CMakeLists.txt
|    |- RixJson.cpp
|    |- RixJson.h
|- CMakeLists.txt
|- DataManager.cpp
|- DataManager.h
|- Info.plist
|- main.cpp
|- MainWindow.cpp
|- MainWindow.h
|- MainWindow.ui
|- resource.qrc
|- RixJsonItemDelegate.cpp
|- RixJsonItemDelegate.h

其中,RixJson目录下为之前编写好的json解析库的源文件和头文件,里面包含了一个CMakeLists.txt用来构建以RixJson为目标的静态库。

它的内容如下:

add_library(
        RixJson
        RixJson.cpp
)

resources目录下存放的是图标文件,其中icon.icns是给mac平台用的,icon.ico是给windows平台用的。

Info.plist文件是用于构建MacOS应用时使用的,一般来说cmake在构建app包的时候会自动添加一个默认的Info.plist。但是默认的会导致Qt应用构建出来显示的界面模糊。这里的Info.plist做了一下修改:

<key>NSPrincipalClass</key>
    <string>NSApplication</string>

MainWindow.ui文件为应用的界面布局文件,使用QtDesigner编辑。

resource.qrc文件为Qt应用的资源文件,也可以使用QtDesigner编辑,这里用于配置在Windows上的窗口图标。

其余的.h/.cpp都是c++的源文件和头文件。整个项目的目录结构以及各个文件的作用就是如此了。

CMakeLists.txt的编写

第一步,给项目起名字

cmake_minimum_required(VERSION 3.5)
project(MyQtAoo LANGUAGES CXX)

这里先制定好需要使用的CMake的版本号,然后第二行指定了项目名和所使用的编程语言

第二步,检测系统并添加Qt的目录

# Detect operation system
message(STATUS "Current Operation System is ${CMAKE_SYSTEM}")
if(WIN32)
    message(STATUS "Configuring for Windows.")
    set(CMAKE_PREFIX_PATH "C:pfQt5.13.2mingw73_32")
    if(NOT EXISTS ${CMAKE_PREFIX_PATH})
        add_compile_options("-m64")
        set(CMAKE_PREFIX_PATH  "C:Qt5.13.2mingw73_64")
    endif()
endif()
if(APPLE)
    message(STATUS "Configuring for MacOS.")
    foreach(QT_POSIBLE_PATH "/usr/local/Cellar/" "~/Applications/")
        message("Finding QT_PATH in ${QT_POSIBLE_PATH}")
        find_file(QT_PATH qt PATHS ${QT_POSIBLE_PATH})
        if(EXISTS ${QT_PATH})
            message("QT_PATH:${QT_PATH} found!")
            set(CMAKE_PREFIX_PATH "${QT_PATH}/5.13.2")
            if(NOT EXISTS ${CMAKE_PREFIX_PATH}/bin)
                set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}/clang_64)
            endif()
            break()
        else()
            message("QT_PATH not found in ${QT_POSIBLE_PATH}")
        endif()
    endforeach(QT_POSIBLE_PATH)
endif()

Qt的目录一般指的是qt/版本号,即改目录下应该包含binlib等文件夹,以便cmake能使用moc预编译器等Qt特有的东西。

注意:在win平台使用mingw构建的时候要注意是64位版本的库还是32位版本的库。

第三步,检测构建配置-Debug/Release

# Detect build type
message(STATUS "Build Type: ${CMAKE_BUILD_TYPE} ")
if(CMAKE_BUILD_TYPE MATCHES Debug)
    set(DEBUG 1)
else()
    set(RELEASE 1)
endif()

用于后续判断。

第四步,Qt相关

# Cmake Configuration for Qt
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

其中倒数第二行指定了c++的标准为c++11。

第五步,添加链接指令(Windows)

# Get rip of cmd window on Windows
if(WIN32)
    add_link_options("-mwindows")
endif()

这里使用了一个链接指令来使在Windows平台编译后执行程序不是以控制台窗口的形式执行的,而是以仅仅为窗口的形式打开。(即不会出现cmd的窗口)

注意这里仅对mingw编译器有效。

第六步,添加依赖库

# Change executable output path to output dir, prepare for target RixJsonEditor
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/output)

find_package(Qt5 COMPONENTS Widgets REQUIRED)

add_subdirectory(RixJson)

这里只引入了两个库,一个是Qt的Widgets库,一个是RixJson库。

第七步,添加图标(MacOS)

if(APPLE)
    set(APPLE_ICNS_FILE ${PROJECT_SOURCE_DIR}/resources/icon.icns)
    set_source_files_properties(${APPLE_ICNS_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
endif()

第八步,指定可执行目标

add_executable(RixJsonEditor
        main.cpp
        MainWindow.cpp
        MainWindow.h
        MainWindow.ui
        DataManager.cpp
        DataManager.h
        RixJsonItemDelegate.cpp
        RixJsonItemDelegate.h
        resource.qrc
        ${APPLE_ICNS_FILE}
        )

第九步,添加Info.plist(MacOS)

if(APPLE)
    set_target_properties(RixJsonEditor PROPERTIES MACOSX_BUNDLE TRUE)
    set(PROJECT_EXECUTABLE_NAME RixJsonEditor)
    set_target_properties(RixJsonEditor PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/Info.plist) # Adding icon for mac app
endif()

第十步,链接

target_link_libraries(RixJsonEditor PRIVATE Qt5::Widgets RixJson)

第十一步,复制Qt的动态链接库

Qt的库文件是以动态链接的方式存在的,当然也可以自行编译静态库。

Qt的SDK中提供了一个程序可以根据构建好的二进制可执行文件里所引用的库文件来复制Qt里的动态链接库到该二进制可执行文件的目录下,十分方便。

该程序在Windows上叫做:windeployqt.exe

在MacOS上叫做:macdeployqt

在这两个平台上的复制动态库的方式大不一样,这里需要分开进行:

# Generated .bat to deploy dlls automatically for Windows
if(WIN32)
    if(DEBUG)
        set(DEPLOY_CONFIGURE debug)
    elseif(RELEASE)
        set(DEPLOY_CONFIGURE release)
    endif()
    set(DEPLOY_FUNC ${PROJECT_BINARY_DIR}/dlls_deployment.bat)
    file(GENERATE
            OUTPUT ${DEPLOY_FUNC}
            CONTENT
            "
echo on

:: Translate unix path to windows path
set "WIN_DEPLOY_DIR=${DEPLOY_DIR}"
set "WIN_DEPLOY_DIR=%WIN_DEPLOY_DIR:/=%"

:: Translate unix path to windows path
:: set "WIN_PROJECT_BINARY_DIR=${PROJECT_BINARY_DIR}"
:: set "WIN_PROJECT_BINARY_DIR=%WIN_PROJECT_BINARY_DIR:/=%"

:: Translate unix path to windows path
set "WIN_QT_PATH=${CMAKE_PREFIX_PATH}"
set "WIN_QT_PATH=%WIN_QT_PATH:/=%"

:: Add QT path to PATH
set PATH=%PATH%;%WIN_QT_PATH%bin

:: Create output dir if it not exists
if not exist %WIN_DEPLOY_DIR% (md  %WIN_DEPLOY_DIR%)

:: Use windeployqt.exe to copy the dependencies
windeployqt.exe %WIN_DEPLOY_DIR%RixJsonEditor.exe -force -${DEPLOY_CONFIGURE}
            "
            )

    # By adding a target indicating deploy dir and func to be cleaned
    add_custom_target(
            DeployDLLs ALL
            DEPENDS RixJsonEditor
            COMMAND echo ${DEPLOY_FUNC} && ${DEPLOY_FUNC}
            BYPRODUCTS ${DEPLOY_DIR} ${DEPLOY_FUNC}
            COMMENT "[${CMAKE_SYSTEM_PROCESSOR}] Deploying dlls for ${CMAKE_SYSTEM_NAME} platform."
    )
endif()

在Windows上,我是直接让cmake生成指定内容的bat文件,然后在构建完应用后自动执行该bat文件,而该bat文件会执行windeployqt.exe,从而达到复制动态库的目的。

# Directly execute command to deploy shared libs automatically for MacOS
if(APPLE)
    if(DEBUG)
        set(DEPLOY_CONFIGURE -use-debug-libs)
    elseif(RELEASE)
        set(DEPLOY_CONFIGURE " ")
    endif()

    # By adding a target indicating deploy dir and func to be cleaned
    add_custom_target(
            DeployDLLs ALL
            DEPENDS RixJsonEditor
            COMMAND echo
            BYPRODUCTS ${DEPLOY_DIR}
            COMMENT "[${CMAKE_SYSTEM_PROCESSOR}] Deploying dlls for ${CMAKE_SYSTEM_NAME} platform."
    )


    # No need to deploy dlls on MacOS in Debug mode
    if(RELEASE)
        add_custom_command(
                TARGET DeployDLLs
                POST_BUILD
                COMMAND ${CMAKE_PREFIX_PATH}/bin/macdeployqt ${DEPLOY_DIR}/RixJsonEditor.app -always-overwrite -dmg
        )
    endif()
endif()

在macos上则直接执行macdeployqt来进行动态库的复制,同时能打包成dmg文件。

注意:macos上若是debug模式则不需要复制动态库,这是由于macos平台上动态库的链接方式导致的神秘现象。

执行cmake,构建应用

使用在项目根下新建cbuild目录,然后在该目录下使用一下指令:

cmake -DCMAKE_BUILD_TYPE=Debug -G "CodeBlocks - Unix Makefiles" ..

该指令会在cbuild的目录下生成makefile文件。

注意:使用参数-DCMAKE_BUILD_TYPE=Debug来指定构建的是Debug版本,使用参数-DCMAKE_BUILD_TYPE=Release则可以构建Release版本。

然后使用以下指令进行编译:

cmake --build . --target RixJsonEditor

编译成功后,在该目录下的output文件夹里生成可执行文件(Windows是exe文件,MacOS是app文件夹以及dmg文件)

278a2a199b1f0586c3cbcac78e49f1b2.png
当然,我们还没有正式开始写代码,所以现在还不能构建任何东西。。。

后语

使用CMake构建Qt应用就是如此简单方便啦,这里推荐一下Clion,这个ide超好用!

接下来应该是ui界面的搭建。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐