想一想大多数时候我们的项目是不是所有代码都会放在同一个工程中?人少的时候都不是事,但当项目越来越大,开发人员越来越多,会发觉开发、管理能让人窒息,大家都绞在一起,出问题时互相推诿责任,各自有理,这时如果按照功能模块进行分组各自开发,以库的形式提供给其他人使用,就能够最大限度的并行开发,提高工作效率,而且项目的模块也很清晰,责任一目了然,此外使用动态链接库后还能够按模块升级,编译的速度也更快。下面就介绍怎么在工程中创建和使用动态链接库。
Windows 中叫动态链接库(Dynamic Link Library: .dll),Linux 中叫共享库(Shared Library: .so),Mac 下后缀为 .dylib,实际指的是一种类型的库,这里都统称为动态链接库吧。
动态链接库需要理解符号的概念,符号包含函数、变量或者类,分为公有符号和私有符号:
公有符号: 在其他程序或者库使用的符号,需要根据用途进行特殊标记:
Q_DECL_EXPORT
: 编译为动态链接库时符号要标记为Q_DECL_EXPORT
,表明是导出符号Q_DECL_IMPORT
: 在调用动态链接库时符号要标记为Q_DECL_IMPORT
,表明是使用符号
私有符号: 除了公有符号外的其他符号,在此库外不应该能够访问,不需要进行标记
建议: 不要在头文件中声明私有符号。
符号上的标记 Q_DECL_EXPORT
和 Q_DECL_IMPORT
不能同时存在,为了在导出和导入时使用同一个头文件, 头文件中包含下面的宏,编译时根据条件使用不同的宏就可以了:
1 |
|
为了达到了在导出和导入时使用同一个头文件的目的:
说了这么多,还是不知道 Qt 中怎么创建和使用动态链接库,下面就以使用子工程的方式介绍创建和使用动态链接库,工程结构如下:
1 | SharedLibraryTest |
SharedLibraryTest 是 Subdirs Project,包含动态链接库的工程(MyLibrary)和使用动态链接库的工程(MyProject)。
创建工程
Qt Creator 中创建工程的步骤如下:
- 创建工程 SharedLibraryTest:
File > New File or Project... > Other Project > Subdirs Project
- 点击
Choose...
- 输入工程名
SharedLibraryTest
然后创建
- 创建工程 MyLibrary:
工程 SharedLibraryTest 上右键 > New Subproject... > Library > C++ Library
- 点击
Choose...
- 选择 Type 为
Shared Library
- 输入工程名
MyLibrary
然后创建
- 创建工程 MyProject:
工程 SharedLibraryTest 上右键 > New Subproject... > Application > Qt Console Application
- 点击
Choose...
- 输入工程名
MyProject
然后创建
修改 MyLibrary
为了清晰起见,我们先把 MyLibrary 下的 .h 和 .cpp 文件都删除掉,创建 C++ Class Calculator 得到 Calculator.h 和 Calculator.cpp,然后编辑它们:
1 | // 文件名: Calculator.h |
1 | // 文件名: Calculator.cpp |
提示:
class Calculator
和work()
是公有符号,在头文件里声明,可以在其他程序中使用,而doWork()
是私有符号,不在头文件里声明,对于其他程序是不可访问的。
因为这个工程是生成动态链接库的,所以需要在工程的 pro 文件中增加 DEFINES += MYLIBRARY_LIBRARY
这一句,这样编译时 MYLIBRARY_SHARED_SYMBOL
为 Q_DECL_EXPORT
,工程的 pro 文件如下:
1 | #------------------------------------------------- |
下面的部分不是必须的,只是我常用来组织编译输出的目录:
1 | CONFIG(debug, debug|release) { |
修改 MyProject
1 | // 文件名: main.cpp |
工程的 pro 文件如下,没有 DEFINES += MYLIBRARY_LIBRARY
这一句哦,因为这个工程是使用动态链接库的,MYLIBRARY_SHARED_SYMBOL
应该为 Q_DECL_IMPORT
:
1 | QT -= gui |
INCLUDEPATH += $$PWD/../MyLibrary
添加 MyLibrary
的路径到包含目录中,使用的时候就可以 include <Calculator.h>
这样包含头文件了, LIBS += -L$$OUT_PWD/../bin - lMyLibrary
则是引入工程 MyLibrary 生成的动态链接库。
很多人奇怪,-L 和 -l 到底是啥?
-L
指定动态链接库所在文件夹-l
指定动态链接库的名字,不需要指定库的前缀和后缀,Qt 会为自动识别,因为不同的系统动态链接库的前缀和后缀都不同,例如 Mac 中前缀为 lib,后缀为 .dylib,而 Windows 中前缀为空,后缀为 .dll- 如果不使用 -L 和 -l,直接使用
LIBS += 动态链接库的绝对路径或相对路径
也是可以的,例如LIBS += C:/curl/bin/curl.dll
- 还能使用通配符一次导入多个库,如
LIBS += C:/curl/bin/*.dll
,当有 20 个 dll 要导入时,通配符的方式就很省事了
运行程序
编译、运行工程,控制台输出:
work() -> doWork()
5
可以看到编译输出目录生成了动态链接库,并且在工程中也成功使用了,以后复杂的项目就可以按模块进行开发了。当然也可以不必使用 Subdirs Project 的方式,而是每个模块一个工程,pro 文件进行简单的修改即可。
参考资料
- Qt 的帮助文件中搜索:
Creating Shared Libraries
,查看怎么创建动态链接库 - Qt 的帮助文件中搜索:
Third Party Libraries
,查看怎么使用第三方的动态链接库