linux下静态库 动态库和 gcc gdb Makefile 使用介绍

一、静态库和动态库

定义

根据链接时期的不同,库有静态库和动态库之分。

静态库是在链接阶段被链接的,所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。

有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。
TODO:链接动态库时链接阶段到底做了什么

两者的优缺点

链接静态库其实从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。

首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。

而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。

正因为动态库在程序运行时被链接,故程序的运行速度和链接静态库的版本相比必然会慢。目前链接程序在链接时一般是优先链接动态库的,除非用-static参数指定链接静态库。

二、GCC 介绍

gcc 作为编译工具,主要在 Linux 操作系统中使用,可以编译 C、C++、Object-C、JAVA 等语言。
编译的流程:
1)预处理 Pre-Processing
2)编译 Compiling
3)汇编 Assembling
4)链接 Linking

GCC编译选项

编译过程中可以带编译选项,选择编译过程:
1) -c :指编译,不链接,生成目标文件“.o”。
2) -S :只编译,不汇编,生成汇编代码“.S”。
3) -E :只进行预编译/预处理,不做其他处理。
4) -o file:把输出文件输出到file里。
5) -g :在可执行程序中包含标准调试信息。
6) -v :打印出编译器内部编译各过程的命令行信息和编译器的版本。7) -I dir :在头文件的搜索路径列表中添加dir目录
8) -L dir :在库文件的搜索路径列表中添加dir目录
9) -static :连接静态库(静态库也可以用动态库链接方式链接)
10) -llibrary :连接名为library的库文件(显示指定需要链接的动态库文件)

生成静态库

gcc -c div.c //生成div.o文件
ar -cr libdiv_sub.a div.o sub.o //生成libdiv_sub.a文件
使用静态库生成可执行文件:
gcc main.c -o main_1.exe -L. -ldiv_sub -I ../add/ -I ../sub/ -I ../mul -I ../div/

-L 表示要使用的静态库的目录,这和前面所讲的 -I (大写 i,指明头文件的目录)差不多,就是用来告诉编译器去哪里找静态库。
因为可能-L所指明的目录下有很多静态库,所以除了要告诉去哪里找之外,还要告诉编译器找哪一个静态库,此时就要用到 -l (小写L )了,它用来说明链接的时候要用到哪个静态库。

注意:
1. 注意是使用 -ldiv_sub,而不是 -llibdiv_sub ,这是因为编译器会自动在库中添加 lib 前缀和 .a 后缀。
2. 要把 -l 放到命令的尽可能后的位置,必须放到源文件的后面。 

生成动态库

gcc -shared -fPIC -o libadd_mul.so add.o mul.o
使用动态库生成可执行文件:
gcc main.c -o main_2.exe ./libadd_mul.so -I ../add/ -I ../sub/ -I ../mul -I ../div/
使用静态库和动态库一起生成可执行文件:
gcc main.c -o main.exe -L. ./libadd_mul.so -ldiv_sub -I ../add/ -I ../sub/ -I ../mul -I ../div/
或者把动态库放到/usr/lib下:
gcc main.c -o main.exe -L. -ladd_mul -ldiv_sub -I ../add/ -I ../sub/ -I ../mul -I ../div/

三、gdb调式

生成调式信息:
gcc  -g
例如:gcc -g main_add.c -o main_add.exe ./libadd.so -I ../add
使用gdb命令开始调试:
gdb ./main_add.exe

四、Makefile 语法介绍

?=  、+= 、:= 的含义

FOO ?= bar
其含义是,如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif

使用“+=”操作符给变量追加值,如:
objects = main.o foo.o bar.o utils.o
objects += another.o
于是,$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o被追加进去了)
使用“+=”操作符可以模拟为下面的这种例子:
objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o
所不同的是用“+=”更为简洁。
如果变量之前没有定义过,那么“+=”会自动变成“=”,如果前面有变量定义,那么“+=”会继承于前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符,如:
variable := value
variable += more
等价于:
variable := value
variable := $(variable) more

wildcard、patsubs、nodir的含义

“wildcard”,其用法是:$(wildcard PATTERN...) 。在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。需要注意的是:这种情况下规则中通配符的展开和其他情况下匹配通配符的区别。
一般用法:我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表。
复杂一些用法:可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。因此,在一个目录下,可以使用如下内容的Makefile来将工作目录下的所有.c文件进行编译,并最后连接成为一个可执行文件:
#举例
objects := $(patsubst %.c,%.o,$(wildcard *.c))
foo : $(objects)
cc -o foo $(objects)
这里我们使用了make的隐含规则来编译.c的源文件

