gcc编译的原理
1、预处理
gcc -E main.c > main.i
作用:
1、展开头文件
2、宏替换
3、去掉注释
4、条件编译
2、编译
gcc -S main.i
作用:
1、将代码转成汇编代码
3、汇编
gcc -c main.s
作用:
将汇编转成机器码 .o文件就是常见的依赖项
4、链接
gcc main.o
作用:编译器将多个.o文件链接到一起,生成一个a.out/.exe可执行文件
Makefile基本语法
Makefile就是将一系列的工作流串到一起自动执行,构成Makefile最基本的要素是目标、依赖、命令。也就是为了实现目标需要那些依赖并执行什么样的命令。
目标:一般是指要编译的目标,也可是一个动作。
依赖:指执行当前目标所要依赖的选项,包括其他目标,某个具体文件或库等,一个目标可以 有多个依赖。
命令:该目标下要执行的具体命令,可以没有、也可以有多条。
实例:
targe:dependences1 dependences2 ...
command1 command2 ...
其中,target表示要生成的目标,dependences表示生成target需要的依赖,而command就是生成target要执行什么命令。格式上,命令所在行行首都有一个<tab>(备注:4个space键不可以:makefile:2 ***missing separator. Stop).
Makefile变量
Makefile也支持变量,使用上和Shell中的变量很相似,比如:Makefile中的变量可以分为三大类:系统变量、系统常量和自定义变量。
系统变量:
$*不包括扩展名的目标文件名称
$@表示目标文件的完整名称
$<表示第一个依赖文件
$?表示比目标文件还要新的依赖文件列表
$^表示所有不重复的依赖文件,以空格分隔
$+这个变量很像"$^",也是所有依赖目标的集合,只是它不去除重复的依赖目标
$% 仅当目标是归档成员,则该变量表示目标的归档成员名单
系统常量(可以使用make -p命令查看)
AR:函数库打包程序,默认命令是ar
AS:汇编语言编译程序,默认命令是as
CC:C语言编译程序,默认命令是cc
CXX:C++语言编译程序,默认命令是g++
CPP:C语言的预处理器,(输出是标准输出设备),默认命令是$(cc) -E
RM:删除文件命令,默认命令是rm -f
Makefile模式匹配
在Makefile中模式匹配使用%来实现,表示匹配任意多个非空字符,相当于shell中的*。
模式匹配有什么用呢?
假如现在有非常多的.c源文件要生成目标.o源文件,我们可以像下面这样写:
%.o:%.c
cc -c $^ -o $@
上面的意思是将所有.c文件都经过编译器编译生成.o文件,其中表示的是所有依赖,在上面的场景中就是当前目录下所有.c文件。而$^表示的是所有依赖,在上面的场景中就是当前目录下所有.c文件。而表示的是所有的依赖,在上面的场景中就是当前目录下所有.c文件。而$@表示目标文件,也就是%.o所代表的所有文件。可以看到模式匹配可以大幅减少Makefile的代码量。
OBJ=$(patsubst %.c, %.o, $(wildcard ./*.c)) #将当前目录下所有.c文件替换成.o文件
main:$(OBJ)
gcc main.o myAdd.o mySub.o -o main
%.o:%.c
gcc -c main.c -o main.o
wildcard:匹配文件。(使用例示:获取指定目录下所有.c文件)
patsubst:模式匹配与替换(使用例示:指定目录下所有.c文件替换成.o文件)
[Makefile 动态库] (wins:.dll文件 类uinx: .so文件)
动态库链接:不会把代码编译到二进制文件中,而是在运行时候才会去加载,所以只需要一个地址。
-fPIC:产生位置无关的代码
-shared:共享
-l(小写L):指定动态库
-I(大写i):指定头文件目录,默认当前目录
-L:手动指定库文件搜索目录,默认只链接共享目录
gcc -shared -fPIC SoTest.c -o libSoTest.so
gcc -ISoTest -L/main.c -o main
提供libSoTest.so和SoTest.h给客户使用
生成动态库
OBJ=$(patsubst %.c, %.o, $(wildcard ./*.c))
TARGET=libMyAdd.so
LIBPATH=/usr/lib/
$(TARGET):$(OBJ)
$(CC) -shared -fPIC $^ -o $@
cp $(TARGET) $(LIBPATH)
使用动态库
OBJ=$(patsubst %.c, %.o, $(wildcard ./*.c))
TARGET=main
LDFLAGS=-L./src_so
LIBS=-lMyAdd
$(TARGET):$(OBJ)
$(CC) $^ $(LIBS) $(LDFLAGS) -o $@
[Makefile]静态库
静态链接库:会把静态库的代码编译到二进制中,当程序编译完成后,该文件可以删除。
缺点:程序体积过大,并且库中的内容如果有更新,则需要重新编译生成程序。
OBJ=$(patsubst %.c, %.o, $(wildcard ./*.c))
TARGET=libMySub.a
$(TARGET):$(OBJ)
$(AR) -r $(TARGET) $^