Chinaunix首页 | 论坛 | 博客
  • 博客访问: 374113
  • 博文数量: 53
  • 博客积分: 1411
  • 博客等级: 上尉
  • 技术积分: 701
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-04 14:40
文章分类

全部博文(53)

文章存档

2011年(6)

2010年(20)

2009年(18)

2008年(9)

我的朋友

分类: LINUX

2009-02-16 11:08:39

    工程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初学者有所帮助!

阅读(7205) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~