Makefile 讲解与总结

首先Makefile的格式
目标:依赖
行为

编译普通的.c文件,或者编译单个文件
例如:callback.c 编译生成可执行程序callback

$ gcc -o  callback  callback.c

执行这条指令就会编译生成,可执行程序 callback 可以使用 ./callback 运行该程序

编译一个文件,pthread_1.c

$ gcc -o pthread_1 pthread_1.c  -lpthread

编译含有创建线程的程序,需要在结尾加上 -lpthread 连接这个库。如果编译很多文件,那就麻烦了。

假设现在有多个文件: main.c mytools1.c mytools2.c 三个源文件,执行这句话就是

$gcc -c main.c              这一步执行会生成.o文件,main.o
$gcc -c mytool1.c           这一步执行会生成.o文件,mytools1.o
$gcc -c mytool2.c           这一步执行会生成.o文件,mytools2.o
$gcc -o main main.o mytool1.o mytool2.o   将上面编译产生的中间文件,编译连接成可执行程序main.c

gcc -c 编译文件会生成中间文件,主要用在多个文件的编译。
单独编译一个文件,没有必要生成中间文件,可以使用gcc -o “可执行程序” 源文件

如果文件再增加,使用这种方式明显不能进行编译了,需要Makefile的规则帮我们进行编译。


Makefile常用的一些变量
$@ :表示规则中的目标文件集。在模式规则中,如果有多个目标,那么, $@ 就是匹配于目标中模式定义的集合。
$< :依赖目标中的第一个目标名字。如果依赖目标是以模式(即 % )定义的,那么 $< 将是符合模式的一系列的文件集。注意,其是一个一个取出来的
$^ :所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$% :仅当目标是函数库文件时,表示规则中的目标成员名。例如,如果一个目标是 foo.a(bar.o),那么, $% 就是 bar.o , $@ 就是 foo.a 。如果目标不是函数库文件(Unix 下是 .a , Windows下是 .lib ),那么,其值为空
$? :所有比目标新的依赖目标的集合。以空格分隔。
$+ :这个变量很像 $^ ,也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$* :这个变量表示目标模式中 % 及其之前的部分。如果目标是 dir/a.foo.b ,并且目标的模式是 a.%.b ,那么, $* 的值就是 dir/a.foo 。这个变量对于构造有关联的文件名是比较有用。如果目标中没有模式的定义,那么 $* 也就不能被推导出,但 是,如果目标文件的后缀是 make 所识别的,那么 $* 就是除了后缀的那一部分。例如:如果目标是 foo.c ,因为 .c 是 make 所能识别的后缀名,所以, $* 的值就是 foo 。这个特性是 GNU make 的,很有可能不兼容于其它版本的make,所 以,你应该尽量避免使用 $* ,除非是在隐含规则或是静态模式中。如果目标中的后缀是make 所不能识别的,那么 $* 就是空值。


gcc/g++ 编译使用的链接参数
-g 打开 gdb 调试
-Wall 打开编译警告,即C语言编译过程中产生的警告显示出来
-pthread 编译连接线程,即与线程有关的API接口调用需要链接这个参数

-L :表示要链接的库所在的目录。-L. 表示要链接的库在当前目录, -L/usr/lib 表示要连接的库在/usr/lib下。目录在/usr/lib时,系统会自动搜索这个目录,可以不用指明。

-l (L的小写):表示需要链接库的名称,注意不是库文件名称,比如库文件为 libtest.so,那么库名称为test

-include :包含头文件,这个很少用,因为一般情况下在源码中,都有指定头文件。

-I (i 的大写):指定头文件的所在的目录,可以使用相对路径。

-shared :指定生成动态链接库

-fPIC: 表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时事通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码共享的目的。

可以使用 SRC_FILES := $(wildcard *.c) 来获取工作目录下的所有的.c文件列表。
OBJS := $(patsubst %.c,%.o,$(SRC_FILES) )中,patsubst把$(SRC_FILES)中的变量符合后缀是.c的全部替换成.o

两个注意点:
1.编译链接,patsubst 展开替换,是将.c文件替换成.o文件,所以 %.c 在 %.o之前
2、编译中间文件 $(OBJS) 可以简单理解为编译中间生成的 .o 文件,然后需要理解 .o 文件依赖 .c 文件所以就是:$(OBJS): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ 注意这里的换行。

先看一个实例:

CC = gcc
CFLAGS = -g -Wall -pthread

SRC_FILES := $(wildcard ./*.c)
OBJS := $(patsubst %.c, %.o, $(SRC_FILES))

TARGET = nwy_pthread

#编译生成目标 $(TARGET) 依赖中间文件 $(OBJS)
$(TARGET): $(OBJS)
    $(CC) $(CFLAGS) $^ -o $@

#编译中间文件 .o 文件依赖 .c源文件, 下面是编译链接规则
$(OBJS): %.o: %.c
    $(CC) -c $(CFLAGS) $< -o $@

#建立伪目标指令进行清理
.PHONY:clean
clean:
    rm -rf $(OBJS)

.PHONY:cleanall
cleanall:
    rm -rf $(TARGET) $(OBJS)

如果项目是包含多文件夹,多文件的工程,那么需要链接头文件所在的文件夹,源文件所在的文件夹,下面是一个例子:

CC = gcc
CFLAG = -g -Wall -pthread

#链接头文件所在的文件夹
INC = -I ./inc

#指定了源文件所在的文件夹,这里使用./src 与src都一样,如果要拷贝Makefile要注意
SRC := $(wildcard ./src/*.c)

#将$(SRC)中的.c文件,扩展替换为.o文件
OBJS := $(patsubst %.c, %.o, $(SRC))

TARGET=my_pthread

$(TARGET): $(OBJS)
    $(CC) $(CFLAG) $^ -o $@

#编译生成的中间文件是依赖于头文件的,所以要链接上头文件
$(OBJS): %.o: %.c
    $(CC) -c $(CFLAG) $< -o $@ $(INC)


.PHONY:clean
clean:
    rm -rf $(OBJS)

.PHONY:cleanall
cleanall:
    rm -rf $(OBJS) $(TARGET)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值