执行make之后,make会在当前目录找Makefile文件,找到之后,会去此Makefile中找终极目标。make从上往下解析Makefile,找到的第一个目标就视为终极目标。
Makefile中最主要的就是生成目标的规则。一条规则包含三个部分:目标和依赖,以及生成目标的命令。其他的部分都可以看做是附加部分,例如给变量赋值,使用各种Makefile的函数等等。
目标可以有依赖,也可以没有依赖,依赖就是目标的冒号后面的内容,例如:
$(EXE): checkdir $(objects) build
中,$(EXE)就是目标,后面的checkdir $(objects) build都是依赖。当make生成一个目标的时候,会从前到后依次检查所有的依赖,如果是文件,就检查文件是否存在,如果不存在就生成文件;如果是一个PHONY的目标,那么就执行一下这个目标就行了。
目标可以有命令,也可以没有命令。如果有命令,则必须以tab键开头。例如上例中,目标 ( E X E ) 就 没 有 生 成 目 标 的 命 令 , 所 以 在 生 成 目 标 (EXE)就没有生成目标的命令,所以在生成目标 (EXE)就没有生成目标的命令,所以在生成目标(EXE)时,只是生成一下后面的各个依赖就完事了。又例如:
build:
$(Q) $(CR_CC) $(CC_FLAGS) -o $(application_bin_dir)/$(EXE)/$(EXE) $(objects) $(LOCAL_LFLAGS) $(LOCAL_CFLAGS) $(LIBS) -Xlinker -Map=$(objects_dir)/$@.map
目标build只有命令,没有依赖。这种情况就直接执行一下下面的命令就完事了。
如果一个目标既有依赖,又有命令,那么会先生成各个目标,然后再执行生成目标的命令。
综上,make执行的过程,就像一个函数调用的过程,其中终极目标(第一次出现的目标)就是程序的主入口,然后依次执行依赖,依赖可能也是一个目标,于是一个目标一个目标的执行完了,最终Makefile直行完毕。
附上一个完整的Makefile:
EXE:=cv2x_app
objects_dir:=$(application_bin_dir)/objs/$(EXE)_objs
#subdirs := $(wildcard */)
subdirs := $(shell find . -maxdepth 3 -type d)
#sources += $(wildcard $(addsuffix *.c,$(subdirs)))
sources += $(foreach dir,$(subdirs),$(wildcard $(dir)/ *.c))
objects := $(patsubst %.c, $(objects_dir)/%.o, $(sources))
all_depends := $(patsubst %.c, $(objects_dir)/%.d, $(sources))
ifeq ($(MOCAR_N4LAYER_CV2X_SDK),N4L)
SRC_SDK_LIB_DIR := $(top_dir)/lib/$(MOCAR_PLATFORM_IMX)/location/lib/n4l
else
SRC_SDK_LIB_DIR := $(top_dir)/lib/$(MOCAR_PLATFORM_IMX)/location/lib/4l/
endif
LOCAL_CFLAGS:= -I $(top_dir)/application/cv2x_app/cv2x_app_main/include \
-I $(top_dir)/lib/$(MOCAR_PLATFORM_IMX)/location/include \
-I $(top_dir)/application/cv2x_app/cv2x_app_middleware/include
LOCAL_LFLAGS:= -L $(top_dir)/lib/$(MOCAR_PLATFORM_IMX)/gps/lib \
-L $(top_dir)/lib/$(MOCAR_PLATFORM_IMX)/log
LIBS+=-lpthread -lm -ldl -lgps -lmocarcv2x -levent -lzlog -lshamem -lsqlite3
$(EXE): checkdir $(objects) build
$(objects_dir)/%.o: %.c
$(Q) $(CR_CC) $(CC_FLAGS) -c $< -o $@ -MD -MF $(objects_dir)/$*.d -MP $(LOCAL_CFLAGS)
@echo "CC "$(EXE)/$<
-include $(all_depends)
checkdir:
$(Q) mkdir -p $(application_bin_dir)/$(EXE)
$(Q) for dir in $(subdirs); do mkdir -p $(objects_dir)/$$dir; done
build:
$(Q) $(CR_CC) $(CC_FLAGS) -o $(application_bin_dir)/$(EXE)/$(EXE) $(objects) $(LOCAL_LFLAGS) $(LOCAL_CFLAGS) $(LIBS) -Xlinker -Map=$(objects_dir)/$@.map