函数库:本质:一组函数。具有相近的功能或操作同一数据结构。strcpy/strcmp/strcat/strlen/strstr/strchr/strtok... <string.h>
bubble_sort / select_sort / quick_sort / insert_sort <mysort.h>
作用:
- 代码复用:软件开发的大部分时间用在应用程序设计上。而不是花在处理底层的细节上。(面向对象程序设计也体现了代码复用)
硬件——系统调用——标准库——用户库——应用程序 (层层复用)
- 程序积累
发布形式:
- 源码形式发布
缺点:1. 保密性差 2. 编译程序耗时、平台、编译器版本
优点:方便使用者学习和研究
- 二进制形式
优缺点 与上相反 标准C库libc.so.6
一、静态库:
机制:复制静态库作为程序代码段的一部分。
优点:将函数库中的函数本地化。寻址方便,速度快。(库函数调用效率 == 自定义函数使用效率)
缺点:消耗系统资源较大。每个进程使用静态库都要复制一份。无端浪费内存
使用场景:多应用于核心程序,保证时效性,可以忽视空间。
制作:
1. gcc add.c sub.c mul.c -c ——>得到*.o
2. ar rs libmymath.a add.o sub.o mul.o ——>得到静态库
(libmymath.a命名规范必须是lib开头 .a结尾)
ar工具不包含在gcc中
r更新、c创建、s建立索引
file libmymath.a ——>查看库信息
3. gcc main.c -o app -L ./ -l mymath -I ./ ——>使用静态库(./ 表示当前文件夹 )
使用:L:指定静态库所在目录位置;l:指定静态库名字 I:指定头文件所在目录位置
二、动态库(共享库):
机制:共享代码(不共享数据)
优点:节省内存(共享)、易于更新(动态链接) ./a.out 《--- libc.so
缺点:相较于静态库函数调用速度略慢(延迟绑定机制)
使用场景:
- 对程序执行速度要求不是很强烈,而相对于系统资源有一定要求的场景
- 对于更新比较频繁的程序
1)停止运行程序
2)使用新库覆盖旧库(保证新旧库名称一致,接口一致) “接口”
3)重新启动程序。
重点强调:
- 动态库是否加载到内存,取决于程序是否运行
- 动态库加载到内存的位置不固定----动态链接器
制作:
1. gcc -fPIC add.c mul.c sub.c -c (-fPIC:生成“与位置无关”的目标文件*.o)
2. gcc -shared -o libmymath.so add.o mul.o sub.o
3. gcc main.c -L库路径 -l库名 -I头文件名 -o app
4. ./app --> 出错
原因:动态连接器 ld-linux.so.2 搜寻动态库的路径未指定,
执行ldd app发现动态链接器找不到 libmymath 库。
指定方法:
1. 环境变量法:export LD_LIBRARY_PATH=./ 将当前目录加入环境变量,但是终端退出了就无效了。
2. 配置文件法:将上条写入家目录下.bashrc文件中 (永久生效,设置到~/.bashrc)
3. 拷贝法:直接将libmymath.so文件拷贝到/usr/lib/目录下。(受libc库的启发)
4. 缓存文件法:将libmymath.so所在绝对路径加入到/etc/ld.so.conf文件,
使用sudo ldconfig -v 动态更新/etc/ld.so.cache文件(2进制文件)
*5. 指定动态库的soname
gcc -shared -Wl,-soname,libmymath.so.1 -o libmymath.so.1.10 add.o mul.o sub.o
*6. 创建动态库的LinkerName
ln -s libmymath.so.1.10 libmymath.so
动-静态库共存时:
编译器默认使用.so的动态库,找不到才使用静态库。
-static可以直接指定使用静态库。
objdump -dS app > out
注意比较加了static和没有加static的可执行文件大小,及内部printf的地址。
gdb:
使用场景:程序编译无误,但是有逻辑错误。
加-g 编译 ---> gdb xxx (gcc gcbtest.c -o app -g)
list l ---> b 行号 (设置断点 b 22 if i = 5 条件断点)
info b 查看断点信息。
disable/enable 断点号——设置断点非使能/使能。
delete 断点号——删除断点
b 行号 if i=5 设置条件断点,只有i=3时断点生效。
run ---- start
p 变量名——查看变量值
display——跟踪变量
undisplay——取消跟踪
ptype 变量名——查看变量类型
bt 查看当前程序函数栈帧使用基本情况
函数的栈帧保存局部变量和临时值,形参,与局部变量等价。
info locals 查看当前栈帧上变量的存储值。
frame 栈帧编号查看变量的值
s——step
n——next
finish 终止当前函数
continue 结束当前断点调试
p *数组名@10 列出数组前10个元素值
p 数组名[n]@m 从下标n开始向后打印m个元素。
三、makefile项目管理
3.1用途
- 项目代码编译管理
- 节省编译项目时间
- 一次编写终身受益
- 操作示例文件:add.c sub.c mul.c dive.c main.c
3.2基本规则
Makefile由一组规则组成,规则如下:
目标:依赖
(tab)命令
如:add.o:add.c
(一个tab缩进)gcc –Wall –g –c add.c –o add.o
目标:要生成的目标文件
依赖(条件):目标文件由哪些文件生成
命令:通过执行该命令由依赖文件生成目标
3.3Makefile工作原理
基本原则:
1.若想生成目标,检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来生成该依赖文件
2.检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任一个被更新,则目标必须更新
- 分析各个目标和依赖之间的关系
- 根据依赖关系自底向上执行命令
- 根据修改时间比目标新,确定更新
- 如果目标不依赖任何条件,则执行对应命令,以示更新
3.5Makefile变量
在Makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使Makefile易于维护,修改内容变得简单
变量定义及使用:
foo = abc
bar = $(foo)
定义了两个变量:foo、bar,其中bar的值是foo变量值的引用。
1、变量定义直接用'='
2、使用变量值用$(变量名)
通常我们在Makefile中会定义一些变量,方便Makefile的修改维护
src = main.c func1.c func2.c
CC = gcc #arm-linux-gcc
CPPFLAGS : C预处理的选项如:-I
CFLAGS:C编译器的选项–Wall –g -c
LDFLAGS :链接器选项–L -l
自动变量:
$@:表示规则中的目标
$<:表示规则中的第一个条件
$^:表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项。
模式规则:
至少在规则的目标定义中要包含'%','%'表示一个或多个,在依赖条件中同样可以使用'%',依赖条件中的'%'的取值,取决于其目标.
模式规则示例:
%.o:%.c
$(CC) –c $(CFLAGS) $(CPPFLAGS) $< -o $@
其中,“$@”表示依次取出目标值,$<表示依次取出依赖条件。
注意:只有写成模式规则的时候,$<才表示了所有依赖条件的依次取值
否则只是取依赖条件中的第一个。
3.5Makefile 函数
src = $(wildcard *.c)
找到当前目录下所有后缀为.c的文件,赋值给src
obj = $(patsubst %.c,%.o, $(src))
把src变量里所有后缀为.c的文件替换成.o
3.6clean
- 用途:清除编译生成的中间.o文件和最终目标文件
- make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令
- 伪目标声明:.PHONY:clean
- clean命令中的特殊符号
– “-”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”
– “@”不显示命令本身,只显示结果。如:“@echo”clean done“” - 其它
– make 默认执行第一个出现的目标,可通过make dest指定要执行的目标
– distclean目标
– install目标
– make -C 指定目录进入指定目录,调用里面的Makefile
– make -n:只打印要执行的命令,不会真正执行命令
– make -p:显示隐含规则数据库中的信息
– make -C:切换到另一个目录中执行该目录下的Makefile
– make -f:-f执行一个makefile文件名称,使用make执行指定的makefile
3.7例子
#src = add.c sub.c mul.c main.c
src = $(wildcard *.c) #wildcard *.c 在当前文件夹找到所有.c后缀的文件
#obj = add.o sub.o mul.o main.o
obj = $(patsubst %.c,%.o,$(src))
CC = gcc
target = app
ALL:$(target)
$(obj):%.o:%.c
$(CC) -c $< -o $@
$(target):$(obj)
$(CC) $^ -o $@
clean:
-rm -rf app $(obj)
.PHONY:clean ALL
3.8例题
1.完成该项目图的makefile
#src = add.c sub.c mul.c main.c
src = $(wildcard ./src/*.c) #wildcard:get all file which name end in .c in this file
obj = $(patsubst ./src/%.c,./obj/%.o,$(src)) #obj = add.o sub.o mul.o main.o
inc_path = ./inc/
CC = gcc
target = app
CFLAGES = -I
ALL:$(target)
$(obj):./obj/%.o:./src/%.c #./obj/add.o ./obj/sub.o ./obj/mul.o : ./src/*.c
$(CC) -c $< -o $@ $(CFLAGES) $(inc_path)
$(target):$(obj)
$(CC) $^ -o $@
clean:
-rm -rf app $(obj)
.PHONY:clean ALL
2.make生成三个不同的app
src = $(wildcard *.c) #a.c b.c c.c gdbtest.c
target = $(patsubst %.c,%,$(src)) #a b c gdbtest
ALL:$(target)
CFLAGES = -Wall
$(target):%:%.c
gcc $< -o $@ $(CFLAGES)
clean:
-rm -rf $(target)
.PHONY:clean ALL