Dtk开发背后的技术: qmake项目构建

本文章将简述Dtk目前的基本模块以及在构建Dtk库项目过程中使用到的一些与qmake相关的技术

项目组织

Dtk目前由dtkcore/dtkwidget/dtkwm三个子模块构成,三个项目通过 deepin-tool-kit 这一个顶层项目进行统一管理

由于Dtk本身是基于Qt进行开发,所以也自然而然的使用qmake来进行项目构建。qmake简单来说,是类似make/cmake一类的项目自动化构建工具。

我们将以dtkwidget为例,说明在dtk中是如何使用qmake来进行项目构建的。

qmake通过pro文件来作为配置文件,一般在项目根目录会放置一个pro文件,作为项目构建的起点,对于dtkwidget来说,即是:dtk_widget.pro

其内容如下:

load(dtk_lib)

对qmake有一定了解的同学会发现,这里并没有像普通pro文件一样写出TEMPLATE属性,那没这个pro文件是如何工作的呢?

这里有一个关键部署就是 load 这个函数了。qmake对load函数的说明如下:

Loads the feature file (.prf) specified by feature, unless the feature has already been loaded.

实际上,我们通过load函数加载了另外一个叫dtk_lib.prf的内容,这样就可以让所有的dtk模块使用同一个pro文件了。

load函数一般会在qt的fetures目录查找prf文件,那么我们可以看一下 dtk_lib.prf的真容了:

exists($$_PRO_FILE_PWD_/src/dtk_translation.prf) {
    include($$_PRO_FILE_PWD_/src/dtk_translation.prf)
} else {
    load(dtk_translation)
}

TEMPLATE  = subdirs
CONFIG += ordered

exists($$_PRO_FILE_PWD_/src) SUBDIRS += src
exists($$_PRO_FILE_PWD_/tools) SUBDIRS += tools
exists($$_PRO_FILE_PWD_/tests) SUBDIRS += tests
exists($$_PRO_FILE_PWD_/examples) SUBDIRS += examples

可以看到,dtk_lib.prf实际上是制定了项目类型为subdirs,并且默认包含了src/tools/tests/examples四个目录。
注意开始部分,dtk_lib还加载了dtk_translation这个feature,这个时用于处理翻译的一个函数,其内容可以自行了解。

模块构建

模块构建的核心部分在于dtk_build.prf这个feature,这个feature主要完成的功能包括 Dtk版本检查/安装路径配置

使用dtk_build的目的是为dtk的所有模块提供统一的构建/安装环境

版本检查部分处理如下:

defineTest(checkDtkVersion) {
    isEmpty(VERSION) {
        !isEqual(TARGET, dtkcore) {
            VERSION = $${QT.dtkcore.VERSION}
        }

        #TODO: faild in window
        isEmpty(VERSION): VERSION = $$system(git describe --tags --abbrev=0)
        isEmpty(VERSION): VERSION = $$DTK_VERSION
        isEmpty(VERSION): return(false)
        VERSION = $$replace(VERSION, [^0-9.],)
    }

    export(VERSION)
    return(true)
}

这里通过defineTest定义了一个checkDtkVersion的函数,defineTest称为 Test Functions, 通过checkDtkVersion来获取dtk的构建版本。

checkDtkVersion里面用到了一些qmake的内置函数,可以参考 Replace Functions

首先使用system函数, system函数可以调用一条系统命令,这里使用git describe 获取git上的版本号。对于非dtkcore模块,其版本号直接读取QT.dtkcore.VERSION的版本号,保持整个dtk的构建版本号都是一致的。

其次时设置库的安装路径,通过dtk_build.prf 读取PREFIX/LIB_INSTALL_DIR/INCLUDE_INSTALL_DIR来决定target.path / includes.paths。


isEmpty(LIB_INSTALL_DIR) { isEqual(TARGET, dtkcore) { LIB_INSTALL_DIR=$$PREFIX/lib } else { LIB_INSTALL_DIR=$${QT.dtkcore.libs} } } isEmpty(target.path): target.path = $$LIB_INSTALL_DIR isEmpty(INCLUDE_INSTALL_DIR) { isEqual(TARGET, dtkcore) { INCLUDE_INSTALL_DIR = $$PREFIX/include/libdtk-$${VER_MAJ}.$${VER_MIN}.$${VER_PAT} } else { INCLUDE_INSTALL_DIR = $${QT.dtkcore.includes}/.. } } DTK_INCLUDEPATH = $$INCLUDE_INSTALL_DIR isEmpty(includes.path): includes.path = $$quote($$DTK_INCLUDEPATH/D$$upper($$member($$list($$split(TARGET,)), 3, 3))$$join($$list($$member($$list($$split(TARGET,)), 4, -1))),)

包管理工具支持

为了支持其他包管理工具,需要按照不同包管理系统提供对应的配置文件

pkgconfig

Qt原生提供了对pkgconfig的支持, 在 dtk_module.prf中对pkgconfig进行了配置:

# -----------------------
# Config pkg-config
QMAKE_PKGCONFIG_VERSION = $$VERSION
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
QMAKE_PKGCONFIG_NAME = DTK_$$upper($$replace(TARGET, "dtk", ""))
QMAKE_PKGCONFIG_DESCRIPTION = Deepin Tool Kit $$TARGET header files
QMAKE_PKGCONFIG_REQUIRES += $$DTK_MODULE_DEPENDS
QMAKE_PKGCONFIG_INCDIR = $$includes.path
QMAKE_PKGCONFIG_LIBDIR = $$target.path

cmake

由于Qt不支持导出cmake的配置文件,需要手动生成一个cmake文件,安装到cmake的配置目录,这些都通过 dtk_cmake.prf进行配置。
这里有一个关键的qmake函数,即write_file函数,通过write_file,可以将变量的内容输出到一个文件中,通过灵活使用write_file,可以使qmake能更简单的完成一些配置输出功能。

write_file($$CMAKE_PATH, CMAKE_CONTENT) | error("Aborting.")

Qt module

最后,dtk也通过dtk_module这个feature完成的qt模块的支持,通过支持qt模块,可以使qt应用通过简单的QT += dtkcore来完成对dtk的引用,具有优秀的跨平台特性。

支持 Qt module的关键是创建一个 qt_lib_$${MODULE_ID}.pri 文件,安装的qt的modules目录中:

QT_HOST_DATA=$$system(qmake -query QT_HOST_DATA)
qt_module.files = $$MODULE_PRI
qt_module.path = $${QT_HOST_DATA}/mkspecs/modules

INSTALLS += qt_module

具体安装路径可以通过 qmake -query QT_HOST_DATA获取。

而文件内容则通过write_file写入


write_file($$MODULE_PRI, MODULE_PRI_CONT)|error("Aborting.")

通过熟练的掌握qmake的Replace/Test函数,dtk可以实现简洁又强大的构建配置。如果想为dtk提供其他特性,也可以通过feature的方式,来方便的扩展dtk提供的功能,甚至来实现简单的项目模板。
如果对qmake的其他特性感兴趣,可以参考qmake的手册:

qmake Manual

发表评论

电子邮件地址不会被公开。 必填项已用*标注