CC :=g++ LD :=g++ SRCDIR := src BUILDDIR := build TARGET :=bin/target
SRCEXT:=cpp SOURCES:=$(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) OBJECTS:=$(patsubst $(SRCDIR)/%, $(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o)) DEP:=$(OBJECTS:%.o=%.d) CFLAGS:= LDFLAGS:= INC:= -I include
$(TARGET):$(OBJECTS) @echo "Linking..." @echo "$(LD) $^ -o $(TARGET) $(LIB)" $(LD) -o $(TARGET) $^ $(LDFLAGS)
-include $(DEP) $(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) @mkdir -p $(sort $(dir $(OBJECTS))) @echo "$(CC) $(CFLAGS) $(INC) -c -o $@ $<" $(CC) $(CFLAGS) $(INC) -MM -MT $@ -MF $(patsubst %.o, %.d, $@) $< $(CC) $(CFLAGS) $(INC) -c -o $@ $<
#$(CC) $(CFLAGS) -MMD -c -o $@ $< clean: @echo "cleaning..."; @echo "$(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET) .PHONY:clean
├── bin │ ├── target │ ├── build │ ├── main.d │ ├── main.o │ ├── code.d │ └── code.o ├── include │ └── code.hpp ├── makefile ├── src ├── main.cpp └── code.cpp
-k:它的作用是让make命令在发现错误时仍然继续执行,而不是在检测到第一个错误时就停下来。 -n:它的作用是让make命令输出将要执行的操作步骤,而不真正执行这些操作 -f :它的作用是告诉make命令将哪个文件作为makefile文件。如果未使用这个选项,标准版本的make
= 是最基本的赋值,makefile展开后最终的值 := 是覆盖之前的值,决定于它在makefile中的位置当前值 ?= 是如果没有被赋值过就赋予等号后面的值 += 是添加等号后面的值
.PHONY是一个伪目标,可以防止在Makefile中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突, 另一种是提交执行makefile时的效率 当一个目标被声明为伪目标后,make在执行此规则时不会试图去查找隐含规则来创建这个目标 访问shell内变量两个$$,访问makefile变量需要加$()或者${} 执行shell两种方式$(shell find $(SRCDIR), `find $(SRCDIR)` echo:会在shell中显示echo这条命令和这条命令的输出结果 @echo:不会在shell中显示echo这条命令,但是会显示命令的输出结果 加上“-”,即使这条命令出错,makefile也会继续执行后续命令的
make -C subdir
make -C /lib/modules/`uname -r`/build M=`pwd`/drivers/net/usb obj-m=GobiNet.o modules
make -C /usr/src/linux M=/usr/src/linux/drivers/net/ethernet/intel/igb modules
* :表示目标文件的名称,不包含目标文件的扩展名。 + :表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能包含重复的依赖文件。 < :表示依赖项中第一个依赖文件的名称 ? :依赖项中,所有目标文件时间戳晚的文件(表示修改过),依赖文件间以空格分开 @ :目标项中目标文件的名称 ^ :依赖项中,所有不重复的依赖文件,以空格分开
shell环境下:
$$: 代表shell本进程的PID(Process ID) $?: 最后运行结束的进程的结束码(返回值) $*: 所有的的参数列表,以"$1 $2 ...$n"的形式表示 $@: 所有的参数列表,以"$1" "$2" ..."$n"的形式表示 $#: 所有参数的个数 $0: 运行程序的文件名
Shell脚本在target里才有效,其它地方都被忽略掉了 把每一行Shell脚本当作一个独立的单元 make在调用Shell之前先进行预处理,即展开所有Makefile的变量和函数。这些变量和函数都以$开头 make预处理时,所有以$开头的,它都不会放过。要想引用Shell自己的变量,应该以$$开头。 另外要注意,Shell自己的变量是不需要括号的
main:main.o code1.o code2.o gcc -o main main.o code1.o code2.o main.o:main.c code1.h code2.h gcc -c main.c code1.o:code1.c code1.h gcc -c code1.c code2.o:code2.c code2.h gcc -c code2.c
main:main.o code1.o code2.o gcc -o $@ $^ .c.o: gcc -c $< 这个规则表示所有的 .o文件都是依赖与相应的.c文件的
-E: 预处理,主要是进行宏展开等步骤,生成的文件微test.i gcc -E test.c
-S: 编译,生成汇编代码,生成的文件为test.S gcc -S test.c
-c: 汇编:生成机器码,生成的文件未test.o gcc -c test.c
(-o): 链接:生成可执行文件 gcc test.c (-o test)
-I后面紧跟着用户设定的编译器头文件查找路径 -L后面紧跟着用户设定的编译器库文件查找路径 -Wall,打开gcc的所有警告。 -W选项类似-Wall,会显示警告,但是只显示编译器认为会出现错误的警告 -Werror,它要求gcc将所有的警告当成错误进行处理。 -D,其意义是添加宏定义
1、wildcard : 扩展通配符 src=$(wildcard *.c ./sub/*.c) wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。 2、notdir : 去除路径 dir=$(notdir $(src)) 3、patsubst :替换通配符 $(patsubst <pattern>,<replacement>,<text> ) $(patsubst %.c,%.o,$(dir) ) patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o, 4、 foo := a.o b.o c.o; bar := $(foo:.o=.c) 将变量“foo”以空格分开的值中的所有的字的尾字符“o”替换为“c”,其他部分不变。
1、“=” make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。 x = foo y = $(x) bar x = xyz 在上例中,y的值将会是 xyz bar ,而不是 foo bar 。
2、“:=” 表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。 x := foo y := $(x) bar x := xyz 在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。