欢迎使用 WordPress。这是系统自动生成的演示文章。编辑或者删除它,然后开始您的博客!
LookUpHost2011.2.24版本
pydns2.3.4文档翻译:请阅读.txt,README.txt
pydns2.3.4 文档翻译:请阅读.txt,README.txt
来源:pydns2.3.4源代码中的README.txt
使用:
import DNS
reqobj=DNS.Request(args)
reqobj.req(args)
args可以是一个域名,那样就会将它拿来查询,以及/或者是一组键/值对的序列组成的args。(看下面的内 容,了解与args 列表相关的东西)
当你调用’req()’方法时,它会将在DNS.Request()调用中指定的选项作为默认值来复用。
选项是按照下面的顺序来应用的:
在req()调用中指定的选项
或者,如果在这里没有指定的话,
在创建Request()对象时指定的选项
或者,如果在这里没有指定的话,
那些在DNS.defaults 字典中指定的选项
可使用以下方法来指定域名服务器:
-
•.通过调用 DNS.DiscoverNameServers()。在 Unix 上,它会从系统的/etc/resolv.conf文件中载入服务器。在 windows 上,它会从注册表中载入。
-
•.以一个选项的方式在 请求中指定
-
•.通过手动地将 DNS.defaults['server']设置成一个要尝试的IP地址列表
-
•.XXXX 应当也可以在一个mac os 机器上从它们保存这个选项的地方载入DNS 服务器
name=”host.do.main” # 要查询的对象
qtype=”SOA” # 查询类型,例如SOA、A、MX、CNAME、ANY
protocol=”udp” # “udp”或者”tcp” – 通常情况下你会使用”udp”
server=”nameserver” # 域名服务器的域名。注意,你可能会在这里使用一个IP 地址。
rd=1 # “递归模式(recursion desired)” – 默认是1。
其它:opcode, port, …
还有一些为懒人准备的便利函数:
做一个反向查询:
>>> print DNS.revlookup(“192.189.54.17″)
yarrina.connect.com.au
查询某个条目的所有MX 记录:
>>> print DNS.mxlookup(“connect.com.au”)
[(10, 'yarrina.connect.com.au'), (100, 'warrane.connect.com.au')]
这个库的接口的剩余部分的文档要以后才能写出来。注意,DnsAsyncRequest当前不起作用-我还没找 到原因。
在tests/目录中有一些示例-包括test5.py,它也许有用。它查询某个域的SOA,检查确认主NS 是权威的,然后检查那些它认为是这个域的NS的域名服务器以确认它们是权威的、并且区的序列号是匹配的。
参见README.guido以查看原来的文档。
向我发送评论,anthony@interlink.com.au, 或者发到邮件列表,pydns-developer@lists.sourceforge.net.
向 SF 上的跟踪器提交问题/补丁-http://sourceforge.net/tracker/?group_id=31674
2011.1.10版本发布
Qt4.7.0文档翻译:QThread类参考,QThread Class Reference
< ?xml version="1.0" encoding="UTF-8"?>
< !DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd">
Qt4.7.0文档翻译:QThread类参考,QThread Class Reference
QThread 类提供与平台无关的线程。
一个QThread表示程序中的一个单独的控制线程;它与同一进程中的其它所有线程共享数据,但是以一个多任务的操作系统中的独立程序的方式来独立地运行。QThread不是从main()开始执行的,而是从run()开始的。默认地,run()通过调用exec()来启动事件循环(下面有例子)。要创建你自己的线程,就继承QThread并且重载run()。例如:
class MyThread : public QThread
{
public:
void run();
};
void MyThread::run()
{
QTcpSocket socket;
//在别的有意义的地方连接QTcpSocket 的信号
…
socket.connectToHost(hostName, portNumber);
exec();
}
这将在线程里创建一个QTcpSocket,并且启动线程的事件循环。使用start()方法来开始执行。当你从run()返回时,执行就结束咯,就好像一个程序离开main()之后就结束一样。当那个线程启动(started())、结束(finished())和终止(terminated())时,QThread 会通过一个信号告诉你,或者你可以使用isFinished()和isRunning()来查询那个线程的状态。使用wait()来阻塞自己,直到那个线程结束了运行。
每个线程都从操作系统获取它自己的栈。操作系统还确定栈的默认大小。你可以使用setStackSize()来设置一个自定义的栈大小。
每个QThread 都可以有它自己的事件循环。你可以通过调用exec()来启动事件循环;你可以通过调用exit()或者quit()来停止它。在一个线程中有了事件循环就使得可以使用一种叫做排队连接(queued connections)的机制来将其它线程中的信号连接到这个线程中的信号槽上。它也使得可以在线程里面使用那些需要有事件循环的类,例如QTimer和QTcpSocket。然而,注意,不可能在线程里面使用任何的部件类。
在极端情况下,你可能想要强制终止(terminate())一个正在执行的线程。然而,这么做是危险的,并且不被提倡的。请阅读terminate()和setTerminationEnabled()的文档,以了解细节信息。
静态函数currentThreadId()和currentThread()返回当前正在执行的线程的标识符。前一个函数为线程返回一个与平台相关的标识符;后一个函数返回一个QThread 指针。
QThread 还提供了与平台无关的不同精度的睡眠函数。使用sleep()来实现整秒的精度,使用msleep()来实现毫秒的精度,使用usleep()来实现微秒的精度。
参考Qt中的线程支持、QThreadStorage、QMutex、QSemaphore、QWaitCondition、Mandelbrot示例、Semaphores示例和等待条件(Wait Conditions)示例。
2010.12.31版本发布
Qt4.7.0文档翻译:配置qmake的环境,Configuring qmake’s Environment
< ?xml version="1.0" encoding="UTF-8"?>
< !DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd">
Qt4.7.0文档翻译:配置qmake的环境,Configuring qmake’s Environment
属性
qmake有一个持久存储信息的系统,这允许你只需要在qmake 中对一个变量设置一次,以后每次调用时都能查询到这个值。使用下面的方法来在qmake 中设置一个属性:
qmake -set 变量 值
应当使用适当的变量和值来替换命令中的变量和值。
你可以这样从 qmake 中查询这个信息:
qmake -query 变量
qmake -query #查询当前所有的变量/值对……
注意:qmake -query只会列出你以前使用qmake -set 变量 值设置的变量。
这个信息将会保存到一个QSettings对象中(意味着它在不同的平台上将保存在不同的地方)。由于变量也是有版本的,所以你可以在一个旧版本的qmake里设置一个值,在新版本里就能获取这个值。然而,如果你为一个新版本的qmake设置变量,那么旧版本将不使用这个值。然而,如果你将qmake的版本号加在变量的前面,那么你可以查询一个指定版本的变量,像下面这个例子一样:
qmake -query “1.06a/变量“
qmake还支持查询内置属性,例如,你可以使用QT_INSTALL_PREFIX属性来查询这个版本的qmake使用的Qt的安装路径。
qmake -query “QT_INSTALL_PREFIX”
这些内置的属性不能加上版本号前缀使用,因为它们没有版本,并且每个版本的qmake都会有它自己的内置属性的集合。下面的列表汇总了内置的属性:
-
•.QT_INSTALL_PREFIX - 这个qmake 使用的Qt 版本的位置
-
•.QT_INSTALL_DATA - 这个版本的Qt 的数据的位置(本座查了一下,/usr/lib/qt4)
-
•.QMAKE_VERSION - 当前qmake的版本
最后,可以在项目文件中使用一种特殊的表示方法来查询这些值,比如:
QMAKE_VERS = $$[QMAKE_VERSION]
QMAKESPEC
qmake需要一个平台和编译器描述文件,这个文件包含很多默认值,qmake用它们来生成合适的Makefile。标准的Qt 发布中有很多这样的文件,位于Qt 安装目录的mkspecs子目录中。
QMAKESPEC环境可以包含下面的东西中的任意一个:
-
•.到一个包含一个qmake.conf文件的目录的完整路径。在这种情况下,qmake会打开那个目录下的qmake.conf文件。如果那个文件不存在,qmake就会报告错误并且退出。
-
•.一个平台-编译器组合的名字。是一个组合的名字。在这种情况下,qmake会在编译Qt 时指定的数据路径(查看QLibraryInfo::DataPath)中的mkspecs子目录下搜索。
注意:QMAKESPEC路径会自动地添加到INCLUDEPATH系统变量中。
INSTALLS
在 Unix 上,使用构建工具来安装程序和库是很平常的;例如,执行make install。由于这个原因,qmake有一个安装集的概念,这个对象包含了一些关于项目的哪一部分要被安装的指令。例如,一组文档文件可以用下面的方式描述:
documentation.path = /usr/local/program/doc
documentation.files = docs/*
path成员告诉qmake文件应当被安装到/usr/local/program/doc(path成员),而files成员指定了应当被复制到安装目录中去的文件。在这个例子里,docs目录中的所有东西都会被复制到/usr/local/program/doc。
一旦完整地描述了一个安装集,你就可以用这样的一行将它追加到安装列表中:
INSTALLS += documentation
qmake将会确保指定的文件被复制到安装目录中。如果你想对这个过程进行更有力的控制,你还可以为这个对象定义一个extra成员。例如,下面的这一行告诉qmake为这个安装集执行一系列的命令:
unix:documentation.extra = create_docs; mv master.doc toc.doc
unix作用域(查看作用域和条件)确保这些特殊的命令只在Unix 平台上执行。适合其它平台的命令可以使用其它作用域规则来定义。
extra成员中指定的命令会在对象的其它成员中的指令处理之前执行。
如果你将一个内置的安装集追加到INSTALLS变量中,而不指定files或者extra成员,那么qmake将会为你决定需要复制什么东西。目前,支持的唯一的内置安装集就是target:
target.path = /usr/local/我的程序
INSTALLS += target
在上面的几行里,qmake知道需要复制什么东西,会自动地处理安装过程。
缓存文件
缓存文件是一个特殊文件,qmake从中读取没有在qmake.conf文件、项目文件或者命令行指定的设置信息。如果在运行qmake的时候没有指定-nocache选项,那么它会尝试在当前目录的那些上级目录里寻找一个.qmake.cache文件。如果它没有找到这个文件,那么它会忽略这一步的处理过程。
如果它找到了一个.qmake.cache文件,那么它会在处理项目文件之前处理这个文件。
库依赖
在与一个库做链接时,qmake经常依赖下层的平台来得知这个库与哪些库链接,并且让平台将它们引入。然而,在很多情况下,这是低效的。例如,当静态链接一个库时,没有与其它库链接,因此就没有创建到那些库的依赖。然而,稍后与这个库做链接的程序将会需要知道去哪里找到这个静态库需要的符号。为了应对这种情况,qmake尝试在适当的时候跟踪这个库的依赖,但是必须按照两个步骤来显式地启用这个行为。
第一步是在库自身启用依赖跟踪。要做到这一点,你必须告诉qmake要保存这个库的信息:
CONFIG += create_prl
这只对lib模板有效,当使用其它模板时会被忽略。当使用这个选项时,qmake会创建一个扩展名为.prl的文件,它会保存这个库的一些元信息。这个元文件就像一个普通的项目文件一样,但是只包含内部变量的定义。你可以随意查看这个文件,如果它被删除了,那么qmake会在需要的时候重新创建它,或者是在稍后读取这个项目文件的时候,或者是在一个依赖库(下面描述)发生改变的时候。当你通过将它指定为INSTALLS声明中的一个目标的方法来安装这个库的时候,qmake会自动地将这个.prl文件复制到安装路径中。
这个过程中的第二步就是在使用这个静态库的程序里面启用对这个元信息的读取:
CONFIG += link_prl
当这个选项被启用时,qmake将会处理这个程序链接到的所有的库,并且查找它们的元信息。qmake会使用这个来确定相关的链接信息,尤其是将一些值添加到程序的项目文件的DEFINES和LIBS列表里。一旦qmake处理完了这个文件,它会检查LIBS变量中新引入的库,找到它们依赖的.prl文件,继续这个过程直到解决了所有的库的依赖关系。在这个时候,照常地创建Makefile,而那些库会显式地与这个程序链接起来。
.prl文件的内部格式是封闭的,这样它们随后可以轻易改变。它们不是设计为让你手动修改的,它们只应当由qmake来生成,不应当在操作系统之间传递,因为它们可能包含与平台相关的信息。
文件扩展名
在一般情况下,qmake会尝试使用适合于你的平台的文件扩展名。然而,有些时候有必要为每个平台覆盖掉默认的选项并且显式地定义文件扩展名以让qmake使用。这是通过重新定义特定的内置变量来实现的;例如,可以在项目文件中使用以下赋值语句来重定义用于moc文件的扩展名:
QMAKE_EXT_MOC = .mymoc
以下变量可用来重定义qmake使用的普通文件的扩展名:
-
•.QMAKE_EXT_MOC – 这个变量修改那些被包含的moc 文件的扩展名。
-
•.QMAKE_EXT_UI – 这个变量修改用于设计师的界面文件(通常是在FORMS中)的扩展名。
-
•.QMAKE_EXT_PRL – 这个变量修改库依赖文件的扩展名。
-
•.QMAKE_EXT_LEX – 这个变量修改lex文件(通常在LEXSOURCES中)的扩展名。
-
•.QMAKE_EXT_YACC – 这个变量修改yacc文件(通常在YACCSOURCES中)的扩展名。
-
•.QMAKE_EXT_OBJ – 这个变量修改生成的对象文件的扩展名。
以上变量只接受一个值,所以你必须只给它们赋予一个值,这个值将在整个项目文件中使用。有两个变量接受一组值:
-
•.QMAKE_EXT_CPP – 导致qmake将所有拥有这些扩展名的文件当成C++源代码文件来解释。
-
•.QMAKE_EXT_H – 导致qmake将所有拥有这些扩展名的文件当成C 和C++头文件来解释。
自定义Makefile 的输出
qmake努力做到一个跨平台的构建工具应当做到的任何事情。当你实在需要运行特殊的与平台相关的命令时,事情通常就不那么完美了。这件事情可以针对不同的qmake后端来采用特殊的指令来完成。
就像在qmake的其它地方一样,对 Makefile 的自定义输出也是通过一个面向对象风格的应用编程接口来实现的。当指定一些对象的成员时,这些对象也被自动定义;例如:
mytarget.target = .buildfile
mytarget.commands = touch $$mytarget.target
mytarget.depends = mytarget2
mytarget2.commands = @echo Building $$mytarget.target
上面的定义中,定义了一个叫做mytarget的qmake对象,它包含了一个叫做.buildfile的Makefile 目标,而这个目标又是使用touch命令生成的。最后,.depends成员指定了mytarget依赖于mytarget2,那是稍后定义的另一个目标。mytarget2是一个虚设的目标;它只是用来向终端输出一些文字。
最后一步就是告诉qmake,这个对象是一个要被构建的目标:
QMAKE_EXTRA_TARGETS += mytarget mytarget2
这就是你为了构建自定义目标时所需要做的全部事情。当然,你可能想要将这些目标中的一个与qmake构建目标绑定。要做到这一点,你只需要简单地将你的Makefile 目标包含到PRE_TARGETDEPS列表中。
下面的表格中列出的是你可以在QMAKE_EXTRA_TARGETS 变量中使用的选项的概述。
|
成员 |
描述 |
|
commands |
用来生成自定义构建目标的命令。 |
|
CONFIG |
针对自定义构建目标的特定配置选项。查看CONFIG 表格,以了解细节。 |
|
depends |
这个自定义构建目标依赖的已有的构建目标。 |
|
recurse |
指定在子目标特定的Makefile 中创建规则时,应当使用哪个子目标。仅当 CONFIG 中设置了recursive时,才使用这个。 |
|
recurse_target |
指定在Makefile 中要使用子目标Makefile 来构建的规则的目标。这将添加类似这样的语句:$(MAKE) -f Makefile.[subtarget] [recurse_target]。仅当 CONFIG 中设置了recursive时,才使用这个。 |
|
target |
由这个自定义构建目标创建的文件。 |
CONFIG 选项的成员列表:
|
成员 |
描述 |
|
recursive |
指明要在Makefile 中创建规则,并且在要子目标特定的Makefile 中调用相应的目标。默认情况下为每个子目标创建一个条目。 |
为了方便,也可以为新的编译器或者预处理器对项目进行自定义设置:
new_moc.output = moc_${QMAKE_FILE_BASE}.cpp
new_moc.commands = moc ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_OUT}
new_moc.depend_command = g++ -E -M ${QMAKE_FILE_NAME} | sed “s,^.*: ,,”
new_moc.input = NEW_HEADERS
QMAKE_EXTRA_COMPILERS += new_moc
使用上面的定义,在有替代品的情况下,你可以为moc插入一个替代品。这个命令将在NEW_HEADERS变量(来自input成员)的全部参数上执行,而结果会被写入到output成员定义的文件中;这个文件将会加入到项目中其它的源代码文件里面。另外,qmake会执行depend_command来生成依赖信息,并且将这个信息也放到项目中。
这些命令可以轻易地放到一个缓存文件中,允许后面的项目文件向NEW_HEADERS里添加新的参数。
下面的表格是你可以在QMAKE_EXTRA_COMPILERS 变量中使用的选项的概述。
|
成员 |
描述 |
|
commands |
用来依据输入生成输出的命令。 |
|
CONFIG |
针对自定义编译器的特殊配置选项。查看CONFIG 表格,以了解细节。 |
|
depend_command |
指定一个用于为输出的东西生成依赖列表的命令。 |
|
dependency_type |
指定输出的文件的类型,如果它是一个已知的类型(例如TYPE_C、TYPE_UI、TYPE_QRC),那么它将会被当作那些类型的文件处理。 |
|
depends |
指定输出文件的依赖关系。 |
|
input |
包含那些应当由自定义编译器处理的文件的变量。 |
|
name |
对那个自定义编译器做的事情的描述。这只用于某些后端。 |
|
output |
由自定义编译器创建的文件的名字。 |
|
output_function |
指定一个自定义的用来指定将要创建的文件的名字的qmake 函数。 |
|
variable_out |
要将从输出文件创建的文件添加到的变量。 |
与CONFIG 选项相关的成员列表:
|
成员 |
描述 |
|
commands |
用来依据输入生成输出的命令。 |
|
CONFIG |
针对自定义编译器的特殊配置选项。查看CONFIG 表格,以了解细节。 |
|
depend_command |
指定一个用于为输出的东西生成依赖列表的命令。 |
|
dependency_type |
指定输出的文件的类型,如果它是一个已知的类型(例如TYPE_C、TYPE_UI、TYPE_QRC),那么它将会被当作那些类型的文件处理。 |
|
depends |
指定输出文件的依赖关系。 |
|
input |
包含那些应当由自定义编译器处理的文件的变量。 |
|
name |
对那个自定义编译器做的事情的描述。这只用于某些后端。 |
|
output |
由自定义编译器创建的文件的名字。 |
|
output_function |
指定一个自定义的用来指定将要创建的文件的名字的qmake 函数。 |
|
variables |
指示,如果在这里指定的变量在pro 文件中以$(VARNAME)的形式引用,那么将被替换成$(QMAKE_COMP_VARNAME)的形式。 |
|
variable_out |
要将从输出文件创建的文件添加到的变量。 |
与CONFIG 选项相关的成员列表:
|
成员 |
描述 |
|
combine |
指示,所有的输入文件合并到一个输出文件里面。 |
|
target_predeps |
指示,输出的东西应当添加到PRE_TARGETDEPS 的列表里面。 |
|
explicit_dependencies |
输出的东西的依赖关系只由depends 成员生成,而不由其它的任何东西生成。 |
|
no_link |
指示,输出的文件不应当添加到要链接的对象的列表里面。 |
注意:与Symbian平台相关:在Symbian 平台上,不支持生成要链接的对象,所以应当一直为附加编译器定义CONFIG的no_link选项或者variable_out变量。
Qt4.7.0文档翻译:在X11平台上部署程序,Deploying an Application on X11 Platforms
Qt4.7.0文档翻译:在X11平台上部署程序,Deploying an Application on X11 Platforms
由于Unix 系统的变种繁多(商业Unices、Linux发行版,等等),在 Unix 上部署程序是一个复杂的事情。在我们开始之前,先告诉你,为某个变 Unix 种系统编译的程序不一定能在另一个Unix 系统上运行。例如,除非你使用交叉编译器,否则你无法在 Irix 上编译你的程序再将它发布到AIX 上。
内容:
这个文档描述的是,如何确定在你发布的软件包里面要包含哪些文件,如何确保程序在运行的时候能找到它们。我们将在部署Qt 的示例目录中提供的插件和画画程序的同时演示这个过程。
静态链接
静态链接通常是在 Unix 上发布程序的最安全、最简单的方法,因为它让你免去了这些工作:发布Qt 库,并确保它们位于目标系统上查找库的默认路径中。
以静态方式构建Qt
要使用这种方法,你必须先安装Qt 库的静态版本:
cd /到/Qt/的路径
./configure -static -prefix /到/Qt/的路径 <其它参数>
make sub-src
我们指定了前缀,这样我们就不会覆盖掉已安装的Qt 了。上面的例子仅仅构建Qt 库,也就是说,那些示例还有Qt Designer 都不会被构建。当make完成之后,你将在/到/Qt/的路径/lib目录中找到Qt 库。
当你将程序与Qt 库静态链接时,注意,你可能需要向你的项目文件中的LIBS行中添加更多的库。要了解更多信息,就去看程序依赖小节。
将程序与Qt的静态版本链接
当Qt 的静态构建完成时,下一步就是重新生成makefile、重新构建程序。首先,我们必须进入包含了这个程序的目录:
cd /到/Qt/的路径/examples/tools/plugandpaint
现在运行qmake 为程序创建一个新的makefile,再进行一次干净的构建,以创建静态链接的可执行程序:
make clean
PATH=/到/Qt/的路径/bin:$PATH
export PATH
qmake -config release
make
你可能想要与发布(release)版的库链接起来,可以在执行qmake的时候指定这个。注意你必须将路径设置成我们刚刚构建的静态Qt 的路径。
要检查以确认这个程序真的与Qt 静态链接在一起,那就运行ldd工具(在大多数Unices 上都有):
ldd ./application
检查确认在输出里面没有提到Qt 库。
现在,在确定所有的东西都正确地编译和链接了之后,我们应当有了一个可以部署的plugandpaint文件了。一个简单的检查这个程序是否能独自运行的方法就是将它复制到一个没有Qt 以及任何的Qt 程序的机器上,再运行它。
记住,如果你的程序依赖了编译器的一些库,那么这些库仍然需要与你的程序一起重新发布。要了解更多信息,就去看程序依赖小节。
插插画画示例由多个组件构成:核心程序(插插画画)、以及基本工具和扩充过滤器插件。由于我们无法将插件用静态链接的方法来部署,所以我们准备好的可执行程序到现在还是不完整的。程序会运行,但是那些功能都会被禁用,因为找不到插件。要部署基于插件的程序,我们应当使用共享库的方式。
共享库
当我们使用共享库的方式来部署插插画画程序时,面临着两个挑战:Qt 运行时库必须与程序一起正确地发布,而插件必须安装到目标系统上正确的位置,这样程序才能找到它们。
以共享库的方式来构建 Qt
我们假设你已经将Qt 作为一个共享库安装了,因为那是安装Qt 时的默认方式,并且你安装到了/到/Qt/的路径目录。要了解更多关于构建Qt 的信息,就去看安装文档。
将Qt 作为共享库与程序链接
在确定Qt 是以共享库的方式构建的之后,我们可以构建插插画画程序了。首先,我们必须进入到包含了这个程序的目录:
cd /到/Qt/的路径/examples/tools/plugandpaint
现在运行qmake,为程序创建一个新的makefile,再进行一次干净的构建,以创建动态链接的可执行程序:
make clean
qmake -config release
make
这就构建了核心程序,下面的操作构建插件:
cd ../plugandpaintplugins
make clean
qmake -config release
make
如果所有的东西都正确地编译和链接了,我们就会得到一个plugandpaint可执行程序以及libpnp_basictools.so和libpnp_extrafilters.so插件文件。
创建一个程序包
在 Unix 上没有标准的包管理系统,所以我们在下面展示的是一个通用解决方法。查看你的目标系统的文档,看看该怎么创建一个软件包。
要部署这个程序,我们必须确保将相关的Qt 库(对应于在程序中用到的Qt 模块)和可执行程序都复制到同一个目录中。记住,如果你的程序依赖于编译器提供的库,那么那些库也应当与你的程序一起发布。要了解更多信息,就去看程序依赖小节。
我们稍后再说插件,现在主要的问题是,在使用共享库的情况下,你必须确保动态链接程序能够找到Qt 库。除非是你告诉了它,否则动态链接程序不会在你的程序所在的目录里查找。有很多方法可以解决这个问题:
-
•.你可以将Qt 库安装到系统的某个库路径里(例如,在大多数系统上是/usr/lib)。
-
•.你可以在链接程序的时候将一个预先确定的路径传递给-rpath命令行选项。这将导致动态链接程序在启动你的程序时在这个指定的目录里面查找库。
-
•.你可以为你的程序写一个启动脚本,在那里面修改动态链接程序的配置(例如,将你的程序的目录添加到LD_LIBRARY_PATH环境变量中。注意:如果你的程序将会以”指定用户”的方式运行,并且指定的用户是root,那么在某些平台上LD_LIBRARY_PATH 会被忽略。在这种情况下,使用LD_LIBRARY_PATH的方法无效)。
第一种方法的缺点是,用户必须拥有超级用户权限。第二种方法的缺点是,用户可能没有将库安装到预定义的路径的权限。在这两种情况下,用户都不能将程序安装到他她们的家目录中。我们建议使用第三种方法,因为它最灵活。例如,plugandpaint.sh脚本可以写成这样:
#!/bin/sh
appname=`basename $0 | sed s,.sh$,,`
dirname=`dirname $0`
tmp=”${dirname#?}”
if [ "${dirname%$tmp}" != "/" ]; then
dirname=$PWD/$dirname
fi
LD_LIBRARY_PATH=$dirname
export LD_LIBRARY_PATH
$dirname/$appname $*
通过运行这个脚本,而不是那个可执行程序,你可以确定动态链接程序能够找到Qt 库。注意,当你在其它程序中使用这个脚本时,你仅仅需要将脚本改个名字。
当查找插件时,程序会在自己所在的目录中的一个插件子目录里查找。你或者需要手动地将插件复制到plugins目录,或者可以在插件的项目文件里设置DESTDIR:
DESTDIR = /到/Qt/的路径/plugandpaint/plugins
一个用于发布在运行Plug & Paint程序的时候所需的所有Qt 库、所有插件的软件包,将会包含以下文件:
|
组件 |
文件名 |
|
可执行程序 |
plugandpaint |
|
用来运行可执行程序的脚本 |
plugandpaint.sh |
|
基本工具插件 |
pluginslibpnp_basictools.so |
|
扩展过滤器插件 |
pluginslibpnp_extrafilters.so |
|
Qt核心模块 |
libQtCore.so.4 |
|
Qt图形界面模块 |
libQtGui.so.4 |
在大多数系统上,共享库的扩展名是.so。一个值得注意的例外是HP-UX,它使用.sl。
记住,如果你的程序依赖编译器提供的一些库,那么它们也应当与你的程序一起发布(搞个鸟,这句话出现好多遍)。要了解更多信息,就去看程序依赖小节。
要验证这个程序现在可以成功部署,你可以将这个软件包在一个没有Qt 和任何编译器的机器上解压,再尝试运行它,实际上,就是运行plugandpaint.sh脚本。
除了将插件放到plugins子目录中这种方法之外,另外一种方法就是在你的程序启动的时候使用QApplication::addLibraryPath()或者QApplication::setLibraryPaths()来添加一个自定义的查找路径。
qApp->addLibraryPath(“/其它/的/路径”);
程序依赖
其它的库
要找出你的程序依赖哪个库,就运行ldd工具(在大多数Unices 上都有):
ldd ./application
这将列出你的程序依赖的所有共享库。依据配置情况,这些库都必须随你的程序重新发布。特别地,如果你使用的编译器与系统的编译器是二进制不兼容的,那么还需要发布标准C++库。在可能的时候,最安全的解决方法就是将程序与这些库静态链接。
你可能要将程序与常规X11 库动态链接,因为在某些库中会尝试使用dlopen()来打开其它共享库,而如果那个操作失败了,那么X11 库可能引起你的程序崩溃。
还有一个值得提醒的事情,Qt可能会寻找某些X11 扩展,例如Xinerama 和Xrandr,并且可能会将它们引用进来,这还包括它们链接到的其它库。如果你不能确保某个扩展的存在性,那么最安全的办法就是在配置Qt 的时候禁用它(例如,./configure -no-xrandr)。
FontConfig和FreeType是另外两个不一定存在或者不一定有二进制兼容性的库的例子。可能听起来很奇怪,某些软件厂商通过在非常旧的机器上编译他她们的软件并且仔细地确保不要升级它们系统上的任何软件来取得成功。
当你将程序与Qt 库静态链接时,你必须显式地与上面提到的依赖库链接。将它们添加到你的项目文件中的LIBS变量,以实现这一点。
Qt插件
你的程序还可能依赖一些Qt 插件,比如JPEG 图片格式插件或者SQL 驱动插件。确保将你的程序需要的全部Qt 插件都发布了,并且注意,每种插件都应当放置到你的发布目录中的一个特定子目录中(例如imageformats或者sqldrivers),下面将描述。
注意:如果你在部署一个使用QtWebKit来显示互联网上的网页的程序,你应当包含全部的文字编码插件以支持尽可能多的网页编码。
查找Qt 插件的路径(还有其它的一些路径)是硬编码到QtCore库中的。默认地,第一个插件查找路径将会硬编码为/到/Qt/的路径/plugins。就像上面提到的那样,使用预定义的路径有一些缺点,所以你需要尝试多种变通方法以确保可以找到Qt 插件:
-
•.使用QApplication::addLibraryPath()或者QApplication::setLibraryPaths()。
-
•.使用一个第三方的安装工具或者是目标系统的包管理器来改变QtCore库中的硬编码路径。
如何创建Qt插件文档说明了你在为Qt 程序构建和部署插件时应当注意的事情。
Qt4.7.0文档翻译:部署Qt 程序,Deploying Qt Applications
Qt4.7.0文档翻译:部署Qt 程序,Deploying Qt Applications
部署一个Qt 程序不需要进行任何的C++编程。你所需要做的就是按照这个文档里描述的步骤以发布(release)模式构建Qt 和你的程序。我们会在部署Qt 示例目录里面提供的即插即画程序的同时演示这个过程。
静态库还是动态库
有两种部署程序的方式:
-
•.静态链接
-
•.共享库(在Mac上叫做框架(Frameworks))
静态链接将产生一个独立的可执行程序。优点是,你只需要部署很少的几个文件。缺点是,可执行程序很大,并且没有灵活性(也就是说,如果这个程序或者Qt 有新的版本了,那么部署过程就要重复一次),而且你无法部署插件。
要部署基于插件的程序,你可以使用共享库的方式。共享库也使得可执行程序更小、更灵活。例如,当使用共享库的方式时,用户可以自由地将程序所使用的Qt 库升级。
另一个可能导致你使用共享库的方式来部署的原因是,你可能想要在一系列的程序中使用同样的Qt 库。实际上,如果下载Qt 的二进制安装程序,那么你获得的Qt 就是一个共享库。
使用共享库的方式来部署的缺点是,你将会需要部署更多的文件。要了解更多,就去看创建共享库。
部署Qt 的库
|
Qt的库 |
|||
|
|
|||
由于Qt 不是一个系统库,所以它必须随你的程序一起重新发布;最少要重新发布那些被你的程序使用的运行时库。然而,使用静态链接时,Qt 运行时库就被编译到可执行程序中了。
通常,你应当将你用到的Qt 的所有插件都部署,排除那些你确定了对于程序和用户无用的插件。
例如,你可能需要部署那些用来实现JPEG 支持和SQL 驱动的插件,但是你也应当部署那些用户可能需要的插件,包含那些提供易用性的插件。要了解更多关于插件的信息,就去看如何创建 Qt 插件文档。
当你使用共享库的方式来部署一个程序的时候,你必须确保Qt 库会使用正确的路径来查找Qt 插件、文档、翻译等等东西。要做到这一点,你可以使用qt.conf文件。要了解更多信息,就去看使用qt.conf文档。
取决于配置情况,可能也需要重新发布与编译器相关的库。要了解更多信息,就去看与平台相关的程序依赖小节:X11、Windows、Mac。
许可证
Qt 的某些库是基于第三方库的,而它们并不像 Qt 是采用双许可证的。所以,当你部署一些使用这些库的程序时,要小心,尤其是当你将它们静态链接到程序中去时。
下面的表格包含一个对于你应当知道的事情的不完全汇总。
|
Qt库 |
依赖 |
许可证方式 |
|
CLucene |
与Qt 一起发布的clucene 版本是采用GNU LGPL 2.1 版或者更新版本的。这对于闭源程序的开发者来说,包含者某些暗示。请查看QtHelp模块文档以了解更多信息。 |
|
|
OpenSSL |
在某些配置情况下,QtNetwork会在运行时使用OpenSSL。对 OpenSSL 的部署同时受到许可证和出口限制的制约。可以在安全套接字层(SSL)类文档中找到更多信息。 |
|
|
WebKit |
WebKit采用GNU LGPL 2 版本或者更新版本。这对于闭源程序的开发者来说,包含者某些暗示。请查看QtWebKit模块文档以了解更多信息。 |
|
|
Phonon |
Phonon在不同的平台上依赖原生的多媒体引擎。Phonon本身采用GNU LGPL 2 版本。请查看Phonon模块文档以了解更多关于许可证的信息,查看Phonon概述以了解它在不同平台上使用的后端的细节。 |
与平台相关的注意事项
部署Qt 程序的过程在各种各样的平台上都不同:
Qt4.7.0文档翻译:qmake常规项目,qmake Common Projects
Qt4.7.0文档翻译:qmake常规项目,qmake Common Projects
这一章讲述如何为三种基于Qt 的常规项目来设置qmake项目文件。虽然所有类型的项目都会很多变量,但是它们中的每一种都有自己独特的变量,以实现自定义的输出文件。
在这里不讲述与具体项目相关的变量;我们建议读者阅读部署Qt程序文档中的内容以了解特定信息,例如为Mac OS X构建通用二进制文件以及处理 Visual Studio列表文件。
构建一个程序
app 模板
app模板告诉qmake要生成一个最终能构建一个可执行程序的Makefile。在使用这个模板时,还可以通过将以下选项之一添加到CONFIG变量的定义中来指定生成的程序的类型:
|
选项 |
描述 |
|
windows |
这个程序是一个Windows 的图形界面程序。 |
|
console |
仅适合app模板:这个程序是一个Windows 终端程序。 |
当使用这个模板时,会识别以下qmake系统变量。你应当在你的.pro文件中使用这些东西来指定你的程序的一些信息。
-
•.HEADERS – 这个程序的全部头文件的列表。
-
•.SOURCES – 这个程序的全部源代码文件的列表。
-
•.FORMS – 这个程序的全部界面文件(使用Qt Designer创建)的列表。
-
•.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
SOURCES += main.cpp
DEFINES += QT_DLL
CONFIG += qt warn_on release
对于那些只有一个值的条目,例如模板或者目标目录变量,我们使用”=”;但是对于多值的条目,我们使用”+=”来将新的值追加到已有的值上。使用”=”会将那个条目的值替换掉,例如,如果我们写上DEFINES=QT_DLL,那么其它的全部定义都会被删除。
构建一个库
lib模板
lib模板告诉qmake要生成一个能够最终构建一个库的Makefile。当使用这个模板时,除了上面在app模板中讲到的系统变量之外,还支持VERSION变量。你应当在你的.pro文件中使用这些东西来指定与这个库相关的信息。
当使用lib模板时,可将以下选项添加到CONFIG变量中,以决定要构建的库的类型:
|
选项 |
描述 |
|
dll |
这个库是一个共享库(dll/so)。 |
|
staticlib |
这个库是一个静态库。 |
|
plugin |
这个库是一个插件;这也启用了dll 选项。 |
还可以使用以下选项来为库提供附加信息。
-
•.VERSION – 目标库的版本号,例如,2.3.1。
目标文件名字依赖于具体的平台。例如,在X11和Mac OS X上,库名字前面会加上lib;在Windows上,不会加上前缀名字。
构建一个插件
插件是使用lib模板构建的,这在前一节已经说过了。这将告诉qmake为项目生成一个能为每个平台生成适宜的形式的插件的Makefile,这些插件通常是一个库。像普通的库一样,使用VERSION变量来指定与插件相关的信息。
-
•.VERSION – 目标库的版本号,例如,2.3.1。
构建一个Qt Designer 插件
Qt Designer插件是使用一组特殊的配置来构建的,这些配置依赖于Qt 在你的系统上的配置方式。为了方便,可以通过在项目的CONFIG变量中加上designer来启用这些配置。例如:
CONFIG += designer plugin
看Qt Designer示例,就能看到更多基于插件的项目的例子。
以Debug 和Release 模式构建及安装
有些时候,有必要同时以debug 和release 模式构建一个项目。尽管CONFIG变量可以同时储存debug和release选项,但是debug选项会覆盖掉release选项。
同时以两种模式构建
要想同时以两种模式构建项目,你必须在你的项目的CONFIG定义中添加上debug_and_release选项:
CONFIG += debug_and_release
CONFIG(debug, debug|release) {
TARGET = debug_binary
} else {
TARGET = release_binary
}
上面的代码片断中的代码块修改了在各个模式下的构建目标,以确保最终目标有不同的名字。提供不同的目标名字,能够确保它们不会互相覆盖。
当qmake处理项目文件时,它将生成一个允许项目同时在两个模式下构建的Makefile规则。用下面的方式调用这个规则:
make all
可以将build_all选项添加到项目文件中的CONFIG变量中,以确保项目在默认情况下是同时在两种模式下构建的:
CONFIG += build_all
这样就可以使用默认规则来处理Makefile 了:
make
同时以两种模式安装
build_all选项还确保了当安装规则被执行时,两个版本的目标都会被安装:
make install
可以根据目标平台来自定义构建目标的名字。例如,一个库在Windows 平台和在Unix 平台上可能会使用不同的习惯来命名:
CONFIG(debug, debug|release) {
mac: TARGET = $$join(TARGET,,,_debug)
win32: TARGET = $$join(TARGET,,d)
}
上面的代码片段的默认行为就是在以debug 模式构建时修改构建的目标的名字。可以在代码块后面加上一个else语句,它将对release 模式做同样的事;如果保持不变,那么目标名字也保持不变。