Inclusive Makefile

来源:互联网 发布:sai for mac版 编辑:程序博客网 时间:2024/06/06 14:53
以前项目中,我都用Recursive Make去构建编译环境。这种方式感觉直观,而且单一,仅仅用Makefile就可以完成,但是不足之处是,扩展起来麻烦,数据定义和规则耦合在一起,并且每执行一次子Make都要step到那个目录。耗时。最近发现在北电的项目中,使用了一种叫做Inclusive的Make。完全摒弃了Recursive的缺点。尤其是在定义和规则相分离上优势明显,并且扩展起来很方便。项目中通过Makefile+Perl+shell共同构建起了load build系统。我理解了他的思想后,写了一个demo.为了简化,我采用了Python+Makefile的组合。一共包含三个部分:
1.控制部分(build.xml)
2.模板部分
3.实例数据部分

控制部分主要的责任就是,利用模板将每个实例部分用实例数据实例化一个make对象,并执行它。

如果我们要添加模块,只需要在新模块目录下添加一份用来实例化对象的数据文件Build.mk就行了。

build.py / build.xml

from xml.etree.ElementTree import ElementTree
import os
import sys
from optparse import OptionParser
class InitConfiguration:
def __init__(self):
  self.dir = ""
  self.modules = []
def initialize(self , file):
  if os.path.exists(file):
   print "parsing:" , file
  else:
   print "can not find the file:" , file
   sys.exit(-1)
  
  xmlTree = ElementTree().parse(file)
  
  for node in xmlTree.getchildren():
   if node.tag == "topdir":
    self.dir = node.text
   if node.tag == "module":
    self.modules.append(node.text)
  
  
def invoke(self):
  cmd = "make MODULE=/'"
  for arg in self.modules:
   cmd = "make MODULE="
   cmd += arg
   cmd += " TOPDIR="
   cmd += self.dir
   print cmd
   os.system(cmd)
def clean(self):
                cmd = "make MODULE=/'"
                for arg in self.modules:
                        cmd = "make MODULE="
                        cmd += arg
                        cmd += " TOPDIR="
                        cmd += self.dir
   cmd += " clean_objs"
                        print cmd
                        os.system(cmd)
  
  os.system("make clean_libs clean_bins")
def main():
        init = InitConfiguration()
        init.initialize("../config/Build.xml")
usage = "%prog options"
optionParser = OptionParser(usage)
optionParser.add_option('--opt', dest='opt' , help='')
(options , args) = optionParser.parse_args()
if options.opt == "clean":
  init.clean()
  return

init.initialize("../config/Build.xml")
init.invoke()
return
if __name__ == "__main__":
main()  
------------------------------------------------------------------
<build>
<topdir>../../src/lteoff/domain/oam</topdir>
<module>pm</module>
<module>fm</module>
<module>sm</module>
<module>util</module>
</build>


模板Makefile:

MODULEDIR = $(patsubst %,$(TOPDIR)/%,$(MODULE))
INSTALL = /usr/bin/install
CC = g++
AR = $(CC)
ARFLAGS = -shared
RM = rm -rf
CXXFLAGS = -O3 -g -Wall
LDFLAGS = -lpthread
CPPFLAGS = -I./
LIBPATH = -L./
LINK = $(CC) -o ../../bin/$@ $^
ARCLIB = $(AR) $(ARFLAGS) -o ../../lib/lib$@.so $^ $(LDFLAGS) $(LIBPATH)
include $(patsubst %,%/Build.mk,$(MODULEDIR))
ifneq (,$(ARCHIVE))
        ifneq (,$(PROGRAM))
                DEPEND += $(ARCHIVE) $(PROGRAM)
        else
                DEPEND += $(ARCHIVE)
        endif
else
        ifneq (,$(PROGRAM))
                DEPEND += $(PROGRAM)
endif
endif
APP_VAR = $($(PROGRAM)_SRC)
ARC_VAR = $($(ARCHIVE)_SRC)
APP_OBJS = $(patsubst %.cpp,%.o,$(APP_VAR))
ARC_OBJS = $(patsubst %.cpp,%.o,$(ARC_VAR))
%.o: %.cpp
@(echo compiling $@)
$(CC) -c $< -o $@ $(CPPFLAGS) $(CXXFLAGS)
all: $(DEPEND)
@(echo done)
$(ARCHIVE): $(ARC_OBJS)
@(echo creating archive $(LIB))
$(ARCLIB)

$(PROGRAM): $(APP_OBJS)
@(echo creating executing file $(BIN))
$(LINK)
.PHONY: clean_objs clean_libs clean_bins
clean_objs:
$(RM) $(MODULEDIR)/*.o
clean_libs:
$(RM) ../../lib/*
clean_bins:
$(RM) ../../bin/*

最后是数据Makefile,在每个字模块目录下面都有一个Build.mk,里面存放了为模板Makefile实例化的数据
Build.mk

PROGRAM = fmApp
fmApp_SRC = $(TOPDIR)/fm/fmApp.cpp

ARCHIVE = fm
fm_SRC = $(TOPDIR)/fm/fm.cpp
原创粉丝点击