qmake手册记录

主要内容概要

  • qmake基本概念介绍;
  • pro文件编写示例;
  • pro文件高级编写语法。
    qmake是Trolltech公司创建的主要用来给qt项目在不同平台和编译器书写Makefile的工具。用qmake,开发者可以创建一个简单的“项目”(.pro文件)然后运行qmake在不同平台下生成适当的Makefile。

!!后续关于qt的相关知识记录在我的gist

qmake相关基本概念

几个名词说明

  • QMAKESPEC环境变量

    • 必须设置为你当前所使用的平台和编译器的组合,否则跨平台编译不会成功。比如,如你使用的是win+msvc,就该把环境变量设为win32-msvc,如果使用的是Solaris和g++,就该设置为solaris-g++。
    • qt/mkspecs中的每一个目录里面,都有一个包含平台和编译器特定信息的qmake.conf文件,这些设置适用于你要使用qmake的任何项目,一般不要进行修改,
  • 项目(.pro)文件

    • 用于告诉qmake关于为这个应用程序创建makefile所需要的细节,如,一个源文件和头文件的列表,任何应用程序特定配置(如一个必须要连接的额外库、或者一个额外的包含路径),都应该放到.pro项目文件中。
  • #注释

    • 可以用#号为项目文件添加注释。注释由”#”符号开始,直到这行结束。

模板

模板变量告诉qmake为这个应用程序生成哪种makefile,有以下可供使用的选择:
- app:建立一个应用程序的makefile。这是默认值,如果模板没有被指定,这个就会被使用;
- lib:建立一个库的makefile(库的文件结构关系,如何被应用程序链接);
- vcapp:建立一个库的Visual Studio项目文件;
- vclib:建立一个库的Visual Studio项目文件;
- subdirs:这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成makefile并且为它调用make的makefile。

“app”模板

“app”模板告诉qmake为建立一个应用程序生成一个makefile,当使用这个模板时,下面这些qmake系统变量是被承认的,这些信息应该在你的.pro文件中指定好。

  • HEADERS 应用程序中所有头文件的列表
  • SOURCES 应用程序中所有源文件的列表
  • FORMS 应用程序中的所有.ui文件(由Qt设计器生成)的列表。
  • LEXSOURCES 应用程序中的所有lex源文件的列表。
  • YACCSOURCES 应用程序中的所有yacc源文件的列表。
  • TARGET 可执行应用程序的名称,默认值为项目文件的名称。(如果需要扩展名,会自动被加上。)
  • DESTDIR 放置可执行程序目标的目录。
  • DEFINES 应用程序所需的额外的预处理程序定义的列表。
  • INCLUDEPATH 应用程序所需的额外的包含理解路径的列表。
  • DEPENDPATH 应用程序所依赖的搜索路径。
  • VPATH 寻找补充文件的搜索路径。
  • DEF_FILE 仅Windows需要:应用程序所需要连接的.def文件。
  • RC_FILE 仅windows需要:应用程序所需要的资源文件。
  • RES_FILE 仅windows需要:应用程序所要连接的资源文件。

如果不需要任何额外的INCLUDEPATH,那么就不需要指定它,qmake会提供默认值,实际的项目文件可能是下面这个样子:

TEMPLATE = app
DESTDIR = c:\helloapp
HEADERS += hello.h
SOURCES += hello.cpp \
            main.cpp
DEFINES += QT_DLL
CONFIG += qt warn_on release

Note:如果条目是单值的,如template或工程目录,用“=”赋值;但如果是多值条目,使用”+=”来为这个类型添加条目。

“lib”模板

“lib”模板告诉qmake为建立一个库而生成makefile(根据makefile进行make之后库会被编译成可调用格式),除了”app”模板中提到的系统变量,还有一个VERSION是被支持的,也需要在”.pro”文件中使用它们

  • VERSION 目标库的版本号,如2.3.1。
“subdirs”模板

“subdirs”模板告诉qmake生成一个makefile,可以进入到特定子目录并为这个目录中的项目文件生成makefile并为它调用make。

