首页 > 编程语言 >从零编译 Qt 源码

从零编译 Qt 源码

时间:2023-04-15 15:44:06浏览次数:51  
标签:... CMake Qt 编译 源码 构建 build Ninja

写在前头

为了保证流程可复现,本文档展示的编译全过程在 Windows 10 提供的沙盒中进行。

Linux 安装 Qt 想必都不会有什么问题,所以本文讲的其实是 Windows 上如何从零编译 Qt 源码。此处的 Qt 源码指的是 Qt 这个第三库本身,所以想找怎么编译自己写的 Qt 项目的可以到此为止了。

严格来说,跟着 Qt 源码下的 README.md 提供的项目构建流程走是完全没问题的,但是奈何构建过程中多多少少总会出现一些奇奇怪怪的问题,所以才出了这么一篇文档走个还算完整的形式。

获取源码

Qt 源码下载地址

选择需要编译的 Qt 版本,下载对应的源码包。方便起见,本文直接下载 single 包。

single 包含 Qt 的全部子模块,其中 WebEngine 的大小占 ~75%,如果只是简单使用并且不需要使用浏览器引擎部分的功能的话,可以考虑在 submodules 单独下载 base 模块及其它需要的子模块。

本文以编译 Qt 6.5.0 为例,其它版本类似。

源码下载完成后,解压至任意目录。

下文以 $devel 表示源码解压的目标目录,如图所示,在本文中 $devel~/Desktop/qt-everywhere-src-6.5.0

image

获取构建工具链

首先的首先,拉完项目先读 README.md

Qt 的 README.md 中开门见山地说明了如何构建项目,如 Qt 6.5.0 中就提及了以下构建项目的必需品

* C++ compiler supporting the C++17 standard
* CMake 3.16 or newer
* Ninja 1.8 or newer
* Python 3

当然还有一个 For more details, see also https://doc.qt.io/qt-6/build-sources.html

获取编译工具链

C++ compiler ... 为使用的编译工具链,Windows 上可以使用的主要有 MSVC,MinGW-w64 系列。使用何种编译器在很大程度上会影响最终生成何种 Qt 库。由于几家默认使用的标准库不同,编译过程链接入 Qt 的库也不一致。假定选择使用 LLVM-MinGW 编译,那么 Qt 所使用的便是 libc++。此时当后期混用 MinGW-w64+GCC 编译自己的 Qt 项目并链接该 Qt 库时,若不能保证目标执行程序链接了正确的动态链接库,则极大可能导致程序在进入 main 之前便崩溃退出。

使用何种编译器根据自己的需求而定,但需要保证编译器支持 C++17 及以上标准。

在本文中,使用 LLVM-MinGW with 15.0.0 作为编译工具链。

正确安装并配置环境变量后,在终端中键入相关命令应该可以看到以下类似信息:

$ clang++ --version

