您的位置:首页 > 其它

简单工程Makefile的编写

2009-02-23 10:11 288 查看
工程Makefile的编写,对于初始Makefile的菜鸟们来说,还是比较头疼的一件事情,如何做到整个工程结构清晰,各个模块相对独立,模块的添加
删除等都比较方便,各个层次的的Makefile风格一致,便于移植,这些并不容易。这里,就自己学习的一些体会,和大家分享一下。

本例工程,实现几种排序算法的具体代码实现和性能比较。工程结构如下:
sort
|-- Makefile
|-- Makefile.rule
|-- main
| |-- Makefile
| |-- include
| | |-- heap_sort.h
| | |-- quick_sort.h
| | `-- shell_sort.h
| |-- libs
| `-- src
| `-- sort.c
|-- heap_sort
| |-- Makefile
| |-- include
| `-- src
| `-- heap_sort.c
|-- quick_sort
| |-- Makefile
| |-- include
| `-- src
| `-- quick_sort.c
`-- shell_sort
|-- Makefile
|-- include
`-- src
`-- shell_sort.c

工程名:sort,根目录下的一级子目录包括main,heap_sort,quick_sort,shell_sort,每级目录中,有include

src目录,include中,包含该模块用到的相关头文件,src中是源代码。在main目录中,另有libs文件夹,工程需要引入的库可以放在该文件
夹中。

Makefile.rule
该文件为工程Makefile的通用规则定义,在各个模块的Makefile中被include。

该文件具体内容如下:

CC := gcc

AR := ar
ARFLAGS := -rcs
SRC := src
INCLUDES := include
LIBS := libs
CFLAGS := -g -Wall -O3 $(addprefix -I,$(INCLUDES)) /
$(addprefix -L,$(LIBS))
CXXFLAGS := $(CFLAGS)
CPPFLAGS += -MD
RM_F := rm -rf

HIDE_PREFIX := .
EXPORT_ODIR := $(HIDE_PREFIX)o
IMPORT_IDIR := $(HIDE_PREFIX)i

