三、cmake的静态库和动态库

其实感觉上两节课的学习,应该都可以自己写一个工程的cmake,这个cmake确实比makefile简单多了,至今我都看不懂内核的makefile,太让人头大了。

接下来看看这节课的任务:

1,建立一个静态库和动态库,提供helloFUnc函数供其他程序编程使用,HelloFunc向终端输出Hello World字符串
2,安装头文件与共享库

3.1 准备工作

把上一节的工程目录直接拷贝一份出来,我们在这一份里修改。

添加lib子目录,需要创建如下文件:

在这里插入图片描述

// hello.c
#include "hello.h"
void HelloFUnc()
{
	printf("Hello world\n");
}
// hello.h
#ifdef HELLO_H
#define HELLO_H

#include <stdio.h>
void HelloFunc();

#endif

然后修改两个CMakeLists.txt

# lib/CMakeLists.txt
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
# 顶级CMakeLists.txt
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)

接下来就自行编译了,这里就不介绍了,无非就是创建一个build,然后cmake …;make;

3.2 语法解释

在上面好像新增加了一个指令,这里我们来解释一波:

# 指令ADD_LIBRARY(libname [SHARED | STATIC | MODULE ] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
# 你不需要写全libhello.so,只需要填写hello即可,cmake系统会自动为你生成libhello.X
# 类型有三种:
# SHARED,动态库
# STATIC,静态库
# MODULE,在使用dyld的系统有效,如果不支持dyld,则被当作SHARED对待
# EXCLUDE_FROM_ALL参数的意思是这个库不会被默认构建,除非有其他组件依赖或者手工构建
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

3.3 添加静态库

# 静态库根本没有被构建,仍然只生成了一个动态库
# 因为hello作为一个target是不能重名的,所以静态库构建指令无效
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

# 然后我们修改了一个target名
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

# 可惜这个生成了hello_static.a的库,也不符合我们需求
# 这时候我们就需要用到另外一条指令了
# SET_TARGET_PROPERTIES,基本语法:
# SET_TARGET_PROPERTIES(target1 target2 ...
#                       PROPERTIES prop1 value1
#                       prop2 value2 ...)
# 这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和API版本
# 我们需要添加这样一条命令:
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
# 这样我们就可以同时得到libhello.so/libhello.a两个库了
# 这个其实是把上面编译好的静态库名称改了

# 静态有SET协议就有GET,我们来看看GET
# GET_TARGET_PROPERTIES(VAR target property)
# 具体用法
# GET_TARGET_PROPERTIES(OUTPUT_VALUE hello_static OUTPUT_NAME)
# MESSAGE(STATUS "This is the hello_static OUTPUT_NAME:"${OUTPUT_VALUE})
# 如果没有这个属性定义,则返回NOTFOUND

3.4 动态版本号

按照规则,动态库是应该包含一个版本号的,系统中的动态库,都是包含版本号的,所以我们接下来也要搞一波

# 动态库版本号
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
# VERSION指代动态库版本,SOVERSION指代API版本

接下来可以尝试编译一下:

在这里插入图片描述

是不是看着就很装逼

3.5 安装共享文件库和头文件

上一节我们已经详细讲过了安装的命令,这次就直接写了

# 安装共享库和头文件
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
INSTALL(FILES hello.h DESTINATION include/hello)

是不是很简单。

3.6 如何使用外部共享库和头文件

继续创建一个新的目录,目录结构如下:

在这里插入图片描述

lib和include是我们上面编译好的动态库和头文件,只是把他们拷贝过来,等下有用到,src目录和CMakeLists.txt才是现在添加的。

// main.c
#include <hello.h>
int main()
{
	HelloFunc();
	return 0;
}
// src/CMakeLists.txt
ADD_EXECUTABLE(main main.c)
// 顶级CMakeLists.txt
PROJECT(NEWHELLO)
ADD_SUBDIRECTORY(src)

还是选择外部编译,mkdir build;cmake …;make;

然后发现构建失败,如果需要查看细节,可以使用第一接提到的方法

make VERBOSE=1来构建

在这里插入图片描述

通过错误发现我们缺少了头文件,接下来要把头文件包含进来,但是我们的main.c中已经包含头文件了,还是找不到,说明是路径不对,我们要设置头文件路径,让编译器自己寻找

# 为了让我们工程能够找到hello.h头文件,需要需要引入一个新的指令
# INCLUDE_DIRECTORIES([AFTER | BEFORE] [SYSTEM] dir1 dir2 ...)
# 这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割
# 如果路径中包含空格,可以使用双引号将它括起来
# 默认的行为是追加到当前的头文件搜索路径的后面
# 可以通过两种方式来进行控制搜索路径添加的方式
# 1.CMAKE_INCLUDE_DIRECTORIES_BEFORE,通过SET这个cmake变量为on,可以将添加的头文件搜索路径放在已有路径的前面
# 2.通过AFTER或者BEFORE参数,也可以控制是追加还是置前
# 现在我们把头文件的搜索路径添加进来
INCLUDE_DIRECTORIES(../include)

接下来继续编译,

在这里插入图片描述

头文件错误已经没有了,现在是找不到函数,我们之前只是定义了头文件路劲,还没有添加库文件路径,接下来好好添加一波

# 为target添加共享库
# 我们现在需要完成的任务是将目标我呢间链接到libhello,这里我们需要引入两个新的指令
# LINK_DIRECTORIES和TARGET_LINK_LIBRARIES

# LINK_DIRECTORIES(directory1 directory2 ...)
# 这个指令非常简单,添加非标准的共享库搜索路径,比如,在工程内部同时存在共享库和可执行二进制
# 在编译时就需要指定一下这些共享库的路径。

# TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2 ...)
# 这个指令可以用来为target添加需要链接的共享库
LINK_DIRECTORIES(/home/mmog/study/cmake/4.use_hellolib/lib)
TARGET_LINK_LIBRARIES(main libhello.so) # hello 等价与 libhello.so

进入build目录重新构建

cmake …;make

不知道我这里为什么老是找不到libhello.so,这个错误先放着,看到后面之后会不会就想起怎么解决了,哈哈哈。

然后我们可以通过ldd查看main的链接情况,我这里没有编译成功,就不演示了(很尴尬)。

那如何链接到静态库呢?

# 这个也简单
# 将TARGET_LINK_LIBRRARIES指令修改为
TARGET_LINK_LIBRARIES(main libhello.a)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值