如何写好Makefile

						Makefile笔记整理
  1. 什么是Makefile?
    makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
  2. make的作用?
    Makefile制定的规则,由make工具来执行,make就是工程管理工具:帮助我们实现项目的自动编译
  3. Makefile的规则
    粗略地Makefile的规则:
    Target…:prerequisites…
    [TAB]command
    target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label).
    prerequisites就是,要生成那个target所需要的文件或是目标。
    command也就是make需要执行的命令
    #其中第一条规则中的目标,将会成为终极目标,其他目标是为终极目标服务的,因为最终目的,就是为了生成这个目标.
    #其他规则之间,没有必然顺序联系
    4,Makefile的命名?
  4. 默认的情况下,make命令会在当前文件夹下按顺序找寻文件名称为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件。在这三个文件名称中,最好使用 “Makefile”这个文件名称,由于,这个文件名称第一个字符为大写,这样有一种显目的感 觉。最好不要用“GNUmakefile”,这个文件是GNU的make识别的。有另外一些make仅仅对全小写的“makefile”文件名称敏感,可是基本上来说,大多数的make都支持“makefile”和“Makefile”这两种默认文件名称
  5. 当想要自己指定makefile文件名时候,例如my_mkfile 执行命令make -f my_mkfile
  6. Makefile中赋值方式
    =  延时变量,只有被使用时才展开定义 也就是说,变量的值将会是整个makefile中最后被指定的值,如:x=fool,y= ( x ) b a r , x = x y z , 这 个 例 子 中 , y 的 最 终 值 是 x y z b a r , 而 不 是 f o o l b a r : =   立 即 变 量 , 定 义 时 的 赋 值 立 即 有 效 变 量 的 值 决 定 于 它 在 m a k e f i l e 中 的 位 置 , 而 不 是 整 个 m a k e f i l e 展 开 后 的 最 终 值 , 如 x = f o o l , y = (x)bar,x=xyz,这个例子中,y的最终值是xyzbar,而不是foolbar := 立即变量,定义时的赋值立即有效 变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值,如x = fool,y= (x)bar,x=xyz,yxyzbar,foolbar:=makefilemakefile,x=fool,y=(x)bar,x := xyz,y的最终值是foolbar
    ?= 条件变量,当变量为空时才赋值
    += 追加赋值,类似字符串string
  7. 引用一个实例讲解接下来的知识点
    1.print.h
    #include<stdio.h>
    Void printhello();
  8. print.c
    #include”print.h”
    Void printhello()
    {
    Printf(“hello,world”);
    }
  9. main.c
    #include”print.h”
    Int main()
    {
    Printhello();
    return 0;
    }
    编译这个程序:gcc main.c print.c
    如果是大工程,这样就会很繁琐
    6.最简单的Makefile
    Helloworld:main.c print.c
    gcc -o helloworld main.c print.c
    有一个问题就是,假如我们更改了main.c 或者print.c其中一个文件,重新make的时候会导致所有的文件跟着一起更新,如果是大工程,就会耗费系统资源和时间,对于这些源文件,我们应该分别处理,执行:预处理 编译 汇编 ,先分别编译它们,最后再把它们链接在一起
    7.引入.o文件
    Helloworld:main.o print.o
    gcc –o main.o print.o
    main.o:main.c
    gcc –c main.c
    print.c:print.o
    gcc –c print.c
    8,引入标签clean
    每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。这是一个“修养”。
    clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”。
    Helloworld:main.o print.o
    gcc –o main.o print.o
    main.o:main.c
    gcc –c main.c
    print.c:print.o
    gcc –c print.c
    clean:
    rm –rf main.o print.o helloworld
    9.引入伪目标
    执行make的时候会将clean误认为是目标文件,所以如果在同目录下有clean文件,makeclean就不会执行成功,所以指定一下clean标签
    Helloworld:main.o print.o
    gcc –o main.o print.o
    main.o:main.c
    gcc –c main.c
    print.c:print.o
    gcc –c print.c
    .PHONY:clean
    clean:
    rm –rf main.o print.o helloworld
    好了,一个成型的makefile到此完成
    10,引入变量
    变量名字可以包含字符、数字(可以用在开头)、下划线,但不可以是: # = 或空字符。 变量是大小写敏感的。
    如果源文件过多,我们每次添加或删除一个不必要的源文件可能或造成不必要的纰漏
    Object = main.o print.o
    Target = helloworld
    ( T a r g e t ) : (Target): (Target):(Object)
    gcc –o helloworld main.o print.o
    main.o:main.c
    gcc –c main.c
    print.c:main.c
    gcc –c print.c
    .PHONY:clean
    Clean:
    rm –f $(Target) $(Object)
    11,引入特殊变量
    $@:当前规则中的目标
    $$:当前执行的进程编号
    $^:当前规则中的所有依赖
    $*:模式规则中的所有%匹配的部分
    $<:当前依赖中的第一个
    $?:模式规则中所有比所在规则中的目标更新的文件组成列表
    Object = main.o print.o
    Target = helloworld
    ( T a r g e t ) : (Target): (Target):(Object)
    gcc $^ –o $@
    main.o:main.c
    gcc –c $<
    print.c:main.c
    gcc –c $<
    .PHONY:clean
    Clean:
    rm –f $(Target) $(Object)
    12,引入通配符
    这样的Makefile还不算完善,因为我们每假如新的文件都要去修改Makefile,如果一下子加1000个.c文件就会很是繁琐
    *:表示所有文件的前缀
    %:%为Makefile规则通配符,一般用于规则描述
    -:发生错误时继续执行
    @使命令在被执行前不被回显。比如我们不想c语言中的printf被打印出来吧
    Object = *.o
    Target = helloworld
    ( T a r g e t ) : (Target): (Target):(Object)
    @echo start -----
    gcc $^ –o $@
    @echo end
    %.c:%.o
    gcc –c $<