SOURCE := $(wildcard $(SRC)/*.c) $(wildcard $(SRC)/*.cc)
OBJS := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCE)))
DEPS := $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.c,$(MISSING_DEPS)) /
$(patsubst %.d,%.cc,$(MISSING_DEPS)))

该文件主要定义了工程的编译工具,编译链接的参数等。 EXPORT_ODIR和IMPORT_IDIR是编译之后模块的输入输出,编译生成.i和.o文件夹,.i中为模块需要引入的文件的软链接,.o中是该模块输出的文件的软链接。

工程总Makefile

根目录下的Makefile,内容如下:

TOPDIR := .
MODDIR := .
TARGET := $(notdir $(shell cd $(MODDIR) && pwd))
MODULES += quick_sort /
heap_sort /
shell_sort /
main

-include $(TOPDIR)/Makefile.rule

submodule_make = $(MAKE) -C $(TOPDIR)/$(1);
submodule_clean = $(MAKE) clean -C $(TOPDIR)/$(1);

.PHONY : all deps objs clean cleanall rebuild modules cleanmodules

all : $(TARGET)

deps : $(DEPS)

objs : $(OBJS)

modules :
@ $(foreach n,$(MODULES),$(call submodule_make,$(n)))

cleanmodules :
@ $(foreach n,$(MODULES),$(call submodule_clean,$(n)))

clean :
@ $(RM_F) *.o
@ $(RM_F) *.d
@ $(RM_F) *.a
@ $(RM_F) $(wildcard $(SRC)/*.o)
@ $(RM_F) $(wildcard $(SRC)/*.d)
@ $(RM_F) $(wildcard $(MODIR)/*.d)
@ $(RM_F) $(EXPORT_ODIR)
@ $(RM_F) $(IMPORT_IDIR)
@ echo CLEAN DONE

cleanall: cleanmodules clean
@ $(RM_F) $(wildcard $(TOPDIR)/*.d)
@ $(RM_F) $(TARGET)
@ echo CLEANALL DONE

rebuild: clean all

ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
@ $(RM_F) $(patsubst %.d,%.o,$@)
endif

-include $(DEPS)

$(TARGET) : $(OBJS) modules
@ echo MAKE $(TARGET) START
@ mkdir -p $(EXPORT_ODIR)
@ mkdir -p $(IMPORT_IDIR)
@ echo MAKE $(TARGET) DONE

在这个Makefile中,变量MODULES 定义了各个子模块,quick_sort,heap_sort,shell_sort, main。

main模块中Makefile

main模块下的Makefile,内容如下:

TOPDIR := ..
MODDIR := .
MODNAME := $(notdir $(shell cd $(MODDIR) && pwd))
TARGET := $(notdir $(shell cd $(TOPDIR) && pwd))
ALIBS = $(addprefix ../, $(wildcard $(TOPDIR)/$(IMPORT_IDIR)/*.a))
LDFLAGS += $(addprefix -L,$(IMPORT_IDIR))
LDFLAGS += $(foreach n,$(MODULES),$(addprefix -l,$(n)))

MODULES += quick_sort /
heap_sort /
shell_sort

-include $(TOPDIR)/Makefile.rule

submodule_make = $(MAKE) -C $(TOPDIR)/$(1);
submodule_clean = $(MAKE) clean -C $(TOPDIR)/$(1);

.PHONY : all deps objs clean cleanall rebuild modules cleanmodules

all : $(TARGET)

deps : $(DEPS)

objs : $(OBJS)

modules :
@ $(foreach n,$(MODULES),$(call submodule_make,$(n)))

cleanmodules :
@ $(foreach n,$(MODULES),$(call submodule_clean,$(n)))

clean :
@ $(RM_F) *.o
@ $(RM_F) *.d
@ $(RM_F) $(wildcard $(SRC)/*.o)
@ $(RM_F) $(wildcard $(SRC)/*.d)
@ $(RM_F) $(EXPORT_ODIR)
@ $(RM_F) $(IMPORT_IDIR)
@ echo CLEAN DONE

cleanall: cleanmodules clean
@ $(RM_F) $(TARGET)
@ echo CLEANALL DONE

rebuild: clean all

ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
@ $(RM_F) $(patsubst %.d,%.o,$@)
endif

-include $(DEPS)

$(TARGET) : $(OBJS) modules
@ echo MAKE $(TARGET) START
@ mkdir -p $(EXPORT_ODIR)
@ mkdir -p $(IMPORT_IDIR)
@ ln -sft $(IMPORT_IDIR) $(ALIBS)
$(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS)
@ cp -f $@ $(TOPDIR)
@ echo MAKE $(TARGET) DONE

在此模块中,变量MODULES定义了其依赖的子模块。首先编译子模块,然后编译本模块。

其他模块中Makefile

其他模块下的Makefile,内容如下:

TOPDIR := ..
MODDIR := .
MODNAME := $(notdir $(shell cd $(MODDIR) && pwd))
TARGET := $(addprefix lib,$(addsuffix .a,$(MODNAME)))
EXPORT_HEADERS += $(INCLUDES)/*.h
MODULES +=

-include $(TOPDIR)/Makefile.rule

submodule_make = $(MAKE) -C $(TOPDIR)/$(1);
submodule_clean = $(MAKE) clean -C $(TOPDIR)/$(1);

.PHONY : all deps objs clean cleanall rebuild

all : $(TARGET)

deps : $(DEPS)

objs : $(OBJS)

modules :
@ $(foreach n,$(MODULES),$(call submodule_make,$(n)))

cleanmodules :
@ $(foreach n,$(MODULES),$(call submodule_clean,$(n)))

clean :
@ $(RM_F) *.o
@ $(RM_F) *.d
@ $(RM_F) $(wildcard $(SRC)/*.o)
@ $(RM_F) $(wildcard $(SRC)/*.d)
@ $(RM_F) $(EXPORT_ODIR)
@ $(RM_F) $(IMPORT_IDIR)
@ echo CLEAN DONE

cleanall: cleanmodules clean
@ $(RM_F) $(TARGET)
@ echo CLEANALL DONE

rebuild: clean all

ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
@ $(RM_F) $(patsubst %.d,%.o,$@)
endif

-include $(DEPS)

$(TARGET) : $(OBJS) modules
@ echo MAKE $(TARGET) START
@ mkdir -p $(EXPORT_ODIR)
@ mkdir -p $(IMPORT_IDIR)
@ mkdir -p $(TOPDIR)/$(IMPORT_IDIR)
@ $(AR) $(ARFLAGS) -o $(TARGET) $(OBJS)
@ ln -sft $(TOPDIR)/$(IMPORT_IDIR) $(TOPDIR)/$(MODNAME)/$(TARGET)
@ echo MAKE $(TARGET) DONE

此Makefile不依赖于模块名及模块具体内容,具有较好的移植性。添加新的模块,只需直接将该Makefile复制到新模块目录下就可以了,然后在main模块Makefile和根Makefile中添加新的模块名。直接编译就可以了。

准备好了Makefile,就可以进行编译了。

在sort根目录下运行make:

root@mygirl:/study/sort# make
root@mygirl:/study/sort# ls
heap_sort sort main Makefile Makefile.rule quick_sort shell_sort
看到的新出现的文件sort,就是编译后的可之执行文件。

在sort根目录下运行make cleanall:

root@mygirl:/study/sort# make cleanall
root@mygirl:/study/sort# ls

heap_sort main Makefile Makefile.rule quick_sort shell_sort
这样,就可以清除编译生成的各个文件了。

至此一切OK! 希望对Makefile初学者有所帮助!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: