gcc过程
预处理 -> 编译 -> 汇编 -> 链接
cc1 main.c -o main.s
as main.s -o main.o
gcc main.o -o main
规则:
目标 : 依赖文件集合
命令
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
main.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm main
变量
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
赋值
= 使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值,
:= 只能使用前面已经定义好的
?= 如果变量 已经被赋值,就不再赋值+= 追加内容
name=zzk
curname = $(name)
print:
# 不输出指令
@echo curname: $(curname)
模式规则
objects = main.o input.o calcu.o
main: $(objects) 3 gcc -o main $(objects) 4
%.o : %.c
#命令
找到所有.c文件并生成.o文件
clean:
rm *.o
rm main
$@ 表示规则的目标文件名
**$^ ** 所有依赖文件的集合,不可重复
** + ∗ ∗ 和 “ +** 和“ +∗∗和“^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件
$? 所有比目标文件更新的依赖文件列表
$% 当目标是函数库的时候表示规则中的目标成员名
$< 规则的第一个依赖的文件名
$* 这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模
式为 a.%.c,那么“$*”就是 test/a.test。
伪目标
.PHONY : clean
条件判断
<条件关键字>ifeq、ifneq、ifdef 和 ifndef,
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
# Define required macros here
SHELL = /bin/sh
OBJS = main.o factorial.o hello.o
CFLAG = -Wall -g
CC = gcc
INCLUDE =
LIBS = -lm
hello:${OBJ}
${CC} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}
clean:
-rm -f *.o core *.core
.cpp.o:
${CC} ${CFLAGS} ${INCLUDES} -c $<
vpath依赖文件查询路径
vapth *.c src
#VPATH = src
函数
patsubst字符替换
$(patsubst <pattern>,<replacement>,<text>)
$(patsubst %.c,%.o,a.c b.c c.c)
dir获取目录
$(dir <names…>)
$(dir </src/a.c>)
notdir去除目录
$(notdir <names…>)
$(notdir </src/a.c>)
foreach 循环遍历
$(foreach <var>, <list>,<text>)
$(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
#取出srcdirs中的所有目录并使用wildcard获取所有.S文件
wildcard
$(wildcard PATTERN…)
$(wildcard *.c)
获取当前目录下所有的.c 文件,类似“%”。
gcc编译选项
-c
只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
例子用法:
gcc -c hello.c
他将生成.o的obj文件
-S
只激活预处理和编译,就是指把文件编译成为汇编代码。
例子用法
gcc -S hello.c
他将生成.s的汇编代码,你可以用文本编辑器察看
-o
制定目标名称,缺省的时候,gcc 编译出来的文件是a.out,很难听,如果
你和我有同感,改掉它,哈哈
例子用法
gcc -o hello.exe hello.c
gcc -o hello.asm -S hello
-L[dir]
制定编译的时候,搜索库的路径。比如你自己的库,可以用它制定目录,不然
编译器将只在标准库的目录找。这个dir就是目录的名称。
-l[library]
制定编译的时候使用的库
例子用法
gcc -lcurses hello.c
使用ncurses库编译程序
-I[dir]
在你是用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头
文件,如果没有找到,他回到缺省的头文件目录找,如果使用-I制定了目录,他
回先在你所制定的目录查找,然后再按常规的顺序去找.
对于#include,gcc/g++会到-I制定的目录查找,查找不到,然后将到系
统的缺省的头文件目录查找
-g
只是编译器,在编译的时候,产生条是信息。
-D[宏]
-O0
-O1
-O2
-O3
编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最
高
-nostdlib
不连接系统标准启动文件和标准库文件,只把指定的文件传递给连接器。这个选项常用于编译内核、bootloader等程序,它们不需要启动文件、标准库文件。
-include file
包含某个代码,简单来说,就是便以某个文件,需要另一个文件的时候,就可以
用它设定,功能就相当于在代码中使用#include
例子用法:
gcc hello.c -include /root/pianopan.h
-imacros file
将file文件的宏,扩展到gcc/g++的输入文件,宏定义本身并不出现在输入文件
中
-I-
就是取消前一个参数的功能,所以一般在-Idir之后使用
-idirafter dir
在-I的目录里面查找失败,讲到这个目录里面查找
-iprefix prefix
-iwithprefix dir
一般一起使用,当-I的目录查找失败,会到prefix+dir下查找
-nostdinc
使编译器不再系统缺省的头文件目录里面找头文件,一般和-I联合使用,明确
限定头文件的位置
-C
在预处理的时候,不删除注释信息,一般和-E使用,有时候分析程序,用这个很
方便的
-M
生成文件关联的信息。包含目标文件所依赖的所有源代码
你可以用gcc -M hello.c来测试一下,很简单。
-MM
和上面的那个一样,但是它将忽略由#include造成的依赖关系。
-MD
和-M相同,但是输出将导入到.d的文件里面
-MMD
和-MM相同,但是输出将导入到.d的文件里面
实例1
vpath *.dll lib
main : d.dll main.o
gcc -Llib -ld main.o
d.dll : a.o b.o
gcc -shared -o ./lib/d.dll a.o b.o
a.o : a.c
gcc -c a.c
b.o : b.c
gcc -c b.c
main.o : main.c
gcc -DASD -c main.c
.PHONY : clean
clean:
rm -rf *.o *.exe *.dll