clang version 15.0.0 (https://github.com/llvm/llvm-project.git 4ba6a9c9f65bbc8bd06e3652cb20fd4dfc846137)
Target: x86_64-w64-windows-gnu
Thread model: posix
InstalledDir: E:/DevEnvr/usr/local/llvm-mingw-20220906-ucrt-x86_64/bin

MinGW-w64 系列预编译包下载地址

LLVM-MinGW 下载地址

获取 CMake

CMake 是一个项目构建工具。用极简且不甚准确的话来说,它是一个允许你以亿点点配置的代价靠一行命令构建所有项目的工具。

好消息是,配置文件是项目维护者写的,我们只需要运行那一行命令就行。坏消息是,写自己的项目想用 CMake 的话……

正确安装并配置环境变量(安装版无需配置)后,在终端中键入相关命令应该可以看到以下类似信息:

$ cmake --version

cmake version 3.25.0

CMake suite maintained and supported by Kitware (kitware.com/cmake).

CMake 下载地址

获取 Ninja

Ninja 同 make 一样是一个构建系统,一个区别在于前者相较于后者具有更精简可读的语法。此处将两者统称为构建系统后端。

构建系统,简而言之就是分析构建目标依赖关系,决定构建命令执行顺序的控制系统。

一个可能的组织是 CMake -> Ninja -> GCC,在这个例子中,GCC 工具链充当 Ninja 的构建工具后端,Ninja 充当 CMake 的构建系统后端。构建一个由 CMake 管理的项目时,一般的顺序是由 CMake 配置生成 Ninja 配置文件,再由 CMake 驱动 Ninja 进行实际的项目构建,Ninja 则驱动默认或配置的构建工具进行实际的编译工作。

CMake 指定 Ninja 为后端进行项目配置

cmake -B build -S . -G Ninja

从 CMake 根据已配置的后端构建所有目标

cmake --build build

直接使用 Ninja 构建所有目标

ninja -C build

一般而言,构建系统的选择不会影响最终目标的生成。然而 Qt 在项目配置中明确指定 Ninja 作为编译后端,为了避免不必要的麻烦产生,此处考虑听从建议安装 Ninja。

正确安装并配置环境变量后,在终端中键入相关命令应该可以看到以下类似信息:

$ ninja --version

1.11.1

Ninja 下载地址

获取 Python 3

对于编程的人来说,Python 想必不是什么稀奇的东西。Python 作为一种便携式的解释型语言,也常参与到项目的配置甚至构建中来。

在 Qt 中,Python 则主要用于相关配置信息的生成。

正确安装并配置环境变量(安装版无需配置)后,在终端中键入相关命令应该可以看到以下类似信息:

$ python --version

Python 3.11.0

Python 下载地址

项目配置

从该步骤开始,正式进行 Qt 源码的编译。在开始前,首先进入终端切入 Qt 源码的根目录

cd $devel

注意前文,此处 $devel 指源码解压的目标目录

configure.bat 是 Qt 用于 Windows 下的项目配置脚本。由于 README.md 中提供的信息有限,所以可以依靠以下命令获取具体的项目构建配置提示

configure -help

根据需求阅读 help 信息,下面会给出一些常用的配置选项


部署路径

-prefix <dir> ... 指定构建完成后 Qt 的安装路径,默认为 `/usr/local/Qt-$QT_VERSION`

构建版本

-release ... Release 版本(默认)

-debug ... Debug 版本

-debug-and-release ... Release & Debug 双版本(Windows 默认)

-optimize-debug ... 启用 Debug 版本的优化

-optimize-size ... 启用 Release 版本的优化

-force-debug-info ... 强制创建 Release 版本的调试信息

链接库类型

-shared ... 生成动态链接库(默认)

-static ... 生成静态链接库

构建目标

-submodules <repo>[,<repo>] ... 指定需要构建的子模块(自动包含模块的依赖项)

-skip <repo>[,<repo>] ... 指定不参与构建的子模块

-gui ... 构建 Qt GUI 模块及依赖项

-widgets ... 构建 Qt Widgets 模块及依赖项

-make <part> ... 指定需要参与构建的部分,包括 libs, tools, examples, tests, benchmarks, manual-tests, minimal-static-tests,默认为 libs, examples

-nomake <part> ... 指定不参与构建的部分,可选值同上

配置样例

指定构建的模块

  • Qt Widgets
  • Qt GUI

指定构建的部分

  • libs
  • examples
  • tools

指定构建的库类型

  • 动态链接库

指定构建的版本

  • Release
  • Debug

指定 CMake 的构建目录

  • $devel/build

指定部署路径

  • ~/Desktop/Qt-6

最终的配置命令

configure ^
    -prefix ~/Desktop/Qt-6 ^
    -shared ^
    -widgets -gui ^
    -make tools ^
    -- -B build

configure 可以理解为是使用 CMake 进行项目配置的封装。即使不使用 configure.bat 脚本,也可以直接通过 CMake 进行项目的配置。只不过后者可能需要构建者对项目的配置细节了解得更深,否则很容易出现配置选项的遗漏、冲突、无效等错误。

项目构建

在配置样例中,指定了 $devel/build 为 CMake 的构建目录,在 $devel 下执行下列命令使用 CMake 进行项目的构建

cmake --build build

不出意外的话,除了报了一堆 WARNING 是没有错误的。

image

构建成功后继续使用 CMake 部署 Qt,使用以下命令

cmake --install build

cmake --build build --target install

构建完成的内容会被安装到配置时指定的部署路径

image

到这里为止,已经完成了所需的 Qt 模块的编译与安装。Qt 库的导入支持通过 CMake 配置,在简单使用中,会介绍如何使用 CMake 导入 Qt 库并将使用已经安装的 Qt 模块。

简单使用

为了能够让 CMake 知道 Qt 位于何处,需要配置环境变量 CMAKE_PREFIX_PATH,该变量所指定的路径将被用于 CMake 的外部包搜索。

对于 CMAKE_PREFIX_PATH,CMake 将从其路径所指定的文件夹开始向子目录递归地搜索 cmake 目录,该目录下包含了 CMake 的配置脚本。对于 Qt 来说,可以直接将部署目录加入 CMAKE_PREFIX_PATH 变量。

完成上述步骤后,简单编写一个 Qt Hello World 程序,此处将其命名为 foobar.cpp

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <memory>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    auto w = std::make_unique<QWidget>();

    auto label = new QLabel("Hello World!");
    label->setAlignment(Qt::AlignCenter);

    auto layout = new QVBoxLayout(w.get());
    layout->addWidget(label);

    w->setFixedSize(QSize(320, 100));
    w->show();

    return app.exec();
}

