qmake使用实践:包含动态库的Qt4工程
文章来源:http://blog.csdn.net/dbzhang800/article/details/6317006
本文是qmake的一个使用练习,是半年前所学的 分析与学习Qt Solution对qmake的使用 的续篇。
采用一个非常简单的Qt程序作为例子,通过pro文件的合理编写,使得我们的程序在使用动态库的时候,几乎可以忽略掉动态库的存在。它包括3部分:
- 生成动态库
- 使用动态库
- 生成与使用的自动化
测试环境:
- ubuntu 11.04 + Qt 4.7.2
- windows vista + Qt 4.7.0(MSVC2008)
- windows vista + Qt 4.6.3(MinGW)
例子的源码:http://code.google.com/p/h-qt-exercise/downloads/detail?name=QtAppWithDll.zip&can=2&q= (你可以先看代码,再决定是不是继续向下看)
引子
一个非常非常简单的Qt的小程序,是吧?
- widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
class Widget:public QWidget
{
Q_OBJECT
public:
Widget(QWidget * parent=0);
};
#endif // WIDGET_H
- widget.cpp (本文件内容不变)
#include "widget.h" Widget::Widget(QWidget *parent)
:QWidget(parent)
{
}
- main.cpp (本文件内容不变)
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Widget w;
w.show();
app.exec();
}
这个程序是如此的简单,我们都能很轻易地写出需要的pro文件
HEADERS += widget.h
SOURCES += main.cpp widget.cpp
然后qmake,make即可得到结果。
可是,你想过么:如果不想让我们的程序铁板一块,分成几个动态库(共享库)会怎么样呢,pro文件又该如何写?
如何做?(一)源码分开放置
既然要准备用动态库了,库的源码和程序的源码还是分开放置吧?
- 将源文件放到不同的路径下
- src/main.cpp
- libwidget/widget.h
- libwidget/widget.cpp
我们知道qmake不如cmake那么强大,它的每个project只能有一个目标,要么是库,要么是可执行程序。当目标多于一个时,只能用 subdirs 这个TEMPLATE,于是,
- 我们需要3个xxx.pro文件
- project.pro
- src/src.pro
- libwidget/libwidet.pro
可以确定,project.pro 文件没有什么悬念:
- project.pro (本文件内容不变)
TEMPLATE=subdirs
CONFIG += ordered
SUBDIRS += libwidget src
如何做?(二)生成动态库
使用动态库,当务之急是生成动态库。
- 如果我们不在windows下使用,一切都会比较简单,源代码也不需要改动。
在windows下,动态库导出的东西需要使用 __declspec(dllexport)。
我们需要兼顾不同的平台,幸好Qt有解决方案,改造后的widget.h文件如下:
- widget.h (本文件内容后续不再改变)
#ifndef WIDGET_H
#define WIDGET_H #include <QtGui/QWidget> #if defined(LIBWIDGET_BUILD)
# define WIDGET_API Q_DECL_EXPORT
#else
# define WIDGET_API Q_DECL_IMPORT
#endif class WIDGET_API Widget:public QWidget
{
Q_OBJECT
public:
Widget(QWidget * parent=0);
}; #endif // WIDGET_H
然后写写 libwidget.pro 文件:
TEMPLATE = lib
TARGET = widget
DEFINES += LIBWIDGET_BUILD
SOURCES += widget.cpp
HEADERS += widget.h
这样一来,确实可以生成动态库了。可是总觉得不太好:
- 首先,windows下debug和release的动态库是不兼容的,取同一个名字(TARGET=widget)会不会有潜在的问题?
- 其次,生成的库放到那个路径下呢?程序链接和运行时如何找到它?
暂且存疑,我们先看看其他
如何做?(三)使用动态库
看看可执行程序的生成,它要使用我们前面的库,那么:
- 编译预处理时需要找到头文件
- 连接时需要找到库文件(库文件在那个目录下,叫什么名字)
- 运行时能够找到动态库
src/src.pro 文件可以就写成这个样子了:
TEMPLATE=app
INCLUDEPATH += ../libwidget LIBS += -LThePathWePutLib -lwidget SOURCES += main.cpp
先不考虑运行时的情况。头文件和库文件都和前面的libwidget直接相关,怎么构建自动化呢?比如:库文件的名字改动了?库文件的存放目录变了?...
如何做?(四)构建自动化
我们构建动态库的时候,可以控制动态库的名字,可以控制存放目录,那么,我在讲动态库的这部分设置独立出来不就行了:恩,使用一个 libwidget/libwidget.pri 文件。l由于src/src.pro和libwidget/libwidget.pro共用这个文件,还需要一个开关来进行区分(这就是widget-buildlib):
INCLUDEPATH += $$PWD
TEMPLATE += fakelib
LIBWIDGET_NAME = $$qtLibraryTarget(widget)
TEMPLATE -= fakelib
!widget-buildlib{
LIBS += -L$$PROJECT_LIBDIR -l$$LIBWIDGET_NAME
}else{
SOURCES += widget.cpp
HEADERS += widget.h
}
注意:这儿库目录用一个变量PROJECT_LIBDIR表示(你这儿可以直接换成存放库的目录),具体稍后解释。这儿的库的名字使用qtLibraryTarget进行生成(这样可以确保windows下debug模式生成的动态库可以自动加个d),fakelib是用来哄骗qtibraryarget的,不然它只在TEMPLATE为lib是生效。
这样,可执行程序的生成时,它要使用我们前面的库,只需要包括进来libwidget.pri,于是:
- src/src.pro 文件可以就写成这个样子了:
TEMPLATE=app
include(../libwidget/libwidget.pri)
SOURCES += main.cpp
- 相应地,libwidget/libwidget.pro 可以修改如下:
TEMPLATE = lib
CONFIG += widget-buildlib
include(libwidget.pri)
TARGET = $$LIBWIDGET_NAME
CONFIG += debug_and_release build_all
DEFINES += LIBWIDGET_BUILD
如何做?(五)运行自动化
现在似乎一切都比较正常了,可是有一点,我们要将生成的库文件放到什么地方呢?才能使得运行时都能被找到(就像没使用动态库一样,点击IDE中的run或者去目录下双击即可运行)
我们需要:
- 将库文件放到 lib目录下
- 将可执行文件放到 bin目录下
- windows下将 xxx.dll 也放到bin目录下
恩,这两个目录对整个工程比较通用,我们可以考虑建立一个 common.pri 文件:
- common.pri 内容 (本文件内容后续不再改变)
PROJECT_BINDIR = $$PWD/bin
PROJECT_LIBDIR = $$PWD/lib
然后libwidget/libwidget.pri 包含该common.pri 文件
- libwidget/libwidget.pri (本文件内容后续不再改变)
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
TEMPLATE += fakelib
LIBWIDGET_NAME = $$qtLibraryTarget(widget)
TEMPLATE -= fakelib
include(../common.pri)
!widget-buildlib{
LIBS += -L$$PROJECT_LIBDIR -l$$LIBWIDGET_NAME
}else{
SOURCES += widget.cpp
HEADERS += widget.h
}
- 完整版的 libwidget/libwidget.pro 文件 (本文件内容后续不再改变)
TEMPLATE = lib
CONFIG += widget-buildlib
include(libwidget.pri)
TARGET = $$LIBWIDGET_NAME
DESTDIR = $$PROJECT_LIBDIR
win32{
DLLDESTDIR = $$PROJECT_BINDIR
QMAKE_DISTCLEAN += $$PROJECT_BINDIR/$${LIBWIDGET_NAME}.dll
}
CONFIG += debug_and_release build_all
DEFINES += LIBWIDGET_BUILD
注意:这儿我们指定了库文件的目录,并会将dll拷贝到了PROJECT_BINDIR目录
- 完整版的 src/src.pro 文件 (本文件内容后续不再改变)
TEMPLATE=app
include(../libwidget/libwidget.pri)
DESTDIR = $$PROJECT_BINDIR
unix:QMAKE_RPATHDIR+=$$PROJECT_LIBDIR
SOURCES += main.cpp
注意:这儿我们对unix下,指定了rpath,使得程序运行时不许设置可以即可找到动态库
源码
qmake使用实践:包含动态库的Qt4工程的更多相关文章
- 最全Windows版本jemalloc库(5.2.1)及其使用:包含动态库和静态库、x86版本和x64版本、debug版本和release版本
编写服务器程序时,需要频繁的申请和释放内存,长时间运行会产生大量的内存碎片,这就导致即使当前系统中的闲置内存还足够多,但也无法申请到大的连续可用的内存块,因为此时的物理内存已经千疮百孔像个马蜂窝.此外 ...
- C++ 系列:静态库与动态库
转载自http://www.cnblogs.com/skynet/p/3372855.html 这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择 ...
- C++静态库与动态库
C++静态库与动态库 这次分享的宗旨是--让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学,推荐一 ...
- Linux下C++静态库、动态库的制作与使用
参考博文:C++静态库与动态库 >> 静态库 1. 静态库的制作 a) 编辑 name.cpp 和name.h文件 b) $g++ -c name.cpp //注意带参数-c,否则直接编译 ...
- c/c++:动态库 静态库 linux/windows 例子 (转)
作者:吴秦出处:http://www.cnblogs.com/skynet/本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名吴秦(包含链接). C++静 ...
- (转)C++静态库与动态库
转自:http://www.cnblogs.com/skynet/p/3372855.html C++静态库与动态库 这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别, ...
- (转)C++静态库与动态库
本文出自 http://www.cnblogs.com/skynet/p/3372855.html 吴秦 什么是库 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不 ...
- 【转】C++静态库与动态库
C++静态库与动态库 这次分享的宗旨是——让大家学会创建与使用静态库.动态库,知道静态库与动态库的区别,知道使用的时候如何选择.这里不深入介绍静态库.动态库的底层格式,内存布局等,有兴趣的同学,推荐一 ...
- face++静态库转为动态库
前言 苹果商店上架应用,有规定支持iOS8.0以上的iPA可执行文件的大小不能超过60M. face++提供过来的是静态库,会导致苹果上架的ipa的包增加1.5M左右.而刚好我们的APP包Mach-O ...
随机推荐
- HDU5266---pog loves szh III (线段树+LCA)
题意:N个点的有向树, Q次询问, 每次询问区间[L, R]内所有点的LCA. 大致做法:线段树每个点保存它的孩子的LCA值, 对于每一次询问只需要 在线段树查询即可. #include <bi ...
- 探求Floyd算法的动态规划本质(转)
---恢复内容开始--- Floyd–Warshall(简称Floyd算法)是一种著名的解决任意两点间的最短路径(All Paris Shortest Paths,APSP)的算法.从表面上粗看,Fl ...
- New Year Permutation(Floyd+并查集)
Description User ainta has a permutation p1, p2, ..., pn. As the New Year is coming, he wants to mak ...
- zabbix linux被监控端部署
测试使用agentd监听获取数据. 服务端的安装可以查看http://blog.chinaunix.net/space.php?uid=25266990&do=blog&id=3380 ...
- Uber明年在中国将继续补贴,并大举进军100个城市!
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- java实现的23种设计模式 (个人推荐)
http://zz563143188.iteye.com/blog/1847029 mark下,个人用,大家会也可以看看写的不错.
- Engineer Economic
1.选择题 10.下列哪项不属于总成本费用() A.生产成本 B.机会成本 C.管理费用 D.财务费用 第1章 11.下列哪项关于自有资金的表述是错误的(D) A.自有资金包括资本金 ...
- css的存在形式以及优先级
css的存在形式以及优先级 css不仅仅可以在每个head标签中定义,而且也可以写在一个文件中,每个页面即可进行引用,这样可以做到重复利用. css文件的写法如下: common.css .c1{ h ...
- Android两种 旋转Bitmap方法
方法1. 利用Bitmap.createBitmap Bitmap adjustPhotoRotation(Bitmap bm, final int orientationDegree) { ...
- POJ 3254 Corn Fields (状态压缩DP)
题意:在由方格组成的矩形里面种草,相邻方格不能都种草,有障碍的地方不能种草,问有多少种种草方案(不种也算一种方案). 分析:方格边长范围只有12,用状态压缩dp好解决. 预处理:每一行的障碍用一个状态 ...