在Linux开发中,Makefile占有比较重要的一席之地。几乎所有的开源项目都会带有Makefile——或脚本产生,或自带。前面的文章也有介绍过,linux环境编译程序有三个步骤:./configure、make和make install。在此过程,configure脚本就会产生Makefile。
另外有些项目是自带Makefile的,比如busybox和kernel。当然,现在也有很多项目为了跨平台编译而使用cmake,比如opencv。
在实际开发中,笔者比较喜欢使用自己编写的Makefile模板,包括应用层和驱动层。本文主要说说应用层的Makefile模板。这个模板的好处是在使用时,只需要修改编译器名称(比如交叉编译情况)、目标名称、头文件、库文件路径即可,其它无需修改。可适用于静态库、动态库、二进制程序的编译。
为了方便介绍,下面分段说说Makefile内容。如使用Makefile模板,请到文后github下载。另外要注意的是Makefile的规则后是使用Tab键的,不能使用空格。
1、编译器、链接器配置。如需交叉编译,则在这里指定交叉编译器。
# !!!=== cross compile...
CROSS_COMPILE ?=
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
ARFLAGS = -cr
RM = -rm -rf
MAKE = make
2、这里指定目标文件,可以是静态库.a文件,动态库.so文件,其它则为二进制文件。后面会根据此目标名称做判断,执行相应的动作。
# !!!===
# target executable file or .a or .so
target = a.out
# !!!===
# compile flags
CFLAGS += -Wall -Wfatal-errors
#****************************************************************************
# debug can be set to y to include debugging info, or n otherwise
debug = y
#****************************************************************************
ifeq ($(debug), y)
CFLAGS += -ggdb -rdynamic
else
CFLAGS += -O2 -s
endif
# !!!===
DEFS += -DJIMKENT
CFLAGS += $(DEFS)
CXXFLAGS = $(CFLAGS)
LIBS +=
LDFLAGS += $(LIBS)
# !!!===
INC1 = ./
INC2 = ./inc
INC3 =
INCDIRS := -I$(INC1) -I$(INC2)
# !!!===
CFLAGS += $(INCDIRS)
CXXFLAGS +=
# !!!===
LDFLAGS += -lpthread -lrt
DYNC_FLAGS += -fpic -shared
6、这里是源码目录名称。如果是工程源码与Makefile在同一级目录,则使用下面的即可(默认是“.”,表示当前目录)。
# !!!===
# source file(s), including c file(s) or cpp file(s)
# you can also use $(wildcard *.c), etc.
SRC_DIR = .
SRC_DIR1 =
SRC_DIR2 =
SRC_DIR3 =
ifeq ($(V),1)
Q=
NQ=true
else
Q=@
NQ=echo
endif
$(target): $(OBJ)
ifeq ($(suffix $(target)), .so)
@$(NQ) "Generating dynamic lib file..." $(notdir $(target))
$(Q)$(CXX) $(CXXFLAGS) $^ -o $(target) $(LDFLAGS) $(DYNC_FLAGS)
else ifeq ($(suffix $(target)), .a)
@$(NQ) "Generating static lib file..." $(notdir $(target))
$(Q)$(AR) $(ARFLAGS) -o $(target) $^
else
@$(NQ) "Generating executable file..." $(notdir $(target))
$(Q)$(CXX) $(CXXFLAGS) $^ -o $(target) $(LDFLAGS)
endif
# make all .c or .cpp
%.o: %.c
@$(NQ) "Compiling: " $(addsuffix .c, $(basename $(notdir $@)))
$(Q)$(CC) $(CFLAGS) -c $< -o $@
%.o: %.cpp
@$(NQ) "Compiling: " $(addsuffix .cpp, $(basename $(notdir $@)))
$(Q)$(CXX) $(CXXFLAGS) -c $< -o $@
clean:
@$(NQ) "Cleaning..."
$(Q)$(RM) $(target)
# use 'grep -v soapC.o' to skip the file
@find . -iname '*.o' -o -iname '*.bak' -o -iname '*.d' | xargs rm -f
Makefile模板的git仓库地址:https://github.com/latelee/Makefile_templet
这个仓库作者会不定时更新。欢迎大家使用并提出宝贵意见。
李迟 2017.9.3 夜