编写 CMake 的配置脚本 CMakeLists.txt 如下

# 约束使用的 CMake 版本
cmake_minimum_required(VERSION 3.21)

# 声明项目
project(foobar)

# 从提供的名称中寻找 Qt 库,此处限制使用 Qt6
find_package(Qt NAMES Qt6)
# 寻找 Qt6 的 Widgets 模块,REQUIRED 限制寻找失败则 FATAL
find_package(Qt6 REQUIRED COMPONENTS Widgets)

# 声明可执行文件目标,参与的源文件为 foobar.cpp
# WIN32 指明构建窗口程序(不会弹出控制台)
add_executable(foobar WIN32 foobar.cpp)

# 为可执行目标链接 Qt 模块
target_link_libraries(
    # ${CMAKE_PROJECT_NAME} 为根 CMakeLists.txt 声明的项目名
    # 对于当前层,使用 ${PROJECT_NAME} 指定
    # 此处 ${PROJECT_NAME} 即为 ${CMAKE_PROJECT_NAME}
    ${CMAKE_PROJECT_NAME}
    # 链接 Qt 的 Widgets 模块
    PRIVATE Qt6::Widgets
)

其中 CMakeLists.txt 与 foobar.cpp 位于同目录(记为 $src)。

使用 CMake 在 $src/build 下构建:

cd $src
cmake -B build -S .
cmake --build build

目标可执行文件将生成在 build 目录下,直接运行或在终端 build\foobar.exe 运行,可以看到窗口正常弹出

image

由于构建的 Qt 为动态链接库的版本,故运行目标 Qt 项目需要加载 dll。

在本机上,可以简单地将 Qt 部署路径的 bin 目录(记为 $bin)添加到环境变量中。

在发行或计划在其它电脑上运行时,可以使用 Qt 提供的 $bin/windeployqt 对目标 Qt 可执行文件(如上述的 foobar.exe)进行部署。

默认参数下,windeployqt 会将相关依赖打包到目标文件的同目录下。

标签:...,CMake,Qt,编译,源码,构建,build,Ninja
From: https://www.cnblogs.com/zymelaii/p/17321250.html

