一、静态库和动态库,Makefile项目管理

函数库:本质:一组函数。具有相近的功能或操作同一数据结构。strcpy/strcmp/strcat/strlen/strstr/strchr/strtok...

bubble_sort / select_sort / quick_sort / insert_sort

作用:

  1. 代码复用:软件开发的大部分时间用在应用程序设计上。而不是花在处理底层的细节上。(面向对象程序设计也体现了代码复用)

硬件——系统调用——标准库——用户库——应用程序 (层层复用)

  1. 程序积累

发布形式:

  • 源码形式发布

缺点: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. 对于更新比较频繁的程序
    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例子
一、静态库和动态库,Makefile项目管理_第1张图片
image.png
#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

一、静态库和动态库,Makefile项目管理_第2张图片
例题1

#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

你可能感兴趣的:(一、静态库和动态库,Makefile项目管理)