您的位置:首页 > 运维架构 > Linux

快速实现工程makefile的简单通用模板

2016-12-08 19:43 399 查看
以前刚开始接触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

好了,你可以尝试试用下看看。我修改我的大型工程,修改起来还是很快的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mekefile linux