以前刚开始接触linux开发的时候,发现makefile真麻烦,我学C/C++开发已经花了不少时间了,现在还要花这个时间类搞这玩意,真是麻烦。真希望能出现一个模板,我只需要填下我需要编译的文件,以及相应的目录,其他的我啥都不用管,该多好呀。本文就是奔着这个目标来的,所以本文不会描述makefile的语法啥的。
工作了这么多年,大大小小的工程已经也开发了不少,幸好公司也有一个模板,我平时都是用公司的模板,我只需要往里面填一些个要编译的文件,以及工程依赖的其他库、头文件目录、库目录,生成目录,除了这些外,我基本上啥都不用关心,真心舒服,但是公司模板也有他的缺陷,就是C和C++不能同时编译,还有就是所有的.o文件不能放到同一个目录,当然这些都不是问题,对于我来说,有点受够了,于是自己对公司的模板动手了。
先写一个我平时写的makefile
TOP := ..
COMM_DIR := .
SRC_DIR := $(TOP)/source
## Name and type of the target for this Makefile
INSTALL_APP_PATH := ./debug
APP_TARGET := smart
## Define debugging symbols
DEBUG = 1
## Object files that compose the target(s)
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
## Libraries to include in shared object file
LIBS :=pthread dl
## Add driver-specific include directory to the search path
CFLAGS += -D_LINUX_
INC_PATH += $(TOP)/include
LIB_PATH := ./debug
INSTALL_LIB_PATH = ./debug
include $(COMM_DIR)/cxxcommon.mk
这就是一个进程的makefile 。这样看起来可能也是有点多,如果就仅仅是编译一个helloworld,用这个确实很麻烦,还不如我直接调用gcc -c -o …来的快,但是如果写一个工程量较大的makefile来说的话,这个还是很方便的,你只需要关注几个变量:
SRCS:所有的源码都需要使用这个,类似如下:
SRCS += $(SRC_DIR)/SDL.c
SRCS += $(SRC_DIR)/SDL_assert.c
…
INC_PATH 所有的头文件的路径 类似SRCS的写法可以使用 +=
LIBS 依赖的所有库
APP_TARGET进程的标示,SO_TARGET 动态库 ARC_TARGET静态库标示
COMM_DIR存放cxxcommon.mk路径
其他的基本上都是一些个临时变量了,所有的东西都在cxxcommon.mk
,这个里面的东西,你基本不用修改,而只需要关注自己的makefile就好了,除非你有特殊的要求。我的cxxcommon.mk的内容粘贴下
### Keda Telecom, Inc.(kedacom.com 俺东家)
### ARC_TARGET - target name for archive file, excluding file extension.
### ARC_TARGET - 静态库
###
### SO_TARGET - target name for shared object file, excluding file extension.
### SO_TARGET - 动态库
### APP_TARGET - target name of application.
### APP_TARGET - 进程
###
### SRCS 源代码文件 一般是.c .cpp等 非头文件
###
### LIB_SUFFIX 其实就是在文件后面加一个字符串,一般没啥用
###
### TOP 顶层目录
###
### OBJDIR 临时库存放的目录,如果没有给出,就会在顶层目录下面创建一个build目录
###
### INC_PATH 所有头文件的目录
###
### LIB_PATH 如果是so 或者是APP,需要依赖的lib库目录
###
### LIBS 所有的依赖库
###
### INSTALL_LIB_PATH 静态库安装目录
###
### INSTALL_APP_PATH APP安装目录
###
### APP_DIR APP安装在INSTALL_APP_PATH目下的子目录 如果定义了INSTALL_APP_PATH,就会忽略APP_DIR
###
### CROSS 交叉编译时使用
###
### SUB_FILE 其他需要安装的文件列表
###
### CP_FILE 需要拷贝的文件
###
### CPFILE_PATH 需要拷贝到指定的目录
## ARC_TARGET 静态库 后面加 .a
ifneq ($(ARC_TARGET),)
ARC_TARGET := lib$(ARC_TARGET)$(LIB_SUFFIX).a
endif
## SO_TARGET shared库 后面加.so
ifneq ($(SO_TARGET),)
SO_TARGET := lib$(SO_TARGET)$(LIB_SUFFIX).so
endif
## 如果木有存放临时库的地方,存放top目录下build
ifeq ($(OBJDIR),)
OBJDIR :=$(TOP)/build/
endif
## C的源文件
CSRCS:=$(filter %.c %.C,$(SRCS))
## C++的源文件
CPPSRCS:=$(filter %.cc %.CC %.cpp %.Cpp %.CPP,$(SRCS))
## 去除目录,只剩文件名和后缀,此时只需要把后缀修改成.o然后再加上一个目录,就是OBJS了
SRCFILE:=$(notdir $(SRCS))
## 所有 .o文件存放路径
#OBJS:=$(patsubst %.c,%.o,$(SRCFILE))
OBJS :=$(SRCFILE:.c=.o)
OBJS :=$(OBJS:.C=.o)
OBJS :=$(OBJS:.cc=.o)
OBJS :=$(OBJS:.CC=.o)
OBJS :=$(OBJS:.cpp=.o)
OBJS :=$(OBJS:.Cpp=.o)
OBJS :=$(OBJS:.CPP=.o)
#OBJS :=$(addprefix $(OBJDIR),$(OBJS))
OBJS :=$(foreach file,$(SRCS),$(OBJDIR)$(basename $(notdir $(file))).o)
## 如果是 Debug模式 如下
ifeq ($(DEBUG),1)
CFLAGS += -g
CFLAGS += -O0
CFLAGS += -DDEBUG=$(DEBUG)
endif
## Release
ifeq ($(DEBUG),0)
CFLAGS += -O2
CFLAGS += -DNDEBUG
endif
# 动态库
ifneq ($(SO_TARGET),)
CFLAGS += -fpic
endif
#科达的通讯库如osp必须要 _LINUX_,所以此处增加一个,木有坏处
CFLAGS += -D_LINUX_
#所有头文件 路径
CFLAGS += $(foreach dir,$(INC_PATH),-I$(dir))
#依赖的静态库路径
LDFLAGS += $(foreach lib,$(LIB_PATH),-L$(lib))
# 动态库
ifneq ($(SO_TARGET),)
LDFLAGS += -shared
endif
## 加入 rt库
LDFLAGS += -lrt
##链接的所有静态库
LDFLAGS += $(foreach lib,$(LIBS),-l$(lib)$(LIB_SUFFIX))
## 如果木有提供INSTALL_LIB_PATH 程序自动给出目录
ifndef INSTALL_LIB_PATH
INSTALL_LIB_PATH = $(TOP)/lib/
endif
## 默认应用程序安装路径
ifndef INSTALL_APP_PATH
## ifneq($(APP_DIR),)
## INSTALL_APP_PATH = $(TOP)/app/$(APP_DIR)
## else
INSTALL_APP_PATH = $(TOP)/app
## endif
endif
CP = $(CROSS)cp
CC = $(CROSS)gcc
CPP = $(CROSS)g++
LD = $(CROSS)g++
AR = $(CROSS)ar
INSTALL = install -D -m 644
OBJDUMP = objdump
RM = -@rm -f
define NEWLINE
endef
## 去掉前后空格后ARC_TARGET还有值
ifneq ($(strip $(ARC_TARGET)),)
## CFLAGS += -DFD_SETSIZE=512
all: $(ARC_TARGET) ARLINK ARCINSTALL
install_arc: $(ARC_TARGET) ARLINK ARCINSTALL
#$(AR) crus $(ARC_TARGET) $(OBJS)
#$(INSTALL) $(ARC_TARGET) $(INSTALL_LIB_PATH)/$(ARC_TARGET)
$(ARC_TARGET) : GENEOBJ
ARLINK:
$(AR) crus $(ARC_TARGET) $(OBJS)
ARCINSTALL:
$(INSTALL) $(ARC_TARGET) $(INSTALL_LIB_PATH)/$(ARC_TARGET)
uninstall: uninstallarc
uninstallarc:
$(foreach file, $(INSTALL_INC), $(RM) $(INSTALL_INC_PATH)/$(file) $(NEWLINE))
$(RM) $(INSTALL_LIB_PATH)/$(ARC_TARGET)
clean: cleanarc
cleanarc:
$(RM) $(ARC_TARGET) $(OBJS)
endif
ifneq ($(strip $(SO_TARGET)),)
all: install
install: install_inc install_so
install_so: $(SO_TARGET)
$(INSTALL) $(SO_TARGET) $(INSTALL_LIB_PATH)/$(SO_TARGET)
$(foreach file, $(SUB_FILE), $(INSTALL) $(file) $(INSTALL_LIB_PATH)/$(file) $(NEWLINE))
$(foreach file, $(CP_FILE), $(CP) -rf $(CPFILE_PATH)$(file) $(INSTALL_LIB_PATH)/$(file) $(NEWLINE))
$(SO_TARGET) : GENEOBJ
$(LD) $(OBJS) -o $(SO_TARGET) $(LDFLAGS) -fpic
uninstall: uninstallso
uninstallso:
$(foreach file, $(INSTALL_INC), $(RM) $(INSTALL_INC_PATH)/$(file) $(NEWLINE))
$(RM) $(INSTALL_LIB_PATH)/$(ARC_TARGET)
clean: cleanso
cleanso:
$(RM) $(SO_TARGET) $(CP_FILE) $(OBJS)
else
#echo $(SRCFILE)
#$(foreach file,$(OBJS), $(file))
endif
## Rules for making applications
ifneq ($(strip $(APP_TARGET)),)
all: install
install: install_inc install_app
install_app: $(APP_TARGET)
$(INSTALL) $(APP_TARGET) $(INSTALL_APP_PATH)/$(APP_TARGET)
$(APP_TARGET): GENEOBJ
$(LD) $(OBJS) -o $(APP_TARGET) $(LDFLAGS)
clean: cleanapp
cleanapp:
$(RM) $(APP_TARGET)
endif
GENEOBJ: createdir
$(foreach file,$(CSRCS),$(CC) $(CFLAGS) -c -o $(OBJDIR)$(basename $(notdir $(file))).o $(file) $(NEWLINE))
$(foreach file,$(CPPSRCS),$(CPP) $(CFLAGS) -c -o $(OBJDIR)$(basename $(notdir $(file))).o $(file) $(NEWLINE))
install_inc:
$(foreach file, $(INSTALL_INC), $(INSTALL) $(file) $(INSTALL_INC_PATH)/$(notdir $(file)) $(NEWLINE))
##判断目录是否存在,不存在就创建
createdir:
test -d $(OBJDIR) || mkdir -p $(OBJDIR)
clean: cleanobjs
cleanobjs:
$(RM) $(OBJS)
setup:
(cd $(TOP); \
make install_inc; \
echo )
你可以把这些信息拷贝下来,保存到你的.mk文件中,下文最后一行include给修改成你的mk文件就好了,另外你的mk的路径就是COMM_DIR
好了,你可以尝试试用下看看。我修改我的大型工程,修改起来还是很快的。