变量替换引用

对于一个已经定义的变量,可以使用“替换引用”将其值中的后缀字符(串)使用指定的字符(字符串)替换。格式为“$(VAR:A=B)”(或者“${VAR:A=B}”),
意思是,替换变量“VAR”中所有“A”字符结尾的字为“B”结尾的字。“结尾”的含义是空格之前(变量值多个字之间使用空格分开)。而对于变量其它部分的“A”字符不进行替换。

例如:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
在这个定义中,变量“bar”的值就为“a.c b.c c.c”。使用变量的替换引用将变量“foo”以空格分开的值中的所有的字的尾字符“o”替换为“c”,其他部分不变。
如果在变量“foo”中如果存在“o.o”时,那么变量“bar”的值为“a.c b.c c.c o.c”而不是“a.c b.c c.c c.c”。

实战演练

本地写了一个小demo,生成四个目标文件,打包成静态库和动态库,给main.c调用。
文件目录如下:

执行过程:

生成文件:

执行main.exe:

main.c 代码:

Makefile脚本代码:

static_obj += $(OBJECT_PATH)/sub.o $(OBJECT_PATH)/div.o
dynamic_obj += $(OBJECT_PATH)/add.o $(OBJECT_PATH)/mul.o

#获取makefile的绝对路径
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
pro_path:=$(shell dirname $(mkfile_path))
$(warning $(mkfile_path))
$(warning $(pro_path))

HFLAGS += -I add/ -I sub/ -I mul/ -I div/
BINARY_PATH ?= out/bin
LIB_PATH    ?= out/lib
OBJECT_PATH ?= out/objs

TARGET1      ?= $(BINARY_PATH)/main_1.exe
TARGET2      ?= $(BINARY_PATH)/main_2.exe
TARGET      ?= $(BINARY_PATH)/main.exe

#创建目录
$(BINARY_PATH) $(OBJECT_PATH) $(LIB_PATH):
    mkdir -p $@

#生成目标文件
$(OBJECT_PATH)/add.o : add/add.c
    cc -c add/add.c -o $(OBJECT_PATH)/add.o
$(OBJECT_PATH)/sub.o : sub/sub.c
    cc -c sub/sub.c -o $(OBJECT_PATH)/sub.o
$(OBJECT_PATH)/mul.o : mul/mul.c 
    cc -c mul/mul.c -o $(OBJECT_PATH)/mul.o
$(OBJECT_PATH)/div.o : div/div.c
    cc -c div/div.c -o $(OBJECT_PATH)/div.o

#生成动态库
$(LIB_PATH)/libadd_mul.so :  $(dynamic_obj)
    cc -shared -fPIC -o $(LIB_PATH)/libadd_mul.so  $(OBJECT_PATH)/add.o $(OBJECT_PATH)/mul.o

#生成静态库
$(LIB_PATH)/libdiv_sub.a : $(OBJECT_PATH)/div.o $(OBJECT_PATH)/sub.o
    ar -cr -o $(LIB_PATH)/libdiv_sub.a  $(OBJECT_PATH)/div.o $(OBJECT_PATH)/sub.o

#使用静态库生成可执行文件:
$(TARGET1) : main.c $(LIB_PATH)/libdiv_sub.a
    cc main.c -o $(BINARY_PATH)/main_1.exe -L out/lib/ -ldiv_sub $(HFLAGS)

#使用动态库生成可执行文件:
$(TARGET2) : main.c $(LIB_PATH)/libadd_mul.so
    cc main.c -o $(TARGET2) $(pro_path)/out/lib/libadd_mul.so $(HFLAGS)

#使用静态库和动态库一起生成可执行文件:
$(TARGET) : main.c $(LIB_PATH)/libdiv_sub.a $(LIB_PATH)/libadd_mul.so
    cc main.c -o $(TARGET)  $(pro_path)/out/lib/libadd_mul.so  -L out/lib/ -ldiv_sub $(HFLAGS)

.PHONY: all clean prepare build hello post-build
all: hello prepare build post-build
clean: ;rm -rf out
hello: ;@echo ==== start, $(shell date) ====
prepare: $(BINARY_PATH) $(OBJECT_PATH) $(LIB_PATH)
build: $(TARGET)
post-build: ;@echo ==== done, $(shell date) ====

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容