一、Makefile文件

为了方便分析,直接上文件,Makefile 文件中的内容如下所示:

#
# Makefile
# 编译的.o文件和.c文件在同一路径下
#

$(info "start...")
# 可执行文件名
PROJECT_NAME = app

##################################### 项目路径 #####################################
PROJECT_PATH ?= ${shell pwd}
OBJ_DIR := $(PROJECT_PATH)/build

##################################### 设置编译器,默认使用GCC #####################################
CC ?= gcc

##################################### 所需头文件的路径 #####################################
CFLAGS += -I$(PROJECT_PATH)/lib/inc

##################################### 编译和链接参数 #####################################
CFLAGS ?= -O3 -g0 -Wall -Wshadow -Wundef -Wmissing-prototypes
LDFLAGS ?= -lm

##################################### 收集需要编译的源文件 #####################################
CSRCS += $(PROJECT_PATH)/application/main.c
include $(PROJECT_PATH)/lib/lib.mk


##################################### 将文件名替换为.o文件 #####################################
CXX_OBJCTS = $(patsubst  %.c, $(OBJ_DIR)/%.o, $(notdir $(CSRCS)))
SOURSE_DIR = $(dir $(CSRCS))

vpath %.c $(SOURSE_DIR)

$(OBJ_DIR)/%.o: %.c
	@$(CC) $(CFLAGS) -c $< -o $@
	#@echo "CC $<"

all: $(CXX_OBJCTS)
	@$(CC) -o $(PROJECT_NAME)  $(CXX_OBJCTS) $(LDFLAGS)

clean: 
	@rm -f $(PROJECT_NAME) $(CXX_OBJCTS)

二、代码分析

  1. 查找所有.c文件

    # 方式一
    CSRCS += $(PROJECT_PATH)/application/main.c
    
    # 方式二
    CXX_SOURCES = $(foreach dir,$(CSRCS), $(wildcard $(dir)/*.c))
    

    注意:方式一是直接将所有的 .c 文件追加到 CSRCS 变量中,方式二是将搜索路径下的所有 .c 文件,并追加到 CSRCS 变量中。

  2. 将所有的 .c 文件换成 .o 文件

    # 方式一
    COBJS = $(CSRCS:.c=.o)
    # 方式二
    COBJS= $(patsubst  %.c, %.o, $(CSRCS))
    

    注意:方式一和方式二原理都是一样的,其目的是将所有的 .c 文件换成 .o 文件而已

  3. 生成 .o 文件

    /%.o: %.c
    	@$(CC) $(CFLAGS) -c $< -o $@
    	#@echo "CC $<"
    

    注意:第2点只是将 .c 文件 换成了 .o 文件名,得到的只是文件名称而已,这里才是根据相应的目标生成 .o 文件

  4. 链接成可执行文件
    将所有的 .o 文件链接成可执行文件

    @$(CC) -o $(PROJECT_NAME)  $(CXX_OBJCTS) $(LDFLAGS)
    
  5. 清理所有的 .o 文件

    @rm -f $(PROJECT_NAME) $(CXX_OBJCTS)
    

注意:以上就是 make 的编译流程,但是编译生成的 .o 文件和.c 文件是在同一目录下的,不满足我们的需求,接着网下看

  1. 将所有的 .o 文件放到指定目录下

    CXX_OBJCTS = $(patsubst  %.c, $(OBJ_DIR)/%.o, $(notdir $(CSRCS)))
    

    注意: notdir $(CSRCS) 函数是去掉文件路径,只保留文件名,如此便可以在替换后缀的时候,在文件前面加上指定路径

  2. 完成指定路径下的所有 .o 文件的目标

    $(OBJ_DIR)/%.o: %.c
    	@$(CC) $(CFLAGS) -c $< -o $@
    	#@echo "CC $<"
    

    注意:这里的作用在源文件中查找能制作目标的文件,因为这里的目标和源文件不在同一目录下,所以需要完成第8点的操作

  3. vpath 和 VPATH
    这里我也不是很理解,在自动目标中需要将源文件路径加入 vpath 或 VPATH 中,如下所示:

    # 方式一
    VPATH += :$(SRC_DIR)
    # 方式二
    SOURSE_DIR = $(dir $(CSRCS))
    vpath %.c $(SOURSE_DIR)
    

    注意:函数 dir 的作用是提取所有文件的路径

参考链接

linux Makefile 如何将生成的.o文件放到指定文件:https://blog.csdn.net/forgetjoker/article/details/117676029