相关文章

  • 亲测一份PHP在线客服系统源码-thinkphp+workerman开发-网上流传最广的客服源码搭建教
    为了帮一个客户修改自己的客服系统,所以把源码在本地搭建了一下。因为,我本身就是使用golang有开发一款客服系统的,本来不愿意看这种旧版本的PHP客服源码。但是客户那边需求很少,购买我的商务版感觉不合算,所以网上找了这一个客服源码,也是流传最广的一款PHP客服系统。当然这个源码有没......
  • python3正则-编译和其他
    1、介绍将作为pattern参数的str类型,编译返回Pattern类型,方便后续调用,提高效率。re模块下存在多个函数,可以进行编译,返回类型是Pattern。Pattern类具有和re正则匹配函数类似的方法,当然在参数上略有不同,比如是将待匹配文本作为Pattern类的参数。2、compile函数pattern=re.comp......
  • 互联网医院源码开发|互联网医院软件如何更加规范化?
    互联网医院系统这几年应用越来越广泛,让患者更好的完成线上就医,线上购药等,其实在诊后的环节中互联网医院更是发挥着真正的作用,因为对于一些慢性病患者来说诊后对患者的管理,后续的用药从医性,才是互联网医院能带给患者真正的环节,互联网医院系统的搭建对各中小型药企也将是一个新渠道,在......
  • 【Spring Cloud】Ribbon工作原理源码剖析
    Ribbon调用流程Ribbon工作原理为什么@LoadBalanced注解能赋予RestTemplate负载均衡的能力?Ribbon组件在启动时,会自动加载RibbonAutoConfiguration这个配置类,如下图RibbonAutoConfiguration加载于EurekaClientAutoConfiguration之前,加载于LoadBalancerAutoConfiguration之后......
  • 源码共读 | axios 工具函数
    前言Axios是一个非常流行的库,它可以让你简单、方便地发送HTTP请求。它可以用在浏览器和node.js中,并且支持跨域请求。在Github上拥有快接近10w颗星了,可见其受欢迎程度。下面就来学习一下axios工具函数的源码。仓库地址:axios/axios:PromisebasedHTTPclientfortheb......
  • 每天打卡一小时 第五天 编译四部曲
      第一部曲自然语言 建立双重循环求解选择语句输出 第二部曲流程图  第三部曲伪代码(代码)#include<stdio.h>intmain(){    intN;    scanf("%d",&N);    inta,b;    intf=0;    for(a=1;a*a<=N;a++)    {      ......
  • Go For Web:Golang http 包详解(源码剖析)
    前言:本文作为解决如何通过Golang来编写Web应用这个问题的前瞻,对Golang中的Web基础部分进行一个简单的介绍。目前Go拥有成熟的Http处理包,所以我们去编写一个做任何事情的动态Web程序应该是很轻松的,接下来我们就去学习了解一些关于Web的相关基础,了解一些概念,以及......
  • vue2源码-五、将模板编译解析成AST语法树1
    将模板编译成ast语法树complileToFunction方法vue数据渲染:template模板->ast语法树->render函数,模板编译的最终结果结果就是render函数。在complileToFunction方法中,生成render函数,需要以下两个核心步骤:通过parserHTML方法:将模板(template或html)内容编译成ast语法树通过co......
  • PyQt5 软件在 macOS HiDPI 模式下出现字体模糊的问题
    ​ Retina屏幕是苹果公司在2010年在 WWDC上发布的一种高密度像素的屏幕。HiDPI是一种渲染技术,它可以让Retina屏幕上的图像更加清晰。HiDPI技术会将图像渲染成两倍于原始分辨率的大小,然后再将其缩小到原始分辨率的大小,这样就可以让图像更加清晰。PyQt5编写的软件在Wi......
  • 未来源码|什么是数据集成?超全的SeaTunnel 集成工具介绍
    以下文章来源于大数据与云原生技术分享,作者liugp推荐语:随着互联网流量爆发式增长,越来越多的公司业务需要支撑海量数据存储,对高并发、高可用、高可扩展性等特性提出了更高的要求。这也促使各种类型的数据库快速发展,至今常见数据库已经达到200多个。与之相伴的便是,各种数据库之间......