在这个模板中只有一个系统变量SUBDIRS可以被识别,这个变量中包含了所要处理的含有项目文件的子目录的列表。这个项目文件的名称和子目录是同名的,这样qmake就可以发现它,如,子目录名是”myapp”,则目录中的项目文件就该叫做myapp.pro

CONFIG变量

配置变量指定了编译器所要使用的选项和所需要被连接的库。配置变量的下面这些选项可以被qmake识别。

  • 这些选项控制着编译器相关标志

    • release 应用程序以release模式连编,如果”debug”被指定,它将被忽略(优先级低于debug)。
    • debug 应用程序以debug模式连编。
    • warn_on 编译器会输出尽可能多的警告信息,如”warn_off”被指定,它将被忽略
  • 这些选项定义了所需要连编的库/应用程序的类型

    • qt 应用程序是一个Qt应用程序(非console),则Qt库会被连接;
    • thread 应用程序是一个多线程应用程序;
    • X11 应用程序是一个X11应用程序或库;
    • windows 只用于“app”模板:应用程序是一个窗口应用程序;
    • console 只用于“app”模板:应用程序是一个控制台应用程序;
    • dll 只用于“lib”模板:库是一个共享库(dll);
    • staticlib 只用于“lib”模板:库是一个静态库。
    • plugin 只用于“lib”模板:库是一个插件,这将会使dll选项生效。

那比如,如果你的应用程序使用Qt库,并且你想把它连编为一个可调试的多线程的应用程序,pro文件中的CONFIG就应该如下设置:

CONFIG += qt thread debug

注意:必须使用”+=”号。

手动安装qmake

当Qt被连编时,默认情况下qmake也会被连编。
在手工连编Qt之前,下面这些环境变量必须被设置
在设置QMAKESPEC时,可以从下面的可能的环境变量列表中进行选择(在/usr/lib/x86_64-linux-gnu/qt5/mkspecs可以查看到各平台的qmake.conf):

aix-64 hpux-64 irix-032 netbsd-g++ solaris-cc unixware7-g++ aix-g++ hpux-g++
linux-cxx openbsd-g++ solaris-g++ win32-borland aix-xlc hpux-n64 linux-g++
openunix-cc sunos-g++ win32-g++ bsdi-g++ hpubx-o64 linux-icc qnx-g++ tru64-cxx
win32-msvc dgux-g++ hurd-g++ linux-kcc reliant-64 tru64-g++ win32-watc freebsd-g++
irix-64 macx-pbuilder reliant-cds ultrix-g++ win32-visa hpux-acc irix-g++ macx-g++
sco-g++ unixware-g hpubx-acc irix-n32 solaris-64 uninxware7-cc

当envvar是以下之一时,环境变量要设置到qws/envvar:

linux-arm-g++ linux-generic-g++ linux-mips-g++ linux-x86-g++ linux-freebsd-g++ 
linux-ipaq-g++ linux-solaris-g++ qnx-rtp-g++
  • QTDIR:必须设置到Qt被安装(或将被安装)到的地方。
    在上述环境变量被设置后,在自己的编译环境下运行make(linux)或者nmake(win)。此时qmake就可以使用了。

10分钟学会使用qmake

1. 创建一个项目文件

qmake使用储存在项目(.pro)文件中的信息来决定Makefile中应该生成什么。

一个基本的项目文件包含关于应用程序的信息,如编译应用程序需要哪些文件,并且使用哪些基本配置设置。

  • 一个简单的示例项目文件
SOURCES = hello.cpp
HEADERS = hello.h
CONFIG += qt warn_on release

对以上例子进行解析:

  • SOURCES = hello.cpp指定实现应用程序的源文件程序当有多个文件时
    1. 可以把所个文件列在一行中,以空格分隔,如
SOURCES = hello.cpp main.cpp
  1. 又或者将每个文件列在一个分开的行中,通过反斜线\另起一行
SOURCES = hello.cpp \
            main.cpp
  1. 或者单独列出每一个文件
