#
# Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of the License "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description:
#
# Python Script to create the vmap file for Binary Variation support in SBSv2
import sys
import os
import re
import subprocess
import tempfile
import traceback
from optparse import OptionParser
# the script will exit with 0 if there are no errors
global exitCode
exitCode = 0
# are we running on Windows?
onWindows = sys.platform.lower().startswith("win")
# error messages go to stderr
def error(format, *extras):
sys.stderr.write("createvmap: error: " + (format % extras) + "\n")
global exitCode
exitCode = 1
# warning messages go to stderr
def warning(format, *extras):
sys.stderr.write("createvmap: warning: " + (format % extras) + "\n")
# debug messages go to stderr
global printDebug
#
def debug(format, *extras):
if printDebug:
sys.stderr.write("createvmap: " + (format % extras) + "\n")
# Return a dictionary with the feature names and values from the preinclude file, by running cpp over the source
def getVmapMacros(aPreInclude, aPreprocessedFile=None, aCPP="cpp", aDefines="", aIncludes = ""):
validmacros = {}
# Run the pre-processor
command = aCPP + " -include " + os.path.abspath(aPreInclude) + " -dU " + aDefines + aIncludes
# Feed in the file to stdin, because we must set the stdin to something
# other than the parent stdin anyway as that may not exist - for example
# when using Talon.
infile = open(aPreprocessedFile, "r")
if onWindows:
p = subprocess.Popen(command, bufsize=65535,
stdin=infile,
stdout=subprocess.PIPE,
stderr=sys.stderr,
universal_newlines=True)
else:
p = subprocess.Popen(command, bufsize=65535,
stdin=infile,
stdout=subprocess.PIPE,
stderr=sys.stderr,
close_fds=True, shell=True)
stream = p.stdout
# Parse the pre-processor output to look for -
# lines "#define NAME VALUE" and "#undef NAME"
defineRE = re.compile('^#define (?P<FEATURENAME>\w+)(\s+(?P<VALUE>\w+))?')
undefRE = re.compile('^#undef (?P<FEATURENAME>\w+)')
data = " "
while data:
data = stream.readline()
definedmacro = defineRE.match(data)
if definedmacro:
name = definedmacro.group('FEATURENAME')
value = definedmacro.group('VALUE')
if value:
validmacros[name] = value
else:
validmacros[name] = "defined"
else:
undefinedmacro = undefRE.match(data)
if undefinedmacro:
validmacros[undefinedmacro.group('FEATURENAME')] = "undefined"
if p.wait() != 0:
error("in command '%s'", command)
infile.close()
return validmacros
# Extract the features from a featurelist file
def getFeatures(aFeatureList):
features = set()
for f in aFeatureList:
try:
file = open(os.path.abspath(f),'r')
for data in file.readlines():
data = data.strip()
features.add(data)
file.close()
except IOError:
error("Feature list file %s not found", f)
return sorted(list(features))
# Returns a dictionary of the features to be put in the vmap file
def getVariationFeatures(aFeatureList = [] ,aPreinclude = None,aPreprocessedFile = None,aCPP = "cpp",aDefines="",aIncludes = ""):
variation_features = {'FEATURENAME':[],'VALUE':[]}
macros = getVmapMacros(aPreinclude,aPreprocessedFile,aCPP,aDefines,aIncludes)
# Co-relate the macros obtained from the pre-processor to the featurelist
for f in aFeatureList:
if f in macros:
variation_features['FEATURENAME'].append(f)
variation_features['VALUE'].append(macros[f])
return variation_features
# Write to the vmap file, with the supplied dictionary containing the features
# The vmap path will be created if it doesn't exist
def createVmapFile(aMacroDictionary,aOutputfile):
if not os.path.exists(os.path.dirname(aOutputfile)):
os.makedirs(os.path.dirname(aOutputfile))
try:
vmapfile = open(aOutputfile,'w')
except IOError:
error("Cannot write to " + aOutputfile)
i = 0
while i < len(aMacroDictionary['FEATURENAME']):
vmapfile.write(aMacroDictionary['FEATURENAME'][i]+"="+aMacroDictionary['VALUE'][i]+"\n")
i += 1
vmapfile.close()
def check_exists(thing, filenames):
if not filenames:
error("No %s specified", thing)
return
if not isinstance(filenames, list):
# we just have a single string
filenames = [filenames]
for filename in filenames:
if not os.path.exists(filename):
error("The %s '%s' does not exist", thing, filename)
# Main function, creates the vmap file
def main():
try:
global exitCode, printDebug
# any exceptions make us traceback and exit
parser = OptionParser(prog = "createvmap.py")
parser.add_option("-c","--cpploc",action="store",dest="cpplocation",help="Full path of the preprocessor")
parser.add_option("-d","--debug",action="store_true",default=False,dest="debug",help="Turn debug information on")
parser.add_option("-D","--define",action="append",dest="defines",help="Macro definition")
parser.add_option("-f","--featurelist",action="append",dest="featurelistfile",help="List of featureslist files")
parser.add_option("-o","--output",action="store",dest="outputvmapfile",help="Output VMAP file name")
parser.add_option("-p","--preinclude",action="store",dest="preinclude",help="Pre-include file ")
parser.add_option("-s","--source",action="append",dest="sourcefiles",help="List of source files")
parser.add_option("-u","--userinc",action="append",dest="user_include",help="User Include Folders")
parser.add_option("-x","--systeminc",action="append",dest="system_include",help="System Include Folders")
(options, leftover_args) = parser.parse_args(sys.argv[1:])
if leftover_args:
for invalids in leftover_args:
warning("Unknown parameter '%s'" % invalids)
printDebug = options.debug
debug("Source Files -> %s", options.sourcefiles)
debug("Macro defines -> %s", options.defines)
debug("Features Files -> %s", options.featurelistfile)
debug("Pre-Include File -> %s", options.preinclude)
debug("User Includes -> %s", options.user_include)
debug("System Includes -> %s", options.system_include)
debug("CPP Location -> %s", options.cpplocation)
debug("VMAP Output name -> %s", options.outputvmapfile)
featurelist = []
definelist = ""
user_includeslist = ""
system_includeslist = ""
includeslist = ""
# Some error checking code
if not options.outputvmapfile:
error("No output vmap file name supplied")
# Source files must be supplied
check_exists("source file", options.sourcefiles)
# A valid preinclude file must be supplied
check_exists("pre-include file", options.preinclude)
# Some feature lists are required
check_exists("feature list", options.featurelistfile)
# A cpp tool is required
check_exists("cpp tool", options.cpplocation)
# if an essential option was missing then we should stop now
if exitCode != 0:
sys.exit(exitCode)
# macro definitions
if options.defines:
for macro in options.defines:
definelist += " -D" + macro.replace('__SBS__QUOTE__', '\\"')
# Note that we have to use -isystem for user includes and system
# includes to match what happens in the compiler. Long story.
# Add each source directory as a user-include, so that our temporary
# concatenated source file can find includes that were next to the
# original source files.
# Check that all the specified source files exist
# and collect a set of all the source directories
sourcedirs = set()
for src in options.sourcefiles:
sourcedirs.add(os.path.dirname(src))
for srcdir in sourcedirs:
user_includeslist += " -isystem " + srcdir
# Convert the include list to a string to be passed to cpp
if options.user_include:
for userinc in options.user_include:
user_includeslist += " -isystem " + userinc
if options.system_include:
for sysinc in options.system_include:
system_includeslist += " -isystem " + sysinc
includeslist = user_includeslist + system_includeslist
# Get a list of all the features, from all the featurelist files
featurelist = getFeatures(options.featurelistfile)
# concatenate the source files together into a temporary file
try:
(tempfd, tempname) = tempfile.mkstemp()
temp = os.fdopen(tempfd, "w")
for src in options.sourcefiles:
sfile = open(src, "r")
for sline in sfile:
temp.write(sline)
sfile.close()
temp.close()
except Exception,e:
error("Could not write source files into temporary file %s : %s" % (tempname, str(e)))
return 1
debug("Temporary file name : " + tempname)
# extract the macros from the concatenated source files
macro_dictionary = getVariationFeatures(featurelist,
options.preinclude,
tempname,
options.cpplocation,
definelist,
includeslist)
debug("Macros extracted:")
for key,values in macro_dictionary.iteritems():
debug(key + " " + str(values))
# if there were no macros then the vmap file will be empty...
if not macro_dictionary['FEATURENAME']:
warning("No feature macros were found in the source")
# Get rid of the temporary file
try:
os.remove(tempname)
except:
error("Could not delete temporary %s" % tempname)
createVmapFile(macro_dictionary, options.outputvmapfile)
# exit with 0 if OK
return exitCode
except Exception,ex:
traceback.print_exc()
return 1
if __name__ == "__main__":
sys.exit(main())