构建Makefile(一)
在linux/Cygwin
下构建Makefile的第一步是做工具链和命令的环境设置,一般在项目根创建一个buildenv.mk
文件,内容如下:
ifeq "$(PHYROOT)" " "
$(error "$$PHYROOT environment variable is not defined!")
endif
PHYROOT:/$(subst \,/,$(PHYROOT))
ifeq "$(strip $(OSTYPE))" "cygwin"
ifeq "$(strip $(NOCYGWIN))" "yes"
ifeq "$(shell uname -m)" "x86_64"
PREFIX=x86_64-w64-mingw32-
else
PREFIX=i686-w64-mingw32-
endif
else
PREFIX?=
endif
else
PREFIX?=
endif
GCC=$(PREFIX)gcc
CC = $(PREFIX)gcc
CPP=$(PREFIX)g++
AR=$(PREFIX)ar
NM=$(PREFIX)nm
DUMP=$(PREFIX)objdump
AS=$(PREFIX)as
LD=$(PREFIX)ld
# Common UNIX utilities
BINFIX= /usr/bin
MKDIR=$(BINFIX)/mkdir -p
RM=$(BINFIX)/rm -rf
CAT=$(BINFIX)/cat
ECHO=$(BINFIX)/echo
MV=$(BINFIX)/mv
CP=$(BINFIX)/cp
OD=$(BINFIX)/od
XXD=$(BINFIX)/xxd
其中的PHYROOT
一般是本项目的目录位置,也可以用个判断设置为当前路径,像这样:
ifeq "$(PHYROOT)" " "
PHYROOT:=$(pwd)
endif
放在本文件的最前面。
有了这个buildenv.mk
文件就可以在Makefile
里制作编写各种编译规则了。
构建Makefile(二)
首先要有buildenv.mk
文件,在准备编译所需要的文件及目录条件,下面是Makefile
的前面半截内容
include ../buildenv.mk
TARGET=libBase.a
SRC_DIR=.
SRCS=$(wildcard $(SRC_DIR)/*.c)
HEADS=$(wildcard $(SRC_DIR)/*.h)
OBJS=$(patsubst $(SRC_DIR)/%.c, %.o, $(SRCS))
DEPS=$(patsubst %.o, %.d, $(OBJS))
ADEP=Makefile.dep
COMMON_DIR=../phy/common
INSTALL_HEADS=$(patsubst %.h, $(COMMON_DIR)/%.h, $(notdir $(HEADS)))
CFLAGS ?= -ggdb --std=gnu99 -Wall
CINCS = -I$(SRC_DIR)
CDEFS =
CLIBS = -lm
需要逐个解释一下:
最开始是包含引用buildenv.mk
文件
定义编译目标,此处是一个静态库.a
文件,静态库的命名习惯是libXXX.a
定义源码目录,这里简单地放在同一级目录下了
源码文件列表,这里使用了个make文件的内嵌宏wildcard,它扫描源码目录,将全部.c文件包含其中
头文件列表,使用内嵌宏将全部.h文件包含其中
目标文件列表,使用内嵌替换宏,patsubst
将后缀为.c的列表改为后缀为.o的列表
依赖文件列表,使用宏将后缀为.o的改为.d的列表
工程依赖文件命名为Makefile.dep
,这只是遵循习惯
COMMON_DIR
此处其实是安装的目的目录, 就是编译完成后的结果放置路径
INSTALL_HEADS
是把本地的头文件列表转换为目标文件列表,先用notdir去掉列表中的文件目录前缀,再用patsubst
将.h加上固定的目录前缀
CC编译设置 CFLAGS,会有:调试代码-g
或-ggdb
; 代码规范--std
,推荐用gnu99
;编译报警,建议全部打开-Wall
CC包含设置CINCS,增加包含源码目录
CC预定义设置CDEFS,有时会用到类似-DTEST
,相当于源码中设置“#define TEST”
CC库设置CLIBS,经常情况下会包含math
,可视需要增加pthread或其他在/usr/lib
下使用的库,有时还会加入自己编译出来的库
构建Makefile(三)
下面编写Makefile
内部的规则项,只给出最简单的一些规则:
install: all
$(CP) $(HEADS) $(COMMON_DIR)
$(CP) $(TARGET) $(COMMON_DIR)
all: $(ADEP) $(DEPS) $(TARGET)
$(TARGET): $(OBJS)
$(AR) -rv $@ $(OBJS)
%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $(CINCS) $(CDEFS) -c $< -o $@
%.d: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) $(CINCS) $(CDEFS) -MM -MQ -c $< > $@
$(ADEP): $(DEPS)
$(CAT) $< > $@
clean:
$(RM) $(addprefix *., o a s v d dep exe log stackdump ini)
clobber: clean
$(RM) $(INSTALL_HEADS) $(COMMON_DIR)/$(TARGET)
注意按Makefile规则要求,每行开始字符串为规则名,执行命令内容以\t
开始,辅助(预执行规则或是输入条件)写在规则名的":"
后
这里的目标是个libBase.a
静态库文件,所以对$(TARGET)
的生成规则使用了$AR
库打包命令。
网友评论