SOURCES += hello.cpp
SOURCES += main.cpp
  • HEADERS = hello.h指定为这个应用程序创建的头文件。当有多个文件时,上述适用SOURCES的方法也一样适用于HEADERS文件。

  • CONFIG += qt warn_on release告诉qmake关于应用程序的配置信息。+=添加选项比做=替换是安全得多的

    • qt部分:告诉qmake这个应用程序是使用Qt来连编的,即qmake在为连接和为编译添加所需要的包含路径时就会考虑到Qt库;
    • warn_on部分:告诉qmake把编译器设置为输出警告信息;
    • release部分:告诉qmake应用程序需要被连编成一个发布的应用程序。那在开发过程中,也可以用debug来替换这里的release;

项目文件就是扩展名为.pro的纯文本文件qmake就是根据这个文件确定不同平台下项目的连编规则。发布的应用程序的执行文件的名称必须和项目文件的名称一样,但是扩展名是跟着平台而改变的。举例来说,一个叫做”hello.pro”的项目文件将会在Windows下生成hello.exe,而在Unix下生成”hello”。

2. 生成Makefile

根据.pro项目文件,用qmake就可以生成Makefile:

qmake -o Makefile hello.pro

对于VS用户,qmake也可以生成.dsp(developer studio project)文件:

qmake -t vcapp -o hello.dsp hello.pro

qmake教程

pro文件编写配合qmakemake使用

以一个工程实现一个qmake的编写(在qtcreator中创建工程时,所有的配置信息都会被qt自动在.pro中写好)。当你的工程已经创建了以下文件:

  • hello.cpp
  • hello.h
  • main.cpp

我们按照以下顺序编写项目的.pro文件:
- 添加源文件:

SOURCES += hello.cpp \
            main.cpp
  • 添加头文件
HEADERS += hello.h
  • 目标名称
    • 会被设置为和项目文件一样的名称,但是为了适合平台所需要的后缀。如,win下应该目标名称为“hello.exe”,在Unix下应该是“hello”。
    • 如果想为项目设置一个不同的名字,可以在项目文件中设置它:
TARGET = helloworld
  • 设置CONFIG变量(当在qtcreator中创建工程时,配置信息在进行工程生成时已经被用户选择好且将相关信息配置到pro文件中)
    • 因为这是个qt程序,我们需要把”qt”放到CONFIG这一行中,这样qmake才会在连接时添加相关的库,并且保证mocuic的连编行也被包含到Makefile中。
CONFIG += qt
  • pro文件编写完成后,可以在应用程序目录下的命令行中输入qmake命令来为应用程序生成Makefile:
qmake -o Makefile hello.pro
  • 根据自己使用的编译器,输入make或者nmake

使程序可以调试

应用程序的发布版本不包含任何调试符号或其他调试信息(发行版本进行了代码优化,也是为了运行流畅)。

在开发过程中,要是要生成一个含有相关调试信息的应用程序的调试版本,只要在项目文件的CONFIG变量中添加一个”debug”就可以简单实现。比如对于hello.pro

CONFIG += qt debug
HEADERS += hello.h
SOURCES += hello.cpp
SOURCES += main.cpp

qmake -o Makefile hello.pro就可以生成相应的Makefile,再用makenmake就可以生成debug版本的可执行程序了。

添加特定平台的源文件

应用程序中与平台相关的文件,如现在有两个新文件hello_win.cpphello_x11.cpp要添加到项目中,不能仅仅添加到SOURCES变量中就结束,因为那会把两个文件都添加到Makefile中。这里需要做的事是根据qmake所运行的平台来使用相应的作用域进行处理

  • 为Windows平台添加的平台依赖的文件的简单的作用域看起来如下:
win32{
    SOURCES += hello_win.cpp
}

qmake运行在windows上,它会把hello_win.cpp添加到源文件列表中,如果qmake运行在其他平台时,这部分就会被跳过。

  • 添加一个X11依赖文件的作用域
x11{
    SOURCES += hello_x11.cpp
}

之后像前面一样使用qmake来生成Makefile,之后是make/nmake。此时项目文件应该像下面这样:

CONFIG += qt debug
HEADERS += hello.h
SOURCES += hello.cpp \
            main.cpp
win32{
    SOURCES += hello_win.cpp
}

x11{
    SOURCES += hello_x11.cpp
}

如果一个指定文件不存在,停止qmake

当某个文件不存在时,也许不想生成一个Makefile。

我们可以通过使用exists()函数来检查一个文件是否存在,然后使用error()函数把正在运行的qmake停下来,这和作用域的工作方式一样,只是要将这个函数替换作用域条件。其实前面的作用域条件都是bool值,bool值为真就执行作用域中语句,否则不执行

!exists(main.cpp){
    error("No main.cpp file found")
}

那么此时使用qmake生成Makefile文件,当缺少main.cpp文件时,error信息显示,并且qmake会停止处理。

检查多于一个的条件

假设使用Windows并且在命令行运行你的应用程序时你想显示debug语句,这就需要在连编程序时使用console设置,否则看不到输出,将console添加到CONFIG行中。那如果我们想要(1)在程序运行在win下;(2)且debug在CONFIG行中时;添加console。
- 这就需要两个嵌套的作用域,然后将设置放在最里面的作用域中,如下:

win32{
    debug{
        CONFIG += console
    }
}
  • 嵌套的作用域也可以使用冒号连接起来
win32:debug{
    CONFIG += console
}

到这里,你就已经准备好为你的开发项目写项目文件了。

qmake高级概念–语法

qmake提供了更强大的功能,如可以使用一个简单的项目文件为多个平台生成makefile。

操作符

  • = 简单分配一个值给一个变量,如同赋值操作(覆盖原有值)
  • += 向一个变量的值的列表中添加一个值。
  • -= 从一个变量的值的列表中移去一个值。
  • *= 仅在一个值不存在于一个变量的值的列表中时,把它添加进去。如DEFINES *= QT_DLL只在QT_DLL未被定义在预处理定义的列表中时,才被添加进去。
  • ~= 替换任何与指定正则表达式匹配的任何值(与vim命令相同,模板匹配替换)。如DEFINES ~= s/QT_[DT].+/QT对所有QT_D或QT_T开头的变量,替换成QT。

作用域

功能类似于条件判断语句,当前面的表达式为bool真,作用域中的语句会被执行。

  • 例如,以下语句作用是在windows下使用qmake时,将QT_DLL添加到makefile中。
win32{
    DEFINES += QT_DLL
}
# 也可以用冒号换成以下形式表示
win32:DEFINES += QT_DLL
  • 又比如在除了win平台以外的平台做些处理,
!win32{
    DEFINES += QT_DLL
}
# 或者
!win32:DEFINES += QT_DLL
  • CONFIG行中任何条目都是一个作用域。如CONFIG += warn_on其中的warn_on就是一个作用域。这个特性使得考虑所有可能的编译器标志成为可能:可以针对不同编译器标志采取不同的措施,使项目易于维护和移植。如下例
CONFIG += qt warn_on debug
debug{
    TARGET = myappdebug
}
release{
    TARGET = myapp
}
  • 也可以定义嵌套作用域,为避免写出过多嵌套作用域,可以使用冒号来嵌套作用域。如以下语句检查平台是windows且线程设置是否设定。
win32{
    thread{
        DEFINES += QT_THREAD_SUPPORT
    }
}
# 用冒号嵌套作用域
win32:thread{
    DEFINES += QT_THREAD_SUPPORT
}
  • 还可以用else作用域提供替代声明,当之前的作用域是false时,对应的else作用域会被处理。
win32:xml{
    message(Building for Windows)
    SOURCES += xmlhandler_win.cpp
}else:xml{
    SOURCES += xmlhandler.cpp
}else{
    message("Unknown configuration")
}

变量

除了DEFINE、SOURCES和HEADERS这些系统变量外,用户还可以创建自己的变量,然后在作用域中使用它们。
当对一个给定的名字进行赋值时,qmake就会创建新的变量。例如

MY_VARIABLE = value

也可以通过在其他任何一个变量的变量名前加$$来把这个变量的值分配给当前的变量。例如

