1、快速使用
-
下载
demo
可以直接克隆Gitee
仓库,文章末尾也会贴上Makefile
文件 -
demo
工程结构如下,对于用户的工程,只需将Makefile
复制到工程根目录下,将.c
文件和.h
文件路径,添加到Makefile
的SRC_DIRS
和INC_DIRS
参数中即可:
.
├── inc
│ └── print_func.h
├── main
│ └── main.c
├── Makefile
├── README.md
└── src
└── print_func.c
- 添加完工程的
.c
和.h
文件路径后,确认OUTPUT
(目标文件)、DEBUG
(调试等级)、DEFS
(宏开关)、TOOLCHAIN_PREFIX
(工具链前缀)等参数无误,在工程根目录下执行make
可执行编译,执行make execute
可运行目标,执行make clean
可删除编译中间文件(build
目录),执行make distclean
可删除build
目录及目标文件
2、Makefile文件详解
- (1)目标文件
a)
target
文件的名称,编译中会在工程根目录下创建build
存放中间文件,目标文件也会在build
中生成
OUTPUT := common-makefile.bin
- (2)调试等级
a)
Makefile
中定义了DEBUG_CFLAGS/DEBUG_LDFLAGS
、RELEASE_CFLAGS/RELEASE_LDFLAGS
宏,将一些常见的调试参数放了进去,然后做了个DEUBG
开关,可以很方便地切换编译等级
b)以上参数会归入CFLAGS
、LDFLAGS
2个变量,最终参加编译
c)一般编译调试将DEBUG
打开,对外释放则关闭(否则目标文件中,会多出一些调试参数)
DEBUG := YES
DEBUG_CFLAGS := -Wall -Wno-format -MMD -DDEBUG -std=gnu99
RELEASE_CFLAGS := -Wall -Wno-unknown-pragmas -Wno-format -MMD -O3 -std=gnu99
LIBS := -lpthread -lrt
DEBUG_LDFLAGS := -g
RELEASE_LDFLAGS :=
ifeq (YES, ${DEBUG})
CFLAGS += ${DEBUG_CFLAGS}
LDFLAGS := ${DEBUG_LDFLAGS}
else
CFLAGS += ${RELEASE_CFLAGS}
LDFLAGS := ${RELEASE_LDFLAGS}
endif
- (3)编译宏开关
a)编译中用到的宏开关,可以统一添加到
DEFS
中,例如-DDEBUG_LEVEL=0
等
b)DEFS
参数会归入CFLAGS
变量,参加编译
DEFS :=
CFLAGS := ${DEFS}
- (4)源文件和头文件路径
a)源文件和头文件路径,是需要重点修改的地方,用户自定义的所有
.c
和.h
文件,其路径要逐个添加到SRC_DIRS
、INC_DIRS
变量中
b)其中第1个被添加的路径用:=
添加(表示如果变量被定义过,则覆盖原定义),后续添加的路径用+=
添加(表示如果变量被定义过,则追加定义)
c)对于demo
工程的结构,有如下路径定义(CURDIR
是Makefile
中的默认变量,表示文件当前所在目录,abspath
是Makefile
内置函数,表示取绝对路径):
PROJ_DIR := $(abspath ${CURDIR})
INC_DIRS := ${PROJ_DIR}/inc
SRC_DIRS := ${PROJ_DIR}/main
SRC_DIRS += ${PROJ_DIR}/src
- (5)源文件和头文件参数的展开
a)
SRC_DIRS
变量通过以下方式,展开成一个.c
文件的列表,其中foreach
和wildcard
都是Makefile
内置的函数,前者表示遍历变量的每个元素,后者表示匹配目录下的特定文件(此处表示匹.c
文件)
b)后续再将上面解析出的.c
文件列表,依次转换成.o
中间文件、.d
依赖文件(生成到build
目录下)
SRC_DIRS := ${PROJ_DIR}/main
SRC_DIRS += ${PROJ_DIR}/src
SRC_FILES := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))
OBJ_FILES := $(SRC_FILES:%.c=$(BUILD_DIR)/%.o)
DEP_FILES := $(OBJ_FILES:%.o=%.d)
c)
INC_DIRS
变量,通过-I
参数包含用户自定义的头文件。在编译过程中,寻找.c
文件中包含的.h
文件,都会到INC_DIRS
中去查找(标准头文件则会到/usr/include
路径下面查找)
INC_DIRS := -I${PROJ_DIR}/inc
INC_DIRS +=
@$(CC) $(CFLAGS) ${INC_DIRS} ${LDFLAGS} ${LIBS} ${EXTRA_LIBS} -c $< -o $@
- (6)编译工具链相关
a)每种平台的编译工具链都不相同,但至少都包含了
gcc
、ar
工具,用户需要修改工具链的前缀
b)例如linux
平台默认就是gcc
、ar
,所以不需要加前缀,arm
平台可能用arm-none-eabi-gcc
等交叉工具链,前缀就是arm-none-eabi-
TOOLCHAIN_PREFIX :=
CC := $(TOOLCHAIN_PREFIX)gcc
LD := $(TOOLCHAIN_PREFIX)gcc
AR := $(TOOLCHAIN_PREFIX)ar
- (7)编译过程解析
需要花点时间,有空再补充
- (8)
clean
、distclean
、execute
等
做一些清理工作,和一些执行动作
clean:
-rm -rf $(BUILD_DIR)
distclean:
-rm -rf ${BUILD_DIR} ./${OUTPUT}
execute :
-cp ${BUILD_DIR}/${OUTPUT} ./
./${OUTPUT}
3、demo工程
a)工程结构
.
├── inc
│ └── print_func.h
├── main
│ └── main.c
├── Makefile
├── README.md
└── src
└── print_func.c
b)
Makefile
文件
#****************************************************************************
# target output
#****************************************************************************
OUTPUT := common-makefile.bin
#****************************************************************************
# DEBUG can be set to YES to include debugging info, or NO otherwise
#****************************************************************************
DEBUG := YES
#****************************************************************************
# PROFILE can be set to YES to include profiling info, or NO otherwise
#****************************************************************************
PROFILE := NO
#****************************************************************************
# add your compile macro, such as: -DDEBUG_LEVEL=0
#****************************************************************************
DEFS :=
CFLAGS := ${DEFS}
#****************************************************************************
# add your source & header file path
#****************************************************************************
PROJ_DIR := $(abspath ${CURDIR})
INC_DIRS := -I${PROJ_DIR}/inc
INC_DIRS +=
SRC_DIRS := ${PROJ_DIR}/main
SRC_DIRS += ${PROJ_DIR}/src
#****************************************************************************
# set your toolchain prefix
#****************************************************************************
TOOLCHAIN_PREFIX :=
CC := $(TOOLCHAIN_PREFIX)gcc
LD := $(TOOLCHAIN_PREFIX)gcc
AR := $(TOOLCHAIN_PREFIX)ar
#****************************************************************************
# set your compile parameters
#****************************************************************************
DEBUG_CFLAGS := -Wall -Wno-format -MMD -DDEBUG -std=gnu99
RELEASE_CFLAGS := -Wall -Wno-unknown-pragmas -Wno-format -MMD -O3 -std=gnu99
LIBS := -lpthread -lrt
DEBUG_LDFLAGS := -g
RELEASE_LDFLAGS :=
ifeq (YES, ${DEBUG})
CFLAGS += ${DEBUG_CFLAGS}
LDFLAGS := ${DEBUG_LDFLAGS}
else
CFLAGS += ${RELEASE_CFLAGS}
LDFLAGS := ${RELEASE_LDFLAGS}
endif
ifeq (YES, ${PROFILE})
CFLAGS += -pg -O3
LDFLAGS += -pg
endif
#****************************************************************************
# lib files path
#****************************************************************************
LIB_DIRS :=
EXTRA_LIBS := $(foreach dir, $(LIB_DIRS), $(wildcard $(dir)/*.a))
#****************************************************************************
# start prepare operation
#****************************************************************************
BUILD_DIR := ${PROJ_DIR}/build
SRC_FILES := $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c))
OBJ_FILES := $(SRC_FILES:%.c=$(BUILD_DIR)/%.o)
DEP_FILES := $(OBJ_FILES:%.o=%.d)
#****************************************************************************
# start compile operation
#****************************************************************************
${OUTPUT} : $(BUILD_DIR)/$(OUTPUT)
${BUILD_DIR}/${OUTPUT} : ${OBJ_FILES}
@echo "Build $(notdir $@)..."
@-mkdir -p ${@D}
@$(CC) $^ ${CFLAGS} ${INC_DIRS} ${LDFLAGS} ${LIBS} ${EXTRA_LIBS} -o $@
-include ${DEP_FILES}
.PHONY : all clean distclean execute
all:
${BUILD_DIR}/%.o : %.c
@echo "Build $(notdir $<)..."
@-mkdir -p $(@D)
@$(CC) $(CFLAGS) ${INC_DIRS} ${LDFLAGS} ${LIBS} ${EXTRA_LIBS} -c $< -o $@
clean:
-rm -rf $(BUILD_DIR)
distclean:
-rm -rf ${BUILD_DIR} ./${OUTPUT}
execute :
-cp ${BUILD_DIR}/${OUTPUT} ./
./${OUTPUT}