qt creator源码全方面分析(3-2)
codeForFamily 人气:1
[TOC]
# qtcreator.pri
前面我们介绍了qtcreator.pro,下面我们开始介绍qtcreator.pri,来看看pro中include的pri到底是干什么用的。
注意,许多函数/变量/关键字的含义,某些基础用法,在qtcreator.pro中进行了介绍。
## 判断重复包含
qtcreator.pri第一部分是
```
!isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included")
QTCREATOR_PRI_INCLUDED = 1
```
很明显,isEmpty()为false,则调用error报错退出编译。那么只能是为true,即要求QTCREATOR_PRI_INCLUDED为空,并在下一行立即定义为1。
那么这个是在干什么呢?我们看变量的名称就能略窥一二,INCLUDED就是已包含的意思,那么这里就是为了避免在其他地方重复包含qtcreator.pri文件,类似于C/C++头文件中的
```c++
# ifndef XXX_H
# define XXX_H
#endif
```
## 定义版本信息
接下来是
```
QTCREATOR_VERSION = 4.6.2
QTCREATOR_COMPAT_VERSION = 4.6.0
VERSION = $$QTCREATOR_VERSION
QTCREATOR_DISPLAY_VERSION = 4.6.2
QTCREATOR_COPYRIGHT_YEAR = 2018
BINARY_ARTIFACTS_BRANCH = 4.6
```
### [VERSION](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#version)
> 如果TEMPLATE值为app,则指定应用程序的版本号;如果TEMPLATE值为lib,则指定库的版本号。
>
> 在Windows上,如果未设置RC_FILE和RES_FILE变量,则自动生成.rc文件。 生成的.rc文件将具有FILEVERSION和PRODUCTVERSION条目,并用主,次,补丁和构建版本号填充。 每个数字的范围必须在0到65535之间。有关.rc文件生成的更多详细信息,请参见[Platform Notes](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-platform-notes.html)。
>
> 示例:
>
> ```
> win32:VERSION = 1.2.3.4 # major.minor.patch.build
> else:VERSION = 1.2.3 # major.minor.patch
> ```
很明显,是在定义QtCreator的版本,兼容性版本,版权,以及git分支。
## 定义IDE名称
接下来是
```
isEmpty(IDE_DISPLAY_NAME): IDE_DISPLAY_NAME = Qt Creator
isEmpty(IDE_ID): IDE_ID = qtcreator
isEmpty(IDE_CASED_ID): IDE_CASED_ID = QtCreator
isEmpty(PRODUCT_BUNDLE_IDENTIFIER): PRODUCT_BUNDLE_IDENTIFIER = org.qt-project.$$IDE_ID
```
我们在qtcreator.pro中已经介绍过isEmpty这种用法。这里在给相关变量设置默认值。
## 启用C++14
接下来是
```
CONFIG += c++14
```
### [CONFIG](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#config)
> 指定项目配置和编译器选项。 这些值由qmake内部识别,并具有特殊含义。
>
> 以下CONFIG值控制编译标志:
>
> | 选项 | 描述 |
> | ------------------------------- | ------------------------------------------------------------ |
> | release | 该项目将以release模式构建。 如果还指定了debug,则最后那个生效。 |
> | debug | 该项目将以debug模式构建。 |
> | debug_and_release | 该项目将同时构建debug和release模式。 |
> | debug_and_release_target | 默认情况下设置此选项。 如果还设置了debug_and_release,则debug和release版本最终将放置在单独的debug和release目录中。 |
> | build_all | 如果指定了debug_and_release,则默认情况下项目同时构建debug和release模式。 |
> | autogen_precompile_source | 自动生成一个.cpp文件,其中包含.pro文件中指定的预编译头文件。 |
> | ordered | 当TEMPLATE为subdirs时,此选项指定应按给出的顺序处理列出的目录。
注意:不建议使用此选项。 如[SUBDIRS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#subdirs)变量文档中所述指定依赖项。 | > | precompile_header | 使能支持在项目中使用[precompiled headers](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-precompiledheaders.html)。 | > | precompile_header_c (MSVC only) | 使能支持在C文件中使用[precompiled headers](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-precompiledheaders.html)。 | > | warn_on | 编译器应尽可能多的输出警告。 如果还指定了warn_off,则最后那个生效。 | > | warn_off | 编译器应尽可能少的输出警告。 | > | exceptions | 使能异常支持。默认设置该选项。 | > | exceptions_off | 禁用异常支持。 | > | rtti | 使能RTTI支持。默认情况下,使用编译器默认值。 | > | rtti_off | 禁用RTTI支持。默认情况下,使用编译器默认值。 | > | stl | 使能STL支持。默认情况下,使用编译器默认值。 | > | stl_off | 禁用STL支持。默认情况下,使用编译器默认值。 | > | thread | 使能Thread支持。当CONFIG包含qt(默认设置)时,将使能此功能。 | > | c99 | 使能C99支持。 如果编译器不支持C99或无法选择C标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c11 | 使能C11支持。 如果编译器不支持C11或无法选择C标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | strict_c | 禁用对C编译器扩展的支持。 默认情况下,它们是使能的。 | > | c++11 | 使能C++11支持。 如果编译器不支持C++11或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++14 | 使能C++14支持。 如果编译器不支持C++14或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++1z | 使能C++17支持。 如果编译器不支持C++17或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++17 | 同c++1z | > | c++2a | 使能C++2a支持。 如果编译器不支持C++2a或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++latest | 如果编译器支持,使能最新C++语言标准的支持。 默认情况下,此选项是禁用的。 | > | strict_c++ | 禁用对C++编译器扩展的支持。 默认情况下,它们是使能的。 | > | depend_includepath | 使能将INCLUDEPATH的值附加到DEPENDPATH。 默认设置此选项。 | > | lrelease | 对[TRANSLATIONS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#translations) 和[EXTRA_TRANSLATIONS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#extra-translations)中列出的所有文件运行lrelease。 如果未设置embed_translations,则将生成的.qm文件安装到[QM_FILES_INSTALL_PATH](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qm-files-install-path)中。 使用[QMAKE_LRELEASE_FLAGS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lrelease-flags)向lrelease调用添加参数选项。 默认情况下未设置此选项。 | > | embed_translations | 将lrelease生成的翻译内容嵌入[QM_FILES_RESOURCE_PREFIX](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qm-files-resource-prefix)下的可执行文件中。 也需要同时设置lrelease。 默认情况下未设置此选项。 | > | create_libtool | 为当前构建的库创建一个libtool.la文件。 | > | create_pc | 为当前构建的库创建一个pkg-config .pc文件。 | > | no_batch | 仅限NMake:关闭NMake批处理规则或推断规则的生成。 | > | skip_target_version_ext | 在Windows上禁止附加自动版本号到DLL文件名。 | > | suppress_vcproj_warnings | 禁止VS项目生成器的警告。 | > | windeployqt | 链接后自动调用windeployqt,并将输出添加为部署项。 | > | dont_recurse | 禁止对当前子项目的qmake递归。 | > | no_include_pwd | 不要将当前目录添加到INCLUDEPATHS。 | > > 当您使用debug_and_release选项(在Windows下是默认设置)时,项目将被处理三次:一次生成元Makefile,再两次生成Makefile.Debug和Makefile.Release。 > > 在后面的过程中,将build_pass和相应的debug或release选项附加到CONFIG。 这样就可以执行特定构建任务。 例如: > > ``` > build_pass:CONFIG(debug, debug|release) { > unix: TARGET = $$join(TARGET,,,_debug) > else: TARGET = $$join(TARGET,,,d) > } > ``` > > 作为手动编写构建类型条件的替代方法,除了常规[QMAKE_LFLAGS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lflags)外,某些变量还提供特定构建变量,例如 [QMAKE_LFLAGS_RELEASE](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lflags-release)。 这些应在可用时使用。 > > 元Makefile通过debug和release目标进行子构建调用,并可通过all目标进行联合构建调用。 使用build_all选项时,联合构建为默认设置。 否则,CONFIG中最后指定的来自集合(debug,release)的选项会变为默认选项。 在这种情况下,您可以显式调用all以一次构建两个配置: > > ``` > make all > ``` > > 注意:在生成Visual Studio和Xcode项目时,详细信息略有不同。 > > 链接库时,qmake依赖基础平台,来了解该库应该链接的其他库。 但是,如果是静态链接,qmake不会获取此信息,除非使用以下CONFIG选项: > > | 选项 | 描述 | > | -------------- | ------------------------------------------------------------ | > | create_prl | 此选项使qmake可以跟踪这些依赖性。 使能此选项后,qmake将创建扩展名为.prl的文件,该文件将保存有关库的元信息(有关更多信息,请参见[Library Dependencies](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-advanced-usage.html#libdepend))。 | > | link_prl | 使能此选项后,qmake将处理该应用程序链接的所有库并找到其元信息(有关更多信息,请参见[Library Dependencies](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-advanced-usage.html#libdepend))。 | > | no_install_prl | 此选项禁用创建.prl文件的安装规则的生成。 | > > 注意:构建静态库时,需要create_prl选项,而使用静态库时,则需要link_prl选项。 > > 以下选项定义应用程序或库的类型: > > | 选项 | 描述 | > | ------------------ | ------------------------------------------------------------ | > | qt | 目标是Qt应用程序或库,并且需要Qt库和头文件。 Qt库正确的包含和库路径将自动添加到项目中。 这是默认定义的,可以使用\l{#qt}{QT}变量进行微调。 | > | x11 | 目标是X11应用程序或库。 正确的包含路径和库将自动添加到项目中。 | > | testcase | 目标是一个自动测试。 一个[检查目标](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-common-projects.html#building-a-testcase)将被添加到生成的Makefile中,以运行测试。 仅在生成Makefile时相关。 | > | insignificant_test | 自动测试的退出代码将被忽略。 仅当还设置了testcase时才相关。 | > | windows | 目标是Win32窗口应用程序(仅适用于TEMPLATE为app)。 正确的包含路径,编译器标志和库将自动添加到项目中。 | > | console | 目标是Win32控制台应用程序(仅适用于TEMPLATE为app)。 正确的包含路径,编译器标志和库将自动添加到项目中。考虑将选项cmdline用于跨平台应用程序。 | > | cmdline | 目标是跨平台的命令行应用程序。 在Windows上,这意味着CONFIG += console。 在macOS上,这意味着CONFIG -= app_bundle。 | > | shared | 目标是共享对象/DLL。 正确的包含路径,编译器标志和库将自动添加到项目中。 请注意,dll也可以在所有平台上使用。 将创建带有目标平台的适当后缀(.dll或.so)的共享库文件。 | > | dll | 同上。 | > | static | 目标是静态库(仅lib)。 正确的编译器标志将自动添加到项目中。 | > | staticlib | 同上。 | > | plugin | 目标是插件(仅lib)。 这也会使能dll。 | > | designer | 目标是Qt Designer的插件。 | > | no_lflags_merge | 确保存储在LIBS变量中的库列表在使用前不减少为值唯一(去除了重复的)列表。 | > > 这些选项仅在Windows上定义特定功能: > > | 选项 | 描述 | > | ------------------ | ------------------------------------------------------------ | > | flat | 使用vcapp模板时,这会将所有源文件置于源组中,并将头文件置于头组中,而不管它们位于哪个目录中。关闭此选项,将根据文件所在目录归类。 默认情况下是打开的。 | > | embed_manifest_dll | 将清单文件嵌入到作为库项目一部分的DLL中。 | > | embed_manifest_exe | 将清单文件嵌入到作为应用程序项目一部分的EXE中。 | > > 有关嵌入清单文件的选项的更多信息,请参见[Platform Notes](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-platform-notes.html#visual-studio-manifest-files)。 > > 以下选项仅在macOS上有效: > > | 选项 | 描述 | > | ------------- | ------------------------------------------------ | > | app_bundle | 将可执行文件放入捆绑包(这是默认设置)。 | > | lib_bundle | 将库放入库包(这是默认设置)。 | > | plugin_bundle | 将插件放入插件包中。 Xcode项目生成器不支持此值。 | > > 捆绑软件的构建过程也受[QMAKE_BUNDLE_DATA](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-bundle-data)变量内容的影响。 > > 以下选项仅在Linux / Unix平台上有效: > > | 选项 | 描述 | > | ------------------- | ------------------------------ | > | largefile | 支持大文件的包含 | > | separate_debug_info | 把库的调试信息放到单独的文件中 | > > 解析作用域时,将检查CONFIG变量。 您可以为该变量分配任何内容。 > > 例如: > > ``` > CONFIG += console newstuff > ... > newstuff { > SOURCES += new.cpp > HEADERS += new.h > } > ``` ## 自定义函数 接下来是 ``` defineReplace(qtLibraryTargetName) { unset(LIBRARY_NAME) LIBRARY_NAME = $$1 CONFIG(debug, debug|release) { !debug_and_release|build_pass { mac:RET = $$member(LIBRARY_NAME, 0)_debug else:win32:RET = $$member(LIBRARY_NAME, 0)d } } isEmpty(RET):RET = $$LIBRARY_NAME return($$RET) } defineReplace(qtLibraryName) { RET = $$qtLibraryTargetName($$1) win32 { VERSION_LIST = $$split(QTCREATOR_VERSION, .) RET = $$RET$$first(VERSION_LIST) } return($$RET) } defineTest(minQtVersion) { maj = $$1 min = $$2 patch = $$3 isEqual(QT_MAJOR_VERSION, $$maj) { isEqual(QT_MINOR_VERSION, $$min) { isEqual(QT_PATCH_VERSION, $$patch) { return(true) } greaterThan(QT_PATCH_VERSION, $$patch) { return(true) } } greaterThan(QT_MINOR_VERSION, $$min) { return(true) } } greaterThan(QT_MAJOR_VERSION, $$maj) { return(true) } return(false) } # For use in custom compilers which just copy files defineReplace(stripSrcDir) { return($$relative_path($$absolute_path($$1, $$OUT_PWD), $$_PRO_FILE_PWD_)) } ``` ### [Replace Functions](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-language.html#replace-functions) > qmake提供了一些内置函数,以允许处理变量的内容。 这些函数处理提供给它们的参数,并返回一个值或值列表。 `要将结果分配给变量,可以将$$运算符与此类函数一起使用`,就像将一个变量的内容分配给另一个一样: > > ``` > HEADERS = model.h > HEADERS += $$OTHER_HEADERS > HEADERS = $$unique(HEADERS) > ``` > > 此类函数应在赋值的右侧(即,作为操作数)。 > > 您可以定义自己的函数来处理变量的内容,如下所示: > > ``` > defineReplace(functionName){ > #function code > } > ``` > > 以下示例函数将变量名作为唯一参数,使用内置函数eval()从变量中提取值列表,并编译文件列表: > > ``` > defineReplace(headersAndSources) { > variable = $$1 > names = $$eval($$variable) > headers = > sources = > > for(name, names) { > header = $${name}.h > exists($$header) { > headers += $$header > } > source = $${name}.cpp > exists($$source) { > sources += $$source > } > } > return($$headers $$sources) > } > ``` > > 参数$$1 ### [Test Functions](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-language.html#test-functions) > qmake提供了内置函数,可以在编写作用域时用作条件。 这些函数不返回值,而是指示成功或失败: > > ``` > count(options, 2) { > message(Both release and debug specified.) > } > ``` > > 此类函数应仅在条件表达式中使用。 > > 可以定义自己的函数以提供作用域条件。 以下示例测试列表中的每个文件是否存在,如果全部存在,则返回true,否则返回false: > > ``` > defineTest(allFiles) { > files = $$ARGS > > for(file, files) { > !exists($$file) { > return(false) > } > } > return(true) > } > ``` > > 参数列表$$ARGS ### [\_PRO_FILE_PWD_](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#pro-file-pwd) > 包含正在使用的项目文件的目录的路径。(即使该变量出现在 .pri 文件,也是指包含该 .pri 文件的 .pro 文件所在目录的路径。) > > 例如,以下行导致包含项目文件的目录的位置写入控制台: > > ``` > message($$_PRO_FILE_PWD_) > ``` > > 注意:请勿尝试覆盖此变量的值。 ### [\_PRO_FILE_](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#pro-file) > 包含正在使用的项目文件的路径。 > > 例如,以下行导致项目文件的位置写入控制台: > > ``` > message($$_PRO_FILE_) > ``` > > 注意:请勿尝试覆盖此变量的值。 现在我们来分析pri中定义的三个函数。 因为这两个函数在 Qt Creator 中使用了多次,并且完全可以拷贝复制到其它项目继续使用。 自定义替换函数`qtLibraryTargetName`。 1. 取消LIBRARY_NAME的定义,设置LIBRARY_NAME为 `$$1`,即函数的第一个参数。 2. CONFIG测试函数判断debug或release模式。 1. 如果是debug模式,再次进行判断。 2. 如果CONFIG没有设置debug_and_release或者是构建过程build_pass,则设置RET变量。对于 mac,LIBRARY_NAME值后面添加_debug赋给RET。对于win,LIBRARY_NAME值后面添加d赋给RET。 3. 如果RET为空,则把LIBRARY_NAME值赋给RET。 4. 返回RET。 简单来说,该函数实现功能:在debug环境下,在库名后面添加\_debug或\_d尾缀,来跟release模式进行区分。当然,也有其他方式来实现上述功能,譬如使用join()函数,见CONFIG小节。 自定义替换函数`qtLibraryName`。 1. 使用qtLibraryTargetName()函数,对输入的第一个参数进行替换,并赋值给RET。 2. 如果 是win32 系统。 1. 使用split()函数,将前面定义的QTCREATOR_VERSION(即4.6.2),使用\'.\'进行分隔得到列表,赋值给VERSION_LIST 2. 使用first()函数,获取VERSION_LIST的第一个元素(即4),与RET拼接,并赋值给RET。 3. 返回RET。 简单来说,该函数实现功能:为了在win32系统中避免出现 dll hell,在win32系统下,在库名后面添加主版本号。 自定义测试函数`minQtVersion`。 1. 获取三个参数(即,主/次/补丁),并赋值给maj,min,patch。 2. maj <= QT_MAJOR_VERSION,min <= QT_MINOR_VERSION和patch <= QT_PATCH_VERSION,则返回true。其他返回false。 简单来说,该函数实现功能:函数参数的版本号小于等于当前Qt的版本号。 自定义替换函数`stripSrcDir`。 1. 获取绝对路径,absolute_path返回$$OUT_PWD/$$1。 2. 获取相对路径,步骤1中获取的绝对路径相对与$$\_PRO_FILE_PWD_的相对路径。 简单来说,该函数实现功能(见自带的注释):用于自定义编译器拷贝文件。 ## 设置macOS最小版本 接下来是: ``` darwin:!minQtVersion(5, 7, 0) { # Qt 5.6 still sets deployment target 10.7, which does not work # with all C++11/14 features (e.g. std::future) QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.8 } ``` 如果是基于Darwin操作系统的,并且Qt 的版本低于`5.7.0`时,设置应用程序支持的macOs最小版本。可以从注释看出,10.7不支持C++11/14特性。 ## 设置QTEST模块 接下来是 ``` QTC_BUILD_TESTS = $$(QTC_BUILD_TESTS) !isEmpty(QTC_BUILD_TESTS):TEST = $$QTC_BUILD_TESTS !isEmpty(BUILD_TESTS):TEST = 1 isEmpty(TEST):CONFIG(debug, debug|release) { !debug_and_release|build_pass { TEST = 1 } } isEmpty(IDE_LIBRARY_BASENAME) { IDE_LIBRARY_BASENAME = lib } equals(TEST, 1) { QT +=testlib DEFINES += WITH_TESTS } ``` 1. 如果设置了QTC_BUILD_TESTS,则赋值给TEST。 2. 如果设置了BUILD_TESTS,则给TEST赋值1。 3. 如果TEST没有值,且为debug模式,并且没有设置debug_and_release,则在构建过程中,设置TEST为1。 4. 如果IDE_LIBRARY_BASENAME为空,则为库赋值基础名为lib。 5. 如果TEST等于1,则添加QTEST模块功能。 ## 设置源目录和构建目录 接下来是 ``` IDE_SOURCE_TREE = $$PWD isEmpty(IDE_BUILD_TREE) { sub_dir = $$_PRO_FILE_PWD_ sub_dir ~= s,^$$re_escape($$PWD),, IDE_BUILD_TREE = $$clean_path($$OUT_PWD) IDE_BUILD_TREE ~= s,$$re_escape($$sub_dir)$,, } ``` ### [re_escape(string)](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#re-escape-string) > 对每个string中的特殊正则表达式字符,使用反斜杠转义,返回转义后的字符串。 该函数是QRegExp::escape的包装。 > > 例如: > > ``` > s1 = QRegExp::escape("bingo"); // s1 == "bingo" > s2 = QRegExp::escape("f(x)"); // s2 == "f\\(x\\)" > ``` ### [clean_path(path)](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#clean-path-path) > 处理path,对目录分隔符进行规范化(转换为"/"),删除了多余的目录分隔符,并且解析"."和".."(尽可能)。 该函数是QDir::cleanPath的包装。 > > 另请阅[absolute_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#absolute-path-path-base), [relative_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#relative-path-filepath-base), [shell_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#shell-path-path), [system_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#system-path-path). 我们在代码后面插桩输出语句 ``` build_pass:message($$PWD) # 当前pri文件所在目录 build_pass:message($$OUT_PWD) # 生成makefile所在目录 build_pass:message($$_PRO_FILE_) # 包含当前pri的pro所在路径 build_pass:message($$_PRO_FILE_PWD_) # 包含当前pri的pro所在目录 ``` 现在,我们来看一下部分输出。 ``` Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2 Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/bin Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin/bin.pro Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2 Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/src/app Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app/app.pro Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app ``` 我们可以发现 1. PWD没有发生变化。 2. 对比OUT_PWD和\_PRO_FILE_PWD_,输出目录和源目录的子文件夹组织架构一样。 下面我们分析pri中的语句 1. 设置源目录IDE_SOURCE_TREE。 2. 如果构建目录IDE_BUILD_TREE为空。 1. 设置sub_dir,并进行替换。可以认为是从\_PRO_FILE_PWD_减去PWD,剩下子文件夹相对路径,如bin/和app/。 2. 初始化IDE_BUILD_TREE,并进行替换。可以认为是从OUT_PWD减去相对路径,剩下相同的根目录。 大家可以用我们上面的message输出结果来简单的计算下即可。 IDE_SOURCE_TREE为F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2, IDE_BUILD_TREE为F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info。 ## 设置IDE和INSTALLS相关路径 接下来是 ``` IDE_APP_PATH = $$IDE_BUILD_TREE/bin osx { IDE_APP_TARGET = "$$IDE_DISPLAY_NAME" # check if IDE_BUILD_TREE is actually an existing Qt Creator.app, # for building against a binary package exists($$IDE_BUILD_TREE/Contents/MacOS/$$IDE_APP_TARGET): IDE_APP_BUNDLE = $$IDE_BUILD_TREE else: IDE_APP_BUNDLE = $$IDE_APP_PATH/$${IDE_APP_TARGET}.app # set output path if not set manually isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_APP_BUNDLE/Contents IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/Frameworks IDE_PLUGIN_PATH = $$IDE_OUTPUT_PATH/PlugIns IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/Resources IDE_DATA_PATH = $$IDE_OUTPUT_PATH/Resources IDE_DOC_PATH = $$IDE_DATA_PATHhttps://img.qb5200.com/download-x/doc IDE_BIN_PATH = $$IDE_OUTPUT_PATH/MacOS copydata = 1 LINK_LIBRARY_PATH = $$IDE_APP_BUNDLE/Contents/Frameworks LINK_PLUGIN_PATH = $$IDE_APP_BUNDLE/Contents/PlugIns INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Frameworks INSTALL_PLUGIN_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/PlugIns INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources INSTALL_DATA_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources INSTALL_DOC_PATH = $$INSTALL_DATA_PATHhttps://img.qb5200.com/download-x/doc INSTALL_BIN_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/MacOS INSTALL_APP_PATH = $$QTC_PREFIX/ } else { contains(TEMPLATE, vc.*):vcproj = 1 IDE_APP_TARGET = $$IDE_ID # target output path if not set manually isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_BUILD_TREE IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/$$IDE_LIBRARY_BASENAME/qtcreator IDE_PLUGIN_PATH = $$IDE_LIBRARY_PATH/plugins IDE_DATA_PATH = $$IDE_OUTPUT_PATH/share/qtcreator IDE_DOC_PATH = $$IDE_OUTPUT_PATH/sharehttps://img.qb5200.com/download-x/doc/qtcreator IDE_BIN_PATH = $$IDE_OUTPUT_PATH/bin win32: \ IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/bin else: \ IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/libexec/qtcreator !isEqual(IDE_SOURCE_TREE, $$IDE_OUTPUT_PATH):copydata = 1 LINK_LIBRARY_PATH = $$IDE_BUILD_TREE/$$IDE_LIBRARY_BASENAME/qtcreator LINK_PLUGIN_PATH = $$LINK_LIBRARY_PATH/plugins INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$$IDE_LIBRARY_BASENAME/qtcreator INSTALL_PLUGIN_PATH = $$INSTALL_LIBRARY_PATH/plugins win32: \ INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/bin else: \ INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/libexec/qtcreator INSTALL_DATA_PATH = $$QTC_PREFIX/share/qtcreator INSTALL_DOC_PATH = $$QTC_PREFIX/sharehttps://img.qb5200.com/download-x/doc/qtcreator INSTALL_BIN_PATH = $$QTC_PREFIX/bin INSTALL_APP_PATH = $$QTC_PREFIX/bin } ``` 我们可以发现上面的内容大部分是基于IDE_BUILD_TREE和QTC_PREFIX的。 代码首先设置了可执行程序的目录。 接下来,我们重点分析else分支的内容。 1. 如果TEMPLATE包含vc.*,其实就是vcapp或vclib,设置vcproj为1,表示是vs工程。 2. 设置可执行程序文件名为IDE_ID(默认为qtcreator)。 3. 设置输出路径IDE_OUTPUT_PATH默认为IDE_BUILD_TREE。 4. 设置IDE相关子文件夹路径,可以发现都是相对于IDE_OUTPUT_PATH的。 5. 如果输出路径不是源目录,则设置copydata为1,表示需要拷贝数据。 6. 考虑到IDE_BUILD_TREE与IDE_OUTPUT_PATH可能不一样,设置IDE库和插件的链接路径。 7. 设置INSTALLS用的相关子文件夹路径。 ## 设置字符串宏 接下来是 ``` RELATIVE_PLUGIN_PATH = $$relative_path($$IDE_PLUGIN_PATH, $$IDE_BIN_PATH) RELATIVE_LIBEXEC_PATH = $$relative_path($$IDE_LIBEXEC_PATH, $$IDE_BIN_PATH) RELATIVE_DATA_PATH = $$relative_path($$IDE_DATA_PATH, $$IDE_BIN_PATH) RELATIVE_DOC_PATH = $$relative_path($$IDE_DOC_PATH, $$IDE_BIN_PATH) DEFINES += $$shell_quote(RELATIVE_PLUGIN_PATH=\"$$RELATIVE_PLUGIN_PATH\") DEFINES += $$shell_quote(RELATIVE_LIBEXEC_PATH=\"$$RELATIVE_LIBEXEC_PATH\") DEFINES += $$shell_quote(RELATIVE_DATA_PATH=\"$$RELATIVE_DATA_PATH\") DEFINES += $$shell_quote(RELATIVE_DOC_PATH=\"$$RELATIVE_DOC_PATH\") ``` ### [shell_quote](https://linux.die.net/man/1/shell-quote) > 在qmake中的介绍很简单:为shell对arg加引号,当构建构建项目时。 > > 在linux man page中的介绍:可让您通过shell传递任意字符串,shell不会更改它们。 这使您可以安全地处理带有`嵌入式空格`或shell globbing字符的命令或文件。 ### qmake定义字符串宏 > 有时候,我们想定义字符串宏,并在源代码中进行使用。假设你想在qmake中定义字符串宏,这里有三种途径 > > > > 我们先来看一下qmake编译得到的Makefile.Debug,符合makefile语法的形式 > > > > 现在我们来介绍下DEFINES中的含义: > > 1. NAME1中第一个"对,告诉qmake引导里面的是字符串。里面的\\"对,是对引号的转义,在makefile中变为"。再里面的\\\\对,也是转义,在makefile中变为\\。在里面的\\"同样,最终变为"。最终得到我们想要的字符串。 > > 2. NAME2使用shell_quote()函数,该函数对参数加引号。 > > 3. NAME0对比NAME1,少了最外面的"对,这导致NAME0只能定义没有空格的字符串。如果存在空格,这会导致内容发生变化,中间多了个-D。 > > ``` > qmake: DEFINES += NAME0=\"\\\"app1 .0\\\"\" > makefile: -DNAME0="\"app1 -D.0\"" > ``` > > 此外,对于没有空格的字符串宏定义,我们甚至可以不需要最外层的引号转义。 > > ``` > qmake: DEFINES += NAME0=\\\"app1\\\" > makefile: -DNAME0=\"app1\" > ``` 分析代码: 1. 设置了PLUGIN,LIBEXEC,DATA和DOC相对于BIN的相对路径,譬如PLUGIN的为../lib/qtcreator/plugins。 2. 使步骤1中的变量称为字符串,添加到DEFINES中,变为宏。 ## 设置INCLUDEPATH 接下来是 ``` INCLUDEPATH += \ $$IDE_BUILD_TREE/src \ # for
注意:不建议使用此选项。 如[SUBDIRS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#subdirs)变量文档中所述指定依赖项。 | > | precompile_header | 使能支持在项目中使用[precompiled headers](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-precompiledheaders.html)。 | > | precompile_header_c (MSVC only) | 使能支持在C文件中使用[precompiled headers](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-precompiledheaders.html)。 | > | warn_on | 编译器应尽可能多的输出警告。 如果还指定了warn_off,则最后那个生效。 | > | warn_off | 编译器应尽可能少的输出警告。 | > | exceptions | 使能异常支持。默认设置该选项。 | > | exceptions_off | 禁用异常支持。 | > | rtti | 使能RTTI支持。默认情况下,使用编译器默认值。 | > | rtti_off | 禁用RTTI支持。默认情况下,使用编译器默认值。 | > | stl | 使能STL支持。默认情况下,使用编译器默认值。 | > | stl_off | 禁用STL支持。默认情况下,使用编译器默认值。 | > | thread | 使能Thread支持。当CONFIG包含qt(默认设置)时,将使能此功能。 | > | c99 | 使能C99支持。 如果编译器不支持C99或无法选择C标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c11 | 使能C11支持。 如果编译器不支持C11或无法选择C标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | strict_c | 禁用对C编译器扩展的支持。 默认情况下,它们是使能的。 | > | c++11 | 使能C++11支持。 如果编译器不支持C++11或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++14 | 使能C++14支持。 如果编译器不支持C++14或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++1z | 使能C++17支持。 如果编译器不支持C++17或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++17 | 同c++1z | > | c++2a | 使能C++2a支持。 如果编译器不支持C++2a或无法选择C++标准,则此选项无效。 默认情况下,使用编译器默认值。 | > | c++latest | 如果编译器支持,使能最新C++语言标准的支持。 默认情况下,此选项是禁用的。 | > | strict_c++ | 禁用对C++编译器扩展的支持。 默认情况下,它们是使能的。 | > | depend_includepath | 使能将INCLUDEPATH的值附加到DEPENDPATH。 默认设置此选项。 | > | lrelease | 对[TRANSLATIONS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#translations) 和[EXTRA_TRANSLATIONS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#extra-translations)中列出的所有文件运行lrelease。 如果未设置embed_translations,则将生成的.qm文件安装到[QM_FILES_INSTALL_PATH](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qm-files-install-path)中。 使用[QMAKE_LRELEASE_FLAGS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lrelease-flags)向lrelease调用添加参数选项。 默认情况下未设置此选项。 | > | embed_translations | 将lrelease生成的翻译内容嵌入[QM_FILES_RESOURCE_PREFIX](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qm-files-resource-prefix)下的可执行文件中。 也需要同时设置lrelease。 默认情况下未设置此选项。 | > | create_libtool | 为当前构建的库创建一个libtool.la文件。 | > | create_pc | 为当前构建的库创建一个pkg-config .pc文件。 | > | no_batch | 仅限NMake:关闭NMake批处理规则或推断规则的生成。 | > | skip_target_version_ext | 在Windows上禁止附加自动版本号到DLL文件名。 | > | suppress_vcproj_warnings | 禁止VS项目生成器的警告。 | > | windeployqt | 链接后自动调用windeployqt,并将输出添加为部署项。 | > | dont_recurse | 禁止对当前子项目的qmake递归。 | > | no_include_pwd | 不要将当前目录添加到INCLUDEPATHS。 | > > 当您使用debug_and_release选项(在Windows下是默认设置)时,项目将被处理三次:一次生成元Makefile,再两次生成Makefile.Debug和Makefile.Release。 > > 在后面的过程中,将build_pass和相应的debug或release选项附加到CONFIG。 这样就可以执行特定构建任务。 例如: > > ``` > build_pass:CONFIG(debug, debug|release) { > unix: TARGET = $$join(TARGET,,,_debug) > else: TARGET = $$join(TARGET,,,d) > } > ``` > > 作为手动编写构建类型条件的替代方法,除了常规[QMAKE_LFLAGS](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lflags)外,某些变量还提供特定构建变量,例如 [QMAKE_LFLAGS_RELEASE](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-lflags-release)。 这些应在可用时使用。 > > 元Makefile通过debug和release目标进行子构建调用,并可通过all目标进行联合构建调用。 使用build_all选项时,联合构建为默认设置。 否则,CONFIG中最后指定的来自集合(debug,release)的选项会变为默认选项。 在这种情况下,您可以显式调用all以一次构建两个配置: > > ``` > make all > ``` > > 注意:在生成Visual Studio和Xcode项目时,详细信息略有不同。 > > 链接库时,qmake依赖基础平台,来了解该库应该链接的其他库。 但是,如果是静态链接,qmake不会获取此信息,除非使用以下CONFIG选项: > > | 选项 | 描述 | > | -------------- | ------------------------------------------------------------ | > | create_prl | 此选项使qmake可以跟踪这些依赖性。 使能此选项后,qmake将创建扩展名为.prl的文件,该文件将保存有关库的元信息(有关更多信息,请参见[Library Dependencies](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-advanced-usage.html#libdepend))。 | > | link_prl | 使能此选项后,qmake将处理该应用程序链接的所有库并找到其元信息(有关更多信息,请参见[Library Dependencies](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-advanced-usage.html#libdepend))。 | > | no_install_prl | 此选项禁用创建.prl文件的安装规则的生成。 | > > 注意:构建静态库时,需要create_prl选项,而使用静态库时,则需要link_prl选项。 > > 以下选项定义应用程序或库的类型: > > | 选项 | 描述 | > | ------------------ | ------------------------------------------------------------ | > | qt | 目标是Qt应用程序或库,并且需要Qt库和头文件。 Qt库正确的包含和库路径将自动添加到项目中。 这是默认定义的,可以使用\l{#qt}{QT}变量进行微调。 | > | x11 | 目标是X11应用程序或库。 正确的包含路径和库将自动添加到项目中。 | > | testcase | 目标是一个自动测试。 一个[检查目标](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-common-projects.html#building-a-testcase)将被添加到生成的Makefile中,以运行测试。 仅在生成Makefile时相关。 | > | insignificant_test | 自动测试的退出代码将被忽略。 仅当还设置了testcase时才相关。 | > | windows | 目标是Win32窗口应用程序(仅适用于TEMPLATE为app)。 正确的包含路径,编译器标志和库将自动添加到项目中。 | > | console | 目标是Win32控制台应用程序(仅适用于TEMPLATE为app)。 正确的包含路径,编译器标志和库将自动添加到项目中。考虑将选项cmdline用于跨平台应用程序。 | > | cmdline | 目标是跨平台的命令行应用程序。 在Windows上,这意味着CONFIG += console。 在macOS上,这意味着CONFIG -= app_bundle。 | > | shared | 目标是共享对象/DLL。 正确的包含路径,编译器标志和库将自动添加到项目中。 请注意,dll也可以在所有平台上使用。 将创建带有目标平台的适当后缀(.dll或.so)的共享库文件。 | > | dll | 同上。 | > | static | 目标是静态库(仅lib)。 正确的编译器标志将自动添加到项目中。 | > | staticlib | 同上。 | > | plugin | 目标是插件(仅lib)。 这也会使能dll。 | > | designer | 目标是Qt Designer的插件。 | > | no_lflags_merge | 确保存储在LIBS变量中的库列表在使用前不减少为值唯一(去除了重复的)列表。 | > > 这些选项仅在Windows上定义特定功能: > > | 选项 | 描述 | > | ------------------ | ------------------------------------------------------------ | > | flat | 使用vcapp模板时,这会将所有源文件置于源组中,并将头文件置于头组中,而不管它们位于哪个目录中。关闭此选项,将根据文件所在目录归类。 默认情况下是打开的。 | > | embed_manifest_dll | 将清单文件嵌入到作为库项目一部分的DLL中。 | > | embed_manifest_exe | 将清单文件嵌入到作为应用程序项目一部分的EXE中。 | > > 有关嵌入清单文件的选项的更多信息,请参见[Platform Notes](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-platform-notes.html#visual-studio-manifest-files)。 > > 以下选项仅在macOS上有效: > > | 选项 | 描述 | > | ------------- | ------------------------------------------------ | > | app_bundle | 将可执行文件放入捆绑包(这是默认设置)。 | > | lib_bundle | 将库放入库包(这是默认设置)。 | > | plugin_bundle | 将插件放入插件包中。 Xcode项目生成器不支持此值。 | > > 捆绑软件的构建过程也受[QMAKE_BUNDLE_DATA](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#qmake-bundle-data)变量内容的影响。 > > 以下选项仅在Linux / Unix平台上有效: > > | 选项 | 描述 | > | ------------------- | ------------------------------ | > | largefile | 支持大文件的包含 | > | separate_debug_info | 把库的调试信息放到单独的文件中 | > > 解析作用域时,将检查CONFIG变量。 您可以为该变量分配任何内容。 > > 例如: > > ``` > CONFIG += console newstuff > ... > newstuff { > SOURCES += new.cpp > HEADERS += new.h > } > ``` ## 自定义函数 接下来是 ``` defineReplace(qtLibraryTargetName) { unset(LIBRARY_NAME) LIBRARY_NAME = $$1 CONFIG(debug, debug|release) { !debug_and_release|build_pass { mac:RET = $$member(LIBRARY_NAME, 0)_debug else:win32:RET = $$member(LIBRARY_NAME, 0)d } } isEmpty(RET):RET = $$LIBRARY_NAME return($$RET) } defineReplace(qtLibraryName) { RET = $$qtLibraryTargetName($$1) win32 { VERSION_LIST = $$split(QTCREATOR_VERSION, .) RET = $$RET$$first(VERSION_LIST) } return($$RET) } defineTest(minQtVersion) { maj = $$1 min = $$2 patch = $$3 isEqual(QT_MAJOR_VERSION, $$maj) { isEqual(QT_MINOR_VERSION, $$min) { isEqual(QT_PATCH_VERSION, $$patch) { return(true) } greaterThan(QT_PATCH_VERSION, $$patch) { return(true) } } greaterThan(QT_MINOR_VERSION, $$min) { return(true) } } greaterThan(QT_MAJOR_VERSION, $$maj) { return(true) } return(false) } # For use in custom compilers which just copy files defineReplace(stripSrcDir) { return($$relative_path($$absolute_path($$1, $$OUT_PWD), $$_PRO_FILE_PWD_)) } ``` ### [Replace Functions](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-language.html#replace-functions) > qmake提供了一些内置函数,以允许处理变量的内容。 这些函数处理提供给它们的参数,并返回一个值或值列表。 `要将结果分配给变量,可以将$$运算符与此类函数一起使用`,就像将一个变量的内容分配给另一个一样: > > ``` > HEADERS = model.h > HEADERS += $$OTHER_HEADERS > HEADERS = $$unique(HEADERS) > ``` > > 此类函数应在赋值的右侧(即,作为操作数)。 > > 您可以定义自己的函数来处理变量的内容,如下所示: > > ``` > defineReplace(functionName){ > #function code > } > ``` > > 以下示例函数将变量名作为唯一参数,使用内置函数eval()从变量中提取值列表,并编译文件列表: > > ``` > defineReplace(headersAndSources) { > variable = $$1 > names = $$eval($$variable) > headers = > sources = > > for(name, names) { > header = $${name}.h > exists($$header) { > headers += $$header > } > source = $${name}.cpp > exists($$source) { > sources += $$source > } > } > return($$headers $$sources) > } > ``` > > 参数$$1 ### [Test Functions](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-language.html#test-functions) > qmake提供了内置函数,可以在编写作用域时用作条件。 这些函数不返回值,而是指示成功或失败: > > ``` > count(options, 2) { > message(Both release and debug specified.) > } > ``` > > 此类函数应仅在条件表达式中使用。 > > 可以定义自己的函数以提供作用域条件。 以下示例测试列表中的每个文件是否存在,如果全部存在,则返回true,否则返回false: > > ``` > defineTest(allFiles) { > files = $$ARGS > > for(file, files) { > !exists($$file) { > return(false) > } > } > return(true) > } > ``` > > 参数列表$$ARGS ### [\_PRO_FILE_PWD_](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#pro-file-pwd) > 包含正在使用的项目文件的目录的路径。(即使该变量出现在 .pri 文件,也是指包含该 .pri 文件的 .pro 文件所在目录的路径。) > > 例如,以下行导致包含项目文件的目录的位置写入控制台: > > ``` > message($$_PRO_FILE_PWD_) > ``` > > 注意:请勿尝试覆盖此变量的值。 ### [\_PRO_FILE_](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-variable-reference.html#pro-file) > 包含正在使用的项目文件的路径。 > > 例如,以下行导致项目文件的位置写入控制台: > > ``` > message($$_PRO_FILE_) > ``` > > 注意:请勿尝试覆盖此变量的值。 现在我们来分析pri中定义的三个函数。 因为这两个函数在 Qt Creator 中使用了多次,并且完全可以拷贝复制到其它项目继续使用。 自定义替换函数`qtLibraryTargetName`。 1. 取消LIBRARY_NAME的定义,设置LIBRARY_NAME为 `$$1`,即函数的第一个参数。 2. CONFIG测试函数判断debug或release模式。 1. 如果是debug模式,再次进行判断。 2. 如果CONFIG没有设置debug_and_release或者是构建过程build_pass,则设置RET变量。对于 mac,LIBRARY_NAME值后面添加_debug赋给RET。对于win,LIBRARY_NAME值后面添加d赋给RET。 3. 如果RET为空,则把LIBRARY_NAME值赋给RET。 4. 返回RET。 简单来说,该函数实现功能:在debug环境下,在库名后面添加\_debug或\_d尾缀,来跟release模式进行区分。当然,也有其他方式来实现上述功能,譬如使用join()函数,见CONFIG小节。 自定义替换函数`qtLibraryName`。 1. 使用qtLibraryTargetName()函数,对输入的第一个参数进行替换,并赋值给RET。 2. 如果 是win32 系统。 1. 使用split()函数,将前面定义的QTCREATOR_VERSION(即4.6.2),使用\'.\'进行分隔得到列表,赋值给VERSION_LIST 2. 使用first()函数,获取VERSION_LIST的第一个元素(即4),与RET拼接,并赋值给RET。 3. 返回RET。 简单来说,该函数实现功能:为了在win32系统中避免出现 dll hell,在win32系统下,在库名后面添加主版本号。 自定义测试函数`minQtVersion`。 1. 获取三个参数(即,主/次/补丁),并赋值给maj,min,patch。 2. maj <= QT_MAJOR_VERSION,min <= QT_MINOR_VERSION和patch <= QT_PATCH_VERSION,则返回true。其他返回false。 简单来说,该函数实现功能:函数参数的版本号小于等于当前Qt的版本号。 自定义替换函数`stripSrcDir`。 1. 获取绝对路径,absolute_path返回$$OUT_PWD/$$1。 2. 获取相对路径,步骤1中获取的绝对路径相对与$$\_PRO_FILE_PWD_的相对路径。 简单来说,该函数实现功能(见自带的注释):用于自定义编译器拷贝文件。 ## 设置macOS最小版本 接下来是: ``` darwin:!minQtVersion(5, 7, 0) { # Qt 5.6 still sets deployment target 10.7, which does not work # with all C++11/14 features (e.g. std::future) QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.8 } ``` 如果是基于Darwin操作系统的,并且Qt 的版本低于`5.7.0`时,设置应用程序支持的macOs最小版本。可以从注释看出,10.7不支持C++11/14特性。 ## 设置QTEST模块 接下来是 ``` QTC_BUILD_TESTS = $$(QTC_BUILD_TESTS) !isEmpty(QTC_BUILD_TESTS):TEST = $$QTC_BUILD_TESTS !isEmpty(BUILD_TESTS):TEST = 1 isEmpty(TEST):CONFIG(debug, debug|release) { !debug_and_release|build_pass { TEST = 1 } } isEmpty(IDE_LIBRARY_BASENAME) { IDE_LIBRARY_BASENAME = lib } equals(TEST, 1) { QT +=testlib DEFINES += WITH_TESTS } ``` 1. 如果设置了QTC_BUILD_TESTS,则赋值给TEST。 2. 如果设置了BUILD_TESTS,则给TEST赋值1。 3. 如果TEST没有值,且为debug模式,并且没有设置debug_and_release,则在构建过程中,设置TEST为1。 4. 如果IDE_LIBRARY_BASENAME为空,则为库赋值基础名为lib。 5. 如果TEST等于1,则添加QTEST模块功能。 ## 设置源目录和构建目录 接下来是 ``` IDE_SOURCE_TREE = $$PWD isEmpty(IDE_BUILD_TREE) { sub_dir = $$_PRO_FILE_PWD_ sub_dir ~= s,^$$re_escape($$PWD),, IDE_BUILD_TREE = $$clean_path($$OUT_PWD) IDE_BUILD_TREE ~= s,$$re_escape($$sub_dir)$,, } ``` ### [re_escape(string)](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#re-escape-string) > 对每个string中的特殊正则表达式字符,使用反斜杠转义,返回转义后的字符串。 该函数是QRegExp::escape的包装。 > > 例如: > > ``` > s1 = QRegExp::escape("bingo"); // s1 == "bingo" > s2 = QRegExp::escape("f(x)"); // s2 == "f\\(x\\)" > ``` ### [clean_path(path)](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#clean-path-path) > 处理path,对目录分隔符进行规范化(转换为"/"),删除了多余的目录分隔符,并且解析"."和".."(尽可能)。 该函数是QDir::cleanPath的包装。 > > 另请阅[absolute_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#absolute-path-path-base), [relative_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#relative-path-filepath-base), [shell_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#shell-path-path), [system_path()](https:/https://img.qb5200.com/download-x/doc.qt.io/qt-5/qmake-function-reference.html#system-path-path). 我们在代码后面插桩输出语句 ``` build_pass:message($$PWD) # 当前pri文件所在目录 build_pass:message($$OUT_PWD) # 生成makefile所在目录 build_pass:message($$_PRO_FILE_) # 包含当前pri的pro所在路径 build_pass:message($$_PRO_FILE_PWD_) # 包含当前pri的pro所在目录 ``` 现在,我们来看一下部分输出。 ``` Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2 Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/bin Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin/bin.pro Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/bin Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2 Project MESSAGE: F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info/src/app Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app/app.pro Project MESSAGE: F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2/src/app ``` 我们可以发现 1. PWD没有发生变化。 2. 对比OUT_PWD和\_PRO_FILE_PWD_,输出目录和源目录的子文件夹组织架构一样。 下面我们分析pri中的语句 1. 设置源目录IDE_SOURCE_TREE。 2. 如果构建目录IDE_BUILD_TREE为空。 1. 设置sub_dir,并进行替换。可以认为是从\_PRO_FILE_PWD_减去PWD,剩下子文件夹相对路径,如bin/和app/。 2. 初始化IDE_BUILD_TREE,并进行替换。可以认为是从OUT_PWD减去相对路径,剩下相同的根目录。 大家可以用我们上面的message输出结果来简单的计算下即可。 IDE_SOURCE_TREE为F:/plugin/qt_creator/qt-creator-opensource-src-4.6.2, IDE_BUILD_TREE为F:/plugin/qt_creator/build-qtcreator-Desktop_Qt_5_11_1_MinGW_32bit-Debug-splt-debug-info。 ## 设置IDE和INSTALLS相关路径 接下来是 ``` IDE_APP_PATH = $$IDE_BUILD_TREE/bin osx { IDE_APP_TARGET = "$$IDE_DISPLAY_NAME" # check if IDE_BUILD_TREE is actually an existing Qt Creator.app, # for building against a binary package exists($$IDE_BUILD_TREE/Contents/MacOS/$$IDE_APP_TARGET): IDE_APP_BUNDLE = $$IDE_BUILD_TREE else: IDE_APP_BUNDLE = $$IDE_APP_PATH/$${IDE_APP_TARGET}.app # set output path if not set manually isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_APP_BUNDLE/Contents IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/Frameworks IDE_PLUGIN_PATH = $$IDE_OUTPUT_PATH/PlugIns IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/Resources IDE_DATA_PATH = $$IDE_OUTPUT_PATH/Resources IDE_DOC_PATH = $$IDE_DATA_PATHhttps://img.qb5200.com/download-x/doc IDE_BIN_PATH = $$IDE_OUTPUT_PATH/MacOS copydata = 1 LINK_LIBRARY_PATH = $$IDE_APP_BUNDLE/Contents/Frameworks LINK_PLUGIN_PATH = $$IDE_APP_BUNDLE/Contents/PlugIns INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Frameworks INSTALL_PLUGIN_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/PlugIns INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources INSTALL_DATA_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/Resources INSTALL_DOC_PATH = $$INSTALL_DATA_PATHhttps://img.qb5200.com/download-x/doc INSTALL_BIN_PATH = $$QTC_PREFIX/$${IDE_APP_TARGET}.app/Contents/MacOS INSTALL_APP_PATH = $$QTC_PREFIX/ } else { contains(TEMPLATE, vc.*):vcproj = 1 IDE_APP_TARGET = $$IDE_ID # target output path if not set manually isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_BUILD_TREE IDE_LIBRARY_PATH = $$IDE_OUTPUT_PATH/$$IDE_LIBRARY_BASENAME/qtcreator IDE_PLUGIN_PATH = $$IDE_LIBRARY_PATH/plugins IDE_DATA_PATH = $$IDE_OUTPUT_PATH/share/qtcreator IDE_DOC_PATH = $$IDE_OUTPUT_PATH/sharehttps://img.qb5200.com/download-x/doc/qtcreator IDE_BIN_PATH = $$IDE_OUTPUT_PATH/bin win32: \ IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/bin else: \ IDE_LIBEXEC_PATH = $$IDE_OUTPUT_PATH/libexec/qtcreator !isEqual(IDE_SOURCE_TREE, $$IDE_OUTPUT_PATH):copydata = 1 LINK_LIBRARY_PATH = $$IDE_BUILD_TREE/$$IDE_LIBRARY_BASENAME/qtcreator LINK_PLUGIN_PATH = $$LINK_LIBRARY_PATH/plugins INSTALL_LIBRARY_PATH = $$QTC_PREFIX/$$IDE_LIBRARY_BASENAME/qtcreator INSTALL_PLUGIN_PATH = $$INSTALL_LIBRARY_PATH/plugins win32: \ INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/bin else: \ INSTALL_LIBEXEC_PATH = $$QTC_PREFIX/libexec/qtcreator INSTALL_DATA_PATH = $$QTC_PREFIX/share/qtcreator INSTALL_DOC_PATH = $$QTC_PREFIX/sharehttps://img.qb5200.com/download-x/doc/qtcreator INSTALL_BIN_PATH = $$QTC_PREFIX/bin INSTALL_APP_PATH = $$QTC_PREFIX/bin } ``` 我们可以发现上面的内容大部分是基于IDE_BUILD_TREE和QTC_PREFIX的。 代码首先设置了可执行程序的目录。 接下来,我们重点分析else分支的内容。 1. 如果TEMPLATE包含vc.*,其实就是vcapp或vclib,设置vcproj为1,表示是vs工程。 2. 设置可执行程序文件名为IDE_ID(默认为qtcreator)。 3. 设置输出路径IDE_OUTPUT_PATH默认为IDE_BUILD_TREE。 4. 设置IDE相关子文件夹路径,可以发现都是相对于IDE_OUTPUT_PATH的。 5. 如果输出路径不是源目录,则设置copydata为1,表示需要拷贝数据。 6. 考虑到IDE_BUILD_TREE与IDE_OUTPUT_PATH可能不一样,设置IDE库和插件的链接路径。 7. 设置INSTALLS用的相关子文件夹路径。 ## 设置字符串宏 接下来是 ``` RELATIVE_PLUGIN_PATH = $$relative_path($$IDE_PLUGIN_PATH, $$IDE_BIN_PATH) RELATIVE_LIBEXEC_PATH = $$relative_path($$IDE_LIBEXEC_PATH, $$IDE_BIN_PATH) RELATIVE_DATA_PATH = $$relative_path($$IDE_DATA_PATH, $$IDE_BIN_PATH) RELATIVE_DOC_PATH = $$relative_path($$IDE_DOC_PATH, $$IDE_BIN_PATH) DEFINES += $$shell_quote(RELATIVE_PLUGIN_PATH=\"$$RELATIVE_PLUGIN_PATH\") DEFINES += $$shell_quote(RELATIVE_LIBEXEC_PATH=\"$$RELATIVE_LIBEXEC_PATH\") DEFINES += $$shell_quote(RELATIVE_DATA_PATH=\"$$RELATIVE_DATA_PATH\") DEFINES += $$shell_quote(RELATIVE_DOC_PATH=\"$$RELATIVE_DOC_PATH\") ``` ### [shell_quote](https://linux.die.net/man/1/shell-quote) > 在qmake中的介绍很简单:为shell对arg加引号,当构建构建项目时。 > > 在linux man page中的介绍:可让您通过shell传递任意字符串,shell不会更改它们。 这使您可以安全地处理带有`嵌入式空格`或shell globbing字符的命令或文件。 ### qmake定义字符串宏 > 有时候,我们想定义字符串宏,并在源代码中进行使用。假设你想在qmake中定义字符串宏,这里有三种途径 > > > > 我们先来看一下qmake编译得到的Makefile.Debug,符合makefile语法的形式 > > > > 现在我们来介绍下DEFINES中的含义: > > 1. NAME1中第一个"对,告诉qmake引导里面的是字符串。里面的\\"对,是对引号的转义,在makefile中变为"。再里面的\\\\对,也是转义,在makefile中变为\\。在里面的\\"同样,最终变为"。最终得到我们想要的字符串。 > > 2. NAME2使用shell_quote()函数,该函数对参数加引号。 > > 3. NAME0对比NAME1,少了最外面的"对,这导致NAME0只能定义没有空格的字符串。如果存在空格,这会导致内容发生变化,中间多了个-D。 > > ``` > qmake: DEFINES += NAME0=\"\\\"app1 .0\\\"\" > makefile: -DNAME0="\"app1 -D.0\"" > ``` > > 此外,对于没有空格的字符串宏定义,我们甚至可以不需要最外层的引号转义。 > > ``` > qmake: DEFINES += NAME0=\\\"app1\\\" > makefile: -DNAME0=\"app1\" > ``` 分析代码: 1. 设置了PLUGIN,LIBEXEC,DATA和DOC相对于BIN的相对路径,譬如PLUGIN的为../lib/qtcreator/plugins。 2. 使步骤1中的变量称为字符串,添加到DEFINES中,变为宏。 ## 设置INCLUDEPATH 接下来是 ``` INCLUDEPATH += \ $$IDE_BUILD_TREE/src \ # for
加载全部内容