MY_DEFINES = $$DEFINES

现在MY_DEFINES变量包含了项目文件在此时DEFINES变量的值,这也和下面的语句等价:

MY_DEFINES = $${DEFINES}

第二种方法允许你将变量的内容附加到另一个值后,而不在两者之间添加空格(相当于拼接)。比如

TARGET = myproject_$${TEMPLATE}

变量可以被用于存储环境变量的内容,这些值在qmake被运行时会被评估(evaluated),或者会被包含在生成的Makefile中而在项目被构建时进行评估。

要在运行qmake时获取环境变量的内容,使用$$(...)操作符:

DESTDIR = $$(PWD)
message(The project will be installed in $$DESTDIR)

在上面的赋值中,PWD环境变量的值会在工程文件被处理时被读出。

如果要在处理生成的Makefile时才去获取一个环境变量的值,使用$(...)操作符,推测主要差别是什么时候用常量值去取代变量,节省空间

DESTDIR = $$(PWD)
message(The project will be installed in $$DESTDIR)

DESTDIR = $(PWD)
message(The project will be installed in the value of PWD)
message(when the Makefile is processed)

在上述的赋值操作中,PWD的值在项目文件(pro文件)被处理时会立即被读出,但是$(PWD)会在生成的Makefile中被赋值给DESTDIR。这使得构建过程更加灵活,只要环境变量在Makefile被处理时被正确设置了的话。

还有一个特殊的$$[...]操作符,可以被用来获取构建Qt时不同的设置选项。

message(Qt version:$$[QT_VERSION])
message(Qt is installed in $$[QT_INSTALL_PREFIX])
message(Qt resources can be found in the following loacations:)
message(Documentation:$$[QT_INSTALL_DOCS])
message(Header files:$$[QT_INSTALL_HEADERS])
message(Libraries:$$[QT_INSTALL_LIBS])
message(Binary files(executables):$$[QT_INSTALL_BINS])
message(Plugins:$$[QT_INSTALL_PLUGINS])
message(Data files:$$[QT_INSTALL_DATA])
message(Translation files:$$[QT_INSTALL_TRANSLATIONS])
message(Settings:$$[QT_INSTALL_SETTINGS])
message(Examples:$$[QT_INSTALL_EXAMPLES])
message(Demonstrations:$$[QT_INSTALL_DEMOS])

可以通过这个操作符获取的变量,经常被用于使得整合到Qt中的第三方的插件和组件可用。比如说,按照下面的声明,一个Qt Designer插件可以被安装为Qt Designes的内建插件目录下。

target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target

变量处理函数

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)
}

测试函数

qmake提供了一些测试函数,这些函数也可以用作书写作用域时的条件,这些函数不返回一个值,而是指示着”success”或者”failure”(bool值)。

  • contains(variablename,value):如果value存在于一个叫做variablename的变量的值的列表中,则执行作用域中内容:
contains(VCONFIG,thread){
    DEFINES += QT_THREAD_SUPPORT
}
  • count(variablename,number):如果variablename变量的值的总数是number个,那么这个作用域中的设置会被执行。
count(DEFINES, 5){
    CONFIG += debug
}
  • error(string):输出指定字符串,然后使qmake退出。
error("An error has occured")
  • exists(filename):如果指定文件存在,那么这个作用域中的设置会被处理。注意:可以不用考虑平台,一致使用/作为目录的分隔符
exists(/local/qt/qmake/main.cpp){
    SOURCES += main.cpp
}
  • include(filename):项目文件在执行到此语句时包含这个文件名的内容,那么作用域中的设置被执行。
include(myotherapp.pro){
}
  • isEmpty(variablename):如果variablename变量中没有任何元素,那么这个作用域中的设置会被处理。
isEmpty(CONFIG){
    CONFIG += qt warn_on debug
}
  • system(command):指令执行且如果返回值为1,则作用域中内容被执行。

  • infile(filename,var,val):如果filename文件包含一个值为val的变量var,那么这个函数将返回成功,第三个参数val省略时,只测试文件中是否有这样一个变量。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值