#! /usr/bin/env python
##
# @file
# waf Makefile.am related classed
#
# note: may be a future base of a Makefile.am to scons converter if someone like to write it
#
# (@) 2005 Ralf Habacker - published under the GPL license
#
import os, re, types, sys, string, shutil, stat, glob
## print a dictionary
def printDict(dict,sep=' = ' ):
for key in dict.keys():
print key + sep + dict[key]
## Makefile.am support class
#
# The class provides methods for the following tasks:
# - parsing Makefile.am's and collecting targets and defines into class members
# - extracting library dependencies and linker flags keyed by the related targets
# - extracting target libraries and programs
# - collecting detailled lists of libraries dependencies
#
#
class AMFile:
def __init__(self):
self.defines = {}
self.targets = {}
self.libadds = {}
self.ldflags = {}
self.libs = {}
self.progs = {}
self.sources = {}
self.includes= {}
self.headers = {}
self.data = {}
self.datadirs= {}
self.path = ''
self.subdirs = ''
## read and parse a Makefile.am
#
# The resulting lines are stored in the defines and targets class member.
# note: Multiple lines in a target are separated by '###'
# @param path - path for Makefile.am
# @return 0 if file couldn't be read
#
def read(self,path):
try:
src=open(path, 'r')
except:
return 0
self.path = path
file = src.read()
lines = file.replace('\n\t','###')
list = lines.replace('\\\n',' ').split('\n')
for line in list:
if line[:1] == '#' or len(line) == 0:
continue
index = 0
while line[index].count('#'):
index = line[index].index('#')
if line[index:index+3] == "###":
index += 3
var = line.split('=')
if len(var) == 2:
self.defines[str(var[0]).strip()] = var[1].strip().replace("'",'').replace('\###',' ')
else:
target = line.split(':')
if len(target) == 2:
single_target = target[1].strip().replace("'",'')
# TODO: (rh) split into list
self.targets[str(target[0]).strip()] = single_target
self.getLibraries()
self.getPrograms()
self.getIncludes()
self.getHeaders()
self.getSources()
self.getLibraryDeps()
self.getLinkerFlags()
self.getSubdirs()
self.getData()
return 1
## adds library dependencies from another AMFile instance
#
# This method is mainly used for an instance collecting definitions
# from instances from lower levels
# @param src - AMFile instance, from which the dependencies are imported
#
def addLibraryDeps(self,src):
for key in src.libadds.keys():
self.libadds[key] = src.libadds[key]
## adds linker flags from another AMFile instance
#
# This method is mainly used for an instance collecting definitions
# from instances from lower levels
# @param src - AMFile instance, from which the flags are imported
#
def addLinkerFlags(self,src):
for key in src.ldflags.keys():
self.ldflags[key] = src.ldflags[key]
def addSources(self,src):
for key in src.sources.keys():
self.sources[key] = src.sources[key]
def addLibraries(self,src):
for key in src.libs.keys():
self.libs[key] = src.libs[key]
def getSubdirs(self):
if self.defines.has_key('SUBDIRS'):
self.subdirs = self.defines['SUBDIRS']
del self.defines['SUBDIRS']
## collect all LIBADDS definitions
#
# the function store the definitions in the libadds class member keyed
# by the relating target
# @return definition list
#
def getLibraryDeps(self):
reg = re.compile("(.*?)_(?:l?a_)?LIBADD$")
# TODO (rh) fix relative library pathes
for key in self.defines.keys():
result=reg.match(key)
if result:
libadd = self.findRealTargetname(str(result.group(1)))
if not len(libadd):
print "WARNING: no corresponding target for libadd item %s \n" % str(result.group(1))
continue
self.libadds[libadd] = self.defines[key]
del self.defines[key]
return self.libadds
## collect all LDFLAGS definitions
#
# the function store the definitions in the ldflags class member keyed
# by the relating target
# @return definition list
#
def getLinkerFlags(self):
reg = re.compile("(.*?)_(?:l?a_)?LDFLAGS$")
for key in self.defines.keys():
result=reg.match(key)
if result:
ldflag = self.findRealTargetname(str(result.group(1)))
if not len(ldflag):
print "WARNING: no corresponding target for ldflag item %s \n" % str(result.group(1))
continue
self.ldflags[ldflag] = self.defines[key]
del self.defines[key]
return self.ldflags
## collect all LTLIBRARIES definitions
#
# the function store the definitions in the libraries class member keyed
# by the relating target
# @return definition list
#
def getLibraries(self):
def stripLibname(val):
reg = re.compile("(?:lib)?(.*)\.l?a$")
files = val.split()
retlist = []
for file in files:
result=reg.match(file)
if result:
retlist.append(str(result.group(1)))
return ' '.join(retlist)
reg = re.compile("(.*)(_l?a)?_(?:LT)?LIBRARIES$")
for key in self.defines.keys():
result=reg.match(key)
if result:
libtype = str(result.group(1))
if not self.libs.has_key(libtype):
self.libs[libtype] = ""
self.libs[libtype] = stripLibname(self.defines[key])
del self.defines[key]
return self.libs
def getPrograms(self):
reg = re.compile("(.*)_PROGRAMS$")
for key in self.defines.keys():
result=reg.match(key)
if result:
progtype = str(result.group(1))
if not self.progs.has_key(progtype):
self.progs[progtype] = ""
self.progs[progtype] = self.defines[key]
del self.defines[key]
return self.progs
def getData(self):
reg = re.compile("(.*)_DATA$")
for key in self.defines.keys():
result=reg.match(key)
if result:
dat = str(result.group(1))
self.data[dat] = self.defines[key]
del self.defines[key]
for name in self.data.keys():
if self.defines.has_key(name+"dir"):
self.datadirs[name] = self.defines[name+"dir"]
del self.defines[name+"dir"]
else:
del self.data[name]
return self.data
## collect all SOURCES definitions
#
# the function store the definitions in the sources class member keyed
# by the relating target
# this function should be called after getPrograms and getLibraries
# @return definition list
#
def getSources(self):
reg = re.compile("(.*?)METASOURCES$")
reg = re.compile("(.*?)_(?:l?a_)?SOURCES$")
# TODO (rh) fix relative library paths
for key in self.defines.keys():
if key.endswith('METASOURCES') and self.defines[key] == "AUTO":
del self.defines[key]
continue
result=reg.match(key)
if result:
source = self.findRealTargetname(str(result.group(1)))
if not len(source):
print "WARNING: no corresponding target for source item %s \n" % str(result.group(1))
continue
self.sources[source] = self.defines[key]
del self.defines[key]
return self.sources
def findRealTargetname(self, target):
def findInDict(dict, target):
for key in dict.keys():
targets = dict[key].split()
if targets.count(target) > 0:
return 1
return 0
if not findInDict(self.progs, target) and not findInDict(self.libs, target):
if target[:3] == "lib":
target = target[3:]
if not findInDict(self.libs, target):
target = ""
else:
target = ""
return target
def getIncludes(self):
#if we've got a dir global includes, save it in self.includes['_DIR_GLOBAL_']
if self.defines.has_key('INCLUDES'):
self.defines['_DIR_GLOBAL__INCLUDES'] = self.defines['INCLUDES']
del self.defines['INCLUDES']
reg = re.compile("(.*?)_(?:l?a_)?INCLUDES")
# TODO (rh) fix relative library pathes
for key in self.defines.keys():
result=reg.match(key)
if result:
include = self.findRealTargetname(str(result.group(1)))
if not len(include):
include = result.group(1)
self.includes[include] = self.defines[key]
del self.defines[key]
return self.includes
def convertMakeFileVariable(self, var):
var = var.strip()
if var[:2] == '$(' and var[-1:] == ')':
return var[2:-1]
else:
return var
def getHeaders(self):
#if we've got a dir global includes, save it in self.headers['_DIR_GLOBAL_']
if self.defines.has_key('HEADERS'):
self.defines['_DIR_GLOBAL__HEADERS'] = self.defines['HEADERS']
del self.defines['HEADERS']
reg = re.compile("(.*?)_(?:l?a_)?HEADERS")
# TODO (rh) fix relative library paths
for key in self.defines.keys():
result=reg.match(key)
if result:
header = self.findRealTargetname(str(result.group(1)))
if not len(header):
header = result.group(1)
self.headers[header] = self.defines[key]
del self.defines[key]
return self.headers
## return a reverse usage list of dependencies
#
# The function scannes the recent library definitions and reorganice
# the resulting list keyed by the used library
# @return dependency list
#
def getReverseLibraryDeps(self):
alist = {}
for key in self.libadds.keys():
for lib in self.libadds[key].split():
if lib in alist:
alist[str(lib)] += " " + key
else:
alist[str(lib)] = key
return alist
def printDefines(self):
print "### DEFINES:"
printDict(self.defines,' = ')
def printTargets(self):
print "### TARGETS:"
printDict(self.targets,' : ')
def printLibraryDeps(self):
print "### LIBADD:"
printDict(self.libadds,' : ')
def printLinkerFlags(self):
print "### LDFLAGS:"
printDict(self.ldflags,' : ')
def printLibraries(self):
print "### Libraries:"
printDict(self.libs,' : ')
def printSources(self):
print "### Sources:"
printDict(self.sources,' : ')
def amview():
uses = 0
libadds = 0
ldflags = 0
defines = 0
targets = 0
libs = 0
sources = 0
if len(sys.argv) == 1:
print "amtool [options] Makefile.am [Makefile.am] ..."
print "list Makefile.am content"
print "options:"
print " --uses print where a library is used"
print " --libadd print all LIBADD depenencies "
print " --ldflags print all LDFLAGS definitions"
print " --defines print all Makefile variables"
print " --targets print all Makefile targets"
print " --libs print all library definitions"
print " --sources print all source definitions"
else:
all_ams = AMFile()
for a in range(1,len(sys.argv)):
if sys.argv[a][:6] == '--uses':
uses = 1
elif sys.argv[a][:8] == '--libadd':
libadds = 1
elif sys.argv[a][:9] == '--defines':
defines = 1
elif sys.argv[a][:9] == '--targets':
targets = 1
elif sys.argv[a][:9] == '--ldflags':
ldflags = 1
elif sys.argv[a][:6] == '--libs':
libs = 1
elif sys.argv[a][:9] == '--sources':
sources = 1
if libadds or defines or targets or ldflags or libs or sources:
uses = 2
for a in range(1,len(sys.argv)):
if sys.argv[a][:2] == '--':
continue
am_file = AMFile()
if not am_file.read(sys.argv[a]):
continue
if uses == 2:
print "### " + sys.argv[a]
if defines:
am_file.printDefines()
if targets:
am_file.printTargets()
if libadds:
am_file.printLibraryDeps()
if ldflags:
am_file.printLinkerFlags()
if libs:
am_file.printLibraries()
if sources:
am_file.printSources()
all_ams.addLibraryDeps(am_file)
all_ams.addLinkerFlags(am_file)
all_ams.addSources(am_file)
all_ams.addLibraries(am_file)
if uses == 0:
all_ams.printLibraryDeps()
elif uses == 1:
a = all_ams.getReverseLibraryDeps()
printDict(a)
|