一文掌握MAKEFILE和GCC

    技术2022-07-10  118

    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 了。

    Processed: 0.024, SQL: 9