GCC以及Makefile
GCC
交叉编译工具链 在x86框架编译ARM框架的代码
下载ARM公司提供的通用工具链
gcc x86 不能在arm框架运行
sudo apt-get install build-essetial
:安装gcc
gcc -V :查看gcc版本
gcc命令
gcc [参数] [文件名]
-c: 只编译不链接为可执行文件,将输入的.c编译为.o的目标文件
-o: 编译后 输出指定的文件名,默认是a.out
-g: 添加调试信息,使用GDB调试工具的话就要加上
-O: 对程序进行优化编译,生成的可执行文件执行效率就会变高
-O2: 比-O优化幅度更大,可执行文件效率更高,但是编译过程会很慢
gcc编译流程:
预处理:展开所有的头文件 替换程序中的宏,解析条件编译添加到文件中。
编译:经过预处理的代码编译成汇编代码。
汇编:将汇编语言文件编译成二进制目标文件。
链接:将汇编出的多个二进制目标文件链接到一起,形成最终的可执行文件。涉及静态库和动态库等
Makefile
编译多文件
Makefile文件中编写代码
用make
命令编译工程
Makefile语法
Makefile规则
//Makefile中由一系列的规则组成,规则格式如下:
目标 :依赖文件集合
命令1
命令2
......
main: main.o input.o bsp.o
gcc -o main main.o input.o bsp.o
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
bsp.o: bsp.c
gcc -c bsp.c
clean :
rm *.o
rm main
生成目标main先更新他的所有依赖,依赖文件中有任意一个有更新,目标也必须更新
命令列表中每条命令必须以TAB键开始,不能使用空格
Makefile 变量
Makefile变量都是字符串 类似于c语言的宏
Makefile注释 是#
$(变量)
:变量的引用方法
#= 赋值符 可以将变量的真实值推到后面去定义,变量的真实值取决与它所引用的变量最后一次的有效值
name=zzk
ader=$(name)
name=ds
print:
@echo ader:$(ader)
#make print 的结果是ds
#:= 不使用后面定义的变量 只是用前面定义好的变量
name=zzk
ader:=$(name)
name=ds
print:
@echo ader:$(ader)
#make prin 的结果是zzk
#?= 如果变量前面没有被赋值 那就赋值 ,如果前面被赋值 使用前面的值
name?=zzk
#+= 在已定义好的变量添加字符串
name=main.o bsp.o
name+=input.o
#现在name变量为 main.o bsp.o input.o
Makefile模式规则
#模式规制:通过一条规则来将所有的.c文件编译成对应的.o文件
#使用模式规则时 必须要包含%,%标志长度任意的非空字符串
%.o :% .c
命令
Make file自动化变量
自动化变量会把模式中所定义的一系列文件自动的挨个取出,直至所有的符合模式的文件都取完
&@
:规则中的目标集合,在模式规则中,如果有多个目标的话。&@表示匹配模式中定义的目标集合。
&%
:当目标是函数库的时候表示规则中目标成员名。目标不是函数库 其值为空。 常用
$<
:如果依赖文件以模式(%)定义的,那么&<就是符合模式的一系列文件集合。 常用
$?
:所有比目标新的依赖目标集合,以空格分开。 常用
$^
:所有依赖文件的集合有空格分开,依赖文化中有多个重复的文件时 ,会去除重复的依赖文件,值保留一份
$+
:和$^类似,但不会去除重复的依赖文件
$*
:表示目标模式中%之前的部分,如果目标ad/b.tes.c ,目标模式为b.%.c,那么$*为ad/b.tes
objects =main.o input.o bsp.o
main:$(objects)
gcc -o main $(objects)
%.o : %.c
gcc -c $<
clean:
rm *.o
rm main
#----------------------------------------上面更精简
main: main.o input.o bsp.o
gcc -o main main.o input.o bsp.o
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
bsp.o: bsp.c
gcc -c bsp.c
clean :
rm *.o
rm main
Makefile伪目标
为目标不会生成可执行文件,
clean :
rm *.o
rm main
#可以make clean 进行rm *o操作的前提是没有clean文件,如果有clean文件时,因为没有依赖文件 目标文件clean 不需要更新 所有不会执行rm *o的操作
#此时就可以使用伪目标,不管工作文件中有没有目标文件都可以进行rm命令
#为目标声明
.PHONY:clean
clean :
rm *.o
rm main
#不管工作文件中有没有目标文件都可以使用make clean进行rm命令
Makefile条件判断
条件判断语法执行不同的分支
#两种写法
<条件关键字>
<条件为真时执行的语句>
endif
---------------------
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
条件关键字:ifeq ,ifneq ,ifdef ,ifndef
其中ifeq和ifneq判断两个参数是都相等,是否不相等
#ifeq:判断参数1是否等于参数2
#ifndef:判断参数1是否不等于参数2
ifeq(<参数1>,<参数2>)
ifeq '<参数>','<参数2>'
ifeq "<参数1>","<参数2>"
ifeq '<参数1>',"<参数2>"
ifeq "<参数1>",'<参数2>'
----------------------------------------
#ifdef:如果变量名值非空,则表达式为真
#ifndef:如果变量名值为空,则表达式为真
ifdef <变量名>
ifndef <变量名>
Makefile 函数使用
makefile不支持自定义函数 ,只能调用标志库
格式:$(函数名 参数集合)
或 ${函数名 参数集合}
subst函数:$(subst <from>,<to>,<text>)
替换字符串。将text字符串中的from字符替换成to字符
patsubst函数:$(patsubst <pattern>,<replacement>,<text>)
如果text字符串符合模式 ,那么text中符合的都会替换成
dir函数 : $(dir <name ...>)
获取目录 从参数提取目录部分
notdir函数: $(notdir <name ...>)
获取非目录部分 从参数提取非目录部分
foreach函数: $(foreach <var>,<list>,<text>)
循环函数 将list中参数逐一提出放到var变量中,在执行text表达式。每执行一次循环都会返回一个字符串,foreach循环会将返回的字符串汇总,不同字符串通过空格分隔
wildcard函数: $(wildcard <pat>)
获取参数目录下的所有指定文件
suffix函数: $(suffix <pat>)
获取文件后缀 若文件无后缀 返回空字符
info函数 : $(info <text>)
用于输出调试信息 不会中断make执行
warning函数 : $(warning <text>)
用于输出报警信息 不会中断make执行
error函数: $(error <text>)
用于输出错误信息 make会停止执行
#subst
$(subst ds,DS,my name is ds) #将ds换成DS
#patsubst
$(patsubst %.c,%.o,a.c b.c c.c) #其中字符串a.c b.c c.c 替换成a.o b.o c.o
#dir
$(dir </src/a.c>) #提取参数中目录部分 /src
#notdir
$(notdir </src/a.c>) #提取参数中非目录部分 a.c
#foreach
name:= a b c d
fa:=$(foreach n,${name},$(n).o) #fa变量值为 a.o b.o c.o d.o
#wildcard
$(wildcard *.c test/*.o) #获取当前目录下的所有.c和test目录下所有.o文件
#suffix
$(suffix test/a.c) #返回.c
#info
$(info debug info) #输出debug info