在linux平台下,除去使用IDE软件进行开发项目,大部分的软件项目都是需要自己写makefile的。其实自从我使用linux平台进行c,c++的开发后,就没有再像windows上面的vs那样,让IDE工具帮助我组织代码结构以及编译环境了。一开始还怀恋工具软件的方便快捷,讨厌手动管理的麻烦。到后来就觉得当时的自己浅显无知。如今,从只在一个文件中做代码修改到独立做一个项目的makefile,终于感受到makefile的强大和方便之处。编写makefile可以帮助我们对代码组织结构,的理解,甚至阅读makefile也有此帮助。
今天要说的不是谈论makefile的好处,而是给大家看一个比较通用的makefile模板。这个makefile模板可以方便的组织代码,库和目标文件。也许你在后面做项目开发时也可以用的上。
makefile的语法规则这里不做详解,下面先放出一个模板。
假如代码组织结构是下面这样的。
moduleA
a.c
a.h
moduleB
b.c
b.h
include
common.h
type.h
libs
libxshare.so
libystatic.a
Makefile
Readme.md
…
我们可以使用下面这样的makefile文件
.PHONY: all
#CROSS_COMPILE = arm-linux-gnueabihf-
VERSION = debug
ifeq ($(VERSION), debug)
DEBUG = -DDEBUG=1 -g
else
DEBUG = -O2
endif
CC = $(CROSS_COMPILE)gcc
CPP = $(CROSS_COMPILE)g++
CFLAGS =-Wall $(DEBUG)
CXXFLAGS =-Wall $(DEBUG)
LDFLAGS = -lpthread -lxshare -L./libs
STATICFLAGS = ./libs/libystatic.a
TARGET = target.out
BUILDPATH=.
SRCDIRS:=. \
moduleA \
moduleB
SRCCS=$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c))
SRCCXXS=$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.cpp))
SRCFILES=$(SRCCS) $(SRCCXXS)
INCLUDES:=$(foreach dir,$(SRCDIRS),-I$(dir)) \
-Iinclude
LIBOBJ=$(addprefix $(BUILDPATH)/, $(addsuffix .o, $(basename $(SRCFILES))))
all: $(TARGET)
$(BUILDPATH)/%.o:%.c
$(CC) $(CFLAGS) ${INCLUDES} -o $@ -c $<
$(BUILDPATH)/%.o:%.cpp
$(CPP) $(CXXFLAGS) ${INCLUDES} -o $@ -c $<
$(TARGET):$(LIBOBJ)
$(CPP) $(LDFLAGS) -o $@ $^ $(STATICFLAGS)
@echo "-----------------build OK-------------------"
clean:
rm -f $(TARGET) $(LIBOBJ)
install:
cp $(TARGET) ../$(TARGET)
从头开始说起这个makefile
.PHONY : all 定义一个伪目标,目标并非实际的文件名,有两种情况可以使用.PHONY目标:避免和同名文件冲突,改善性能。这里的这一行不是必需的。
#CROSS_COMPILE = arm-linux-gnueabihf-这里注释掉了,只是因为我工作的平台不一样,这里是编译器的前缀,一般不需要。make内置了一些符号和变量,可以帮助我们方便的管理和配置,这里只做举个例子,在这篇文档中,这个不重要。
VERSION=debug定义版本,方便release和debug版本的编译,比如是使用make VERSION=release 就不会用到“-g”参数了,版本的编译参数控制在下面ifeq那几行。
“CC” “CPP” “CFLAGS 是一些变量来控制make时候的执行命令。这个地方很容易理解,但也很重要。这里设置了gcc, g++这两种编译器,然后还设置了编译过程中的动态库和静态库。例如文件目录lib下面存放着库文件,这里设置参数让动态库libxshare.so 和静态库libystatic.a参与到编译过程中。
SRCCS=$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c)) 这里使用了makefile内置函数, $(widldcard *.c) 列出目录下的.c文件。$(foreach var, list, body) 从list里面提取出每一个字符串,并将其赋值给var,然后执行body的动作 。这里就是遍历目录下的c文件。
下面就是找到目录下的所有源文件,并根据依赖关系执行相应的命令了。还是记一下make脚本的内置符号,这符号真的很不人性,太容易忘。但是却非常方便,而且这样使用就对了,也不需要怎么记。
$@ :target的名称
$* :和target类似 只是不包含target的后缀
$^ :所有先决条件名称,以空格(space)分隔,如果先决条件有重复,自动去重。
$? :先决条件更新表,比如4个先决条件,更新了2个文件,就代表那两个文件,make是按文件更新时间来确定是否执行命令的嘛。
$< :第一个先决条件名称。
配置好各种变量参数,下面的内容都可以是一样的了,make install 什么的,可以安装自己的需要进行更改。