.PHONY:clean
Clean:
-rm –f $(Target) $(Object)
13,引入函数
Wildcard:获取工作目录下的所有.c文件
Notdir:去除所有的目录信息,src = $(notdir wildcarcd),src中文件名列表将只有文件名
Patsubst:src = ( p a t s u b s t (patsubst%.c ,%.o , (patsubst(SRC)),意思是找到所有的.c结尾文件然后替换成.o
SRC = $(wildcard *.c)
File = $(notdir $(SRC))
Object = ( p a t s u b s t (patsubst %c,%.o, (patsubst(File))
Target = helloworld
( T a r g e t ) : (Target): (Target):(object)
Gcc $^ -o $@
%.o:%.c
Gcc –c $<
.PHONY:clean
Clean:
-rm $(Target) $(object)
14,隐含规则
make会按照这种“惯例”心照不喧地来运行,那怕我们的Makefile中没有书写这样的规则。例如,把[.c]文件编译成[.o]文件这一规则,你根本就不用写出来,make会自动推导出这种规则,并生成我们需要的[.o]文件。
SRC = $(wildcard *.c)
File = $(notdir $(SRC))
Object = ( p a t s u b s t (patsubst %c,%.o, (patsubst(File))
Target = helloworld
( T a r g e t ) : (Target): (Target):(object)
Gcc $^ -o $@
.PHONY:clean
Clean:
-rm $(Target) $(object)
在这里插入图片描述
可以使用make -p 打印出make的所有隐含规则
15.引入.d文件
在一个工程中,因为头文件被源文件所包含,所以头文件的更新应该使得它所依赖的文件也被更新,
使用gcc -MM可以查看到源文件生成对应的.o文件需要依赖那些文件
在这里插入图片描述
于是我们在Makefile中引入.d文件,其实文件名称是自己定义,无所谓
%.d:%.c
gcc -MM $< > $@
我们将依赖关系重定向到.d文件中,这样就可以实现改变头文件会导致所依赖的源文件重新编译

16,多目录Makefile
一般管理代码会将代码放入不同目录下进行管理,方便维护
文件存放说明:
bin: 存放编译生成的二进制文件
src: 存放源文件 (add.c multis.c sub.c main.c)
obj: 存放编译生成的目标文件
include: 存放头文件 (add.h multis.h sub.h)
Makefile 文件和 bin、src、include处于同一级目录
Makefile的写法
CUR_DIR = $(shell pwd)
INC_DIR = $(CUR_DIR)/include
BIN_DIR = $(CUR_DIR)/bin
SRC_DIR = $(CUR_DIR)/src
OBJ_DIR = $(CUR_DIR)/obj
SRC = $(wildcard $(SRC_DIR)/*.c)
OBJ = ( p a t s u b s t (patsubst %.c, (patsubst(OBJ_DIR)/%.o,$(notdir $(SRC)))
TARGET = main
BIN_TARGET = ( B I N D I R ) / (BIN_DIR)/ (BINDIR)/(TARGET)
CC = gcc
CFLAGS = -g –Wall –I(INC_DIR)
( B I N T A R G E T ) : (BIN_TARGET): (BINTARGET):(OBJ)
$(CC) $(OBJ) –o $@
@echo “Compile done”
( O B J D I R ) / (OBJ_DIR)/%.o: (OBJDIR)/(SRC_DIR)/%.c
@echo “Compiling $< ==>”
$(CC) $(CFLAGS) –c $< -o $@
.PHONY:clean
Clean:
@rm –f $(OBJ)
@echo “clean object files done”
@rm –f *~
@echo “clean tempreator files done”
@rm –f $(TARGET)
@echo “Clean target files done”
@echo “Clean done”

注释:
CFLAGS:指定头文件路径
LIBS:告诉连接器要链接那些库文件
LDFLAGS:gcc等编译器会用到的一些优化参数也可以在里面指定库文件的位置
Export:导出变量将被子make继承,有点类似C语言中的全局变量
CROSS_COMPILE:指的是交叉编译器(或前缀),这里是arm-linux(-gcc)。可以在Makefile中指定,也可以在	     
make clean仅仅是清除之前编译的可执行文件及配置文件。 

make distclean要清除所有生成的文件
CXXFLAGS用于C++代码
AR:归档文件
AS:汇编器
LD:连接器

obj-y += foo.o 该例子告诉Kbuild在这目录里,有一个名为foo.o的目标文件。foo.o将从foo.c 或foo.S文件编译得到
"obj-y += subdir/"表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。
strip 去掉字符串中多余的空格符(若干单词,使用若干空字符分割) “STR”开头和结尾的空字符,并将其中多个连续空字符合并为一个空字符。
arm-linux-objcopy 复制选项,支持格式转换
arm-linux-objdump 反编译选项
o 编译及链接,会生成一个exe可执行文件
-Wall 指定产生全部的警告信息
-O/-O2/-O3 数字越高,代表优化的更多,可以使生成的执行文件的提高执行效率
-c 编译不链接,会生成一个*.obj文件,若后面加了-o,则表示指定输出文件名称
-static 静态链接,生成的文件会非常大, 好处在于不需要动态链接库,也可以运行
-S 只激活预处理和编译,就是指把文件编译成为汇编代码
-g选项是指可以用gdb调试

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值