本节的任务是:
- 建立一个静态库和动态库,提供HelloFunc函数供其他程序使用,HelloFunc函数向终端输出Hello World字符串。
- 安装头文件和共享库
1. 准备工作
在 /backup/cmake
目录建立t3
目录,用于存放本节涉及到的工程。
然后建立共享库lib
:
cd /backup/cmake/t3
mkdir lib
在t3
目录下建立CMakeLists.txt
。内容如下:
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)
在lib目录
下建立两个源文件hello.cpp
和 hello.h
:
hello.cpp内容如下:
#include “hello.h”
void HelloFunc(){
cout << "Hello World" << endl;
}
hello.h内容如下:
#ifndef HELLO_H
#define HELLO_H
#include <iostream>
using namespace std;
void HelloFunc();
#endif
在lib 目录
下建立CMakeLists.txt
,内容如下:
SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
2. 编译共享库
我们仍然使用外部编译:
mkdir build
cd build
cmake ..
make
编译完成后,我们就可以在build/lib目录
中得到一个libhello.so
,这就是我们期望的共享库
。
我们可以通过在主工程文件CMakeLists.txt
中修改ADD_SUBDIRECTORY(lib)
指令来指定一个编译输出位置或者在lib/CMakeLists.txt 中添加SET(LIBRARY_OUTPUT_PATH < 路径>)
来指定一个新的位置。
3. 指令解释
语法:
ADD_LIBRARY(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
libname是我们指定的库名称,这里不需要写全libhello.so
,只需要写hello
即可,cmake系统会自动为你生成libhello.X,X是根据类型指定的。
类型有三种:共享库/动态库SHARED
,静态库STATIC
,模块库MODULE
。
其中静态库的一个缺点,当同时运行许多应用程序并且它们都使用来自同一个静态库的函数时,就会在内存中有同一函数的多份拷贝
,在程序文件自身中也有多份同样的拷贝。这将消耗大量宝贵的内存和磁盘空间。可以用共享库来实现函数的动态链接。
程序使用共享库时,它的链接方式
是这样的:它本身不再包含函数代码,而是运行时
进行动态加载
,所以共享库也被称为动态加载库
,简称动态库
。
静态库的后缀是.a
,动态库的后缀是.so
。
4. 添加静态库
我们在支持动态库的基础上再为工程添加一个静态库,按照一般的习惯,静态库名字跟动态库名字应该是一致的,只不过后缀是.a
而已。
我们修改lib 目录
下的CMakeLists.txt
,加入下面的指令:
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})
但是这样并不会创建静态库,因为在cmake中,target是不能重名
的,所以上述指令无效。
如果我们把静态库的名字改一下就可以构建一个名为libhello_static.a
的静态库:
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
但是,我们真正想要的是生成两个同名的静态库和共享库,此时,我们需要用到另一条指令:
语法:
SET_TARGET_PROPERTIES(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...)
这条指令可以用来设置输出的名称
,对于动态库
,还可以用来指定动态库版本和API 版本
。
具体的,我们在本例中,向lib/CMakeLists.txt
中添加:
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
然后我们来构建工程,我们发现,在build/lib目录
中确实存在libhello.a
,但是libhello.so
却消失了。这是因为cmake在构建一个新的target时,会尝试清理掉其他同名的库
。
注意
,这个问题跟上面target同名已经不是同一个问题了,现在target已经不同名了,其中动态库的target名称是hello,静态库的target名称是hello_static。这里的问题cmake在构建库时清理同名库的问题。
为了回避这个问题,我们向lib/CMakeLists.txt中添加:
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
上述指令中,1代表不清除同名库
。这样,我们重新构建,会发现build/lib 目录中同时生成了libhello.so 和libhello.a。
这样我们的目的就达到了。
5. 动态库版本号
一般动态库都会有一个版本号的关联。我们可以使用SET_TARGET_PROPERTIES
指令来指定动态库的版本号,我们在lib/CMakeLists.txt
中加入下面的指令:
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
重新构建后,在build/lib 目录会生成:
libhello.so.1.2
libhello.so->libhello.so.1
libhello.so.1->libhello.so.1.2
6. 安装共享库和头文件
我们需要将库文件和头文件安装到某一个目录中,才能被其他开发者使用,在本例中我们的任务是:
- 将hello 的共享库和静态库安装到/lib 目录
- 将hello.h 安装到/include/hello 目录
我们向lib/CMakeLists.txt
中添加如下指令:
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include/hello)
我们重新构建工程并安装:
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
make
make install
我们就可以将头文件和库文件安装到系统目录/usr/lib
和 /usr/include/hello
中了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)