sbsv2/raptor/bin/createvmap.py
changeset 0 044383f39525
child 3 e1eecf4d390d
equal deleted inserted replaced
-1:000000000000 0:044383f39525
       
     1 #
       
     2 # Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of the License "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 # Python Script to create the vmap file for Binary Variation support in SBSv2
       
    18 
       
    19 import sys
       
    20 import os
       
    21 import re
       
    22 import subprocess
       
    23 import tempfile
       
    24 import traceback
       
    25 from optparse import OptionParser
       
    26 
       
    27 # the script will exit with 0 if there are no errors
       
    28 global exitCode
       
    29 exitCode = 0
       
    30 
       
    31 # are we running on Windows?
       
    32 onWindows = sys.platform.lower().startswith("win")
       
    33 
       
    34 # error messages go to stderr
       
    35 def error(format, *extras):
       
    36 	sys.stderr.write("createvmap: error: " + (format % extras) + "\n")
       
    37 	global exitCode
       
    38 	exitCode = 1
       
    39 
       
    40 # warning messages go to stderr
       
    41 def warning(format, *extras):
       
    42 	sys.stderr.write("createvmap: warning: " + (format % extras) + "\n")
       
    43 
       
    44 # debug messages go to stderr
       
    45 global printDebug
       
    46 #
       
    47 def debug(format, *extras):
       
    48 	if printDebug:
       
    49 		sys.stderr.write("createvmap: " + (format % extras) + "\n")
       
    50 	
       
    51 # Return a dictionary with the feature names and values from the preinclude file, by running cpp over the source
       
    52 def getVmapMacros(aPreInclude, aPreprocessedFile=None, aCPP="cpp", aDefines="", aIncludes = ""):
       
    53 
       
    54 	validmacros = {}
       
    55 	# Run the pre-processor
       
    56 	command = aCPP + " -include " + os.path.abspath(aPreInclude) + " -dU " + aDefines + aIncludes
       
    57 
       
    58 	# Feed in the file to stdin, because we must set the stdin to something
       
    59 	# other than the parent stdin anyway as that may not exist - for example
       
    60 	# when using Talon.
       
    61 	infile = open(aPreprocessedFile, "r")
       
    62 
       
    63 	if onWindows:
       
    64 		p = subprocess.Popen(command, bufsize=65535,
       
    65 					                  stdin=infile,
       
    66 					                  stdout=subprocess.PIPE,
       
    67 					                  stderr=sys.stderr,
       
    68 					                  universal_newlines=True)
       
    69 	else:
       
    70 		p = subprocess.Popen(command, bufsize=65535,
       
    71 					                  stdin=infile,
       
    72 					                  stdout=subprocess.PIPE,
       
    73 					                  stderr=sys.stderr,
       
    74 					                  close_fds=True, shell=True)
       
    75 	stream = p.stdout
       
    76 
       
    77 	# Parse the pre-processor output to look for -
       
    78 	# lines "#define NAME VALUE" and "#undef NAME"
       
    79 	defineRE = re.compile('^#define (?P<FEATURENAME>\w+)(\s+(?P<VALUE>\w+))?')
       
    80 	undefRE = re.compile('^#undef (?P<FEATURENAME>\w+)')
       
    81 
       
    82 	data = " "
       
    83 	while data:
       
    84 		data = stream.readline()
       
    85 
       
    86 		definedmacro = defineRE.match(data)
       
    87 		if definedmacro:
       
    88 			name = definedmacro.group('FEATURENAME')
       
    89 			value = definedmacro.group('VALUE')
       
    90 			if value:
       
    91 				validmacros[name] = value
       
    92 			else:
       
    93 				validmacros[name] = "defined"
       
    94 
       
    95 		else:
       
    96 			undefinedmacro = undefRE.match(data)
       
    97 			if undefinedmacro:
       
    98 				validmacros[undefinedmacro.group('FEATURENAME')] = "undefined"
       
    99 
       
   100 	if p.wait() != 0:
       
   101 		error("in command '%s'", command)
       
   102 		
       
   103 	infile.close()
       
   104 	
       
   105 	return validmacros
       
   106 
       
   107 # Extract the features from a featurelist file
       
   108 def getFeatures(aFeatureList):
       
   109 	features = set()
       
   110 	for f in aFeatureList:
       
   111 		try:
       
   112 			file = open(os.path.abspath(f),'r')
       
   113 		
       
   114 			for data in file.readlines():
       
   115 				data = data.strip()
       
   116 				features.add(data)
       
   117 		
       
   118 			file.close()
       
   119 		
       
   120 		except IOError:
       
   121 			error("Feature list file %s not found", f)
       
   122 
       
   123 	return sorted(list(features))
       
   124 	
       
   125 # Returns a dictionary of the features to be put in the vmap file
       
   126 def getVariationFeatures(aFeatureList = [] ,aPreinclude = None,aPreprocessedFile = None,aCPP = "cpp",aDefines="",aIncludes = ""):
       
   127 	
       
   128 	variation_features = {'FEATURENAME':[],'VALUE':[]}
       
   129 	macros = getVmapMacros(aPreinclude,aPreprocessedFile,aCPP,aDefines,aIncludes)
       
   130 	
       
   131 	# Co-relate the macros obtained from the pre-processor to the featurelist
       
   132 	for f in aFeatureList:
       
   133 		if f in macros:
       
   134 			variation_features['FEATURENAME'].append(f)
       
   135 			variation_features['VALUE'].append(macros[f])
       
   136 	
       
   137 	return variation_features
       
   138 
       
   139 # Write to the vmap file, with the supplied dictionary containing the features
       
   140 # The vmap path will be created if it doesn't exist
       
   141 def createVmapFile(aMacroDictionary,aOutputfile):
       
   142 	if not os.path.exists(os.path.dirname(aOutputfile)):
       
   143 		os.makedirs(os.path.dirname(aOutputfile))
       
   144 	try:
       
   145 		vmapfile = open(aOutputfile,'w')
       
   146 	except IOError:
       
   147 		error("Cannot write to " + aOutputfile)
       
   148 	i = 0
       
   149 	while i < len(aMacroDictionary['FEATURENAME']):
       
   150 		vmapfile.write(aMacroDictionary['FEATURENAME'][i]+"="+aMacroDictionary['VALUE'][i]+"\n")
       
   151 		i += 1
       
   152 	vmapfile.close()
       
   153 
       
   154 def check_exists(thing, filenames):
       
   155 	if not filenames:
       
   156 		error("No %s specified", thing)
       
   157 		return
       
   158 	
       
   159 	if not isinstance(filenames, list):
       
   160 		# we just have a single string
       
   161 		filenames = [filenames]
       
   162 		
       
   163 	for filename in filenames:
       
   164 		if not os.path.exists(filename):
       
   165 			error("The %s '%s' does not exist", thing, filename)
       
   166 		
       
   167 # Main function, creates the vmap file
       
   168 def main():
       
   169 
       
   170 	try:
       
   171 		global exitCode, printDebug
       
   172 		
       
   173 		# any exceptions make us traceback and exit
       
   174 
       
   175 		parser = OptionParser(prog = "createvmap.py")
       
   176 	
       
   177 		parser.add_option("-c","--cpploc",action="store",dest="cpplocation",help="Full path of the preprocessor")
       
   178 		parser.add_option("-d","--debug",action="store_true",default=False,dest="debug",help="Turn debug information on")
       
   179 		parser.add_option("-D","--define",action="append",dest="defines",help="Macro definition")
       
   180 		parser.add_option("-f","--featurelist",action="append",dest="featurelistfile",help="List of featureslist files")
       
   181 		parser.add_option("-o","--output",action="store",dest="outputvmapfile",help="Output VMAP file name")
       
   182 		parser.add_option("-p","--preinclude",action="store",dest="preinclude",help="Pre-include file ")
       
   183 		parser.add_option("-s","--source",action="append",dest="sourcefiles",help="List of source files")
       
   184 		parser.add_option("-u","--userinc",action="append",dest="user_include",help="User Include Folders")
       
   185 		parser.add_option("-x","--systeminc",action="append",dest="system_include",help="System Include Folders")
       
   186 
       
   187 		(options, leftover_args) = parser.parse_args(sys.argv[1:])
       
   188 
       
   189 		if leftover_args:
       
   190 			for invalids in leftover_args:
       
   191 				warning("Unknown parameter '%s'" % invalids)
       
   192 		
       
   193 		printDebug = options.debug
       
   194 		debug("Source Files     -> %s", options.sourcefiles)
       
   195 		debug("Macro defines    -> %s", options.defines)
       
   196 		debug("Features Files   -> %s", options.featurelistfile)
       
   197 		debug("Pre-Include File -> %s", options.preinclude)
       
   198 		debug("User Includes    -> %s", options.user_include)
       
   199 		debug("System Includes  -> %s", options.system_include)
       
   200 		debug("CPP Location     -> %s", options.cpplocation)
       
   201 		debug("VMAP Output name -> %s", options.outputvmapfile)
       
   202 			
       
   203 		featurelist = []
       
   204 		definelist = ""
       
   205 		user_includeslist = ""
       
   206 		system_includeslist = ""
       
   207 		includeslist = ""
       
   208 
       
   209 		# Some error checking code
       
   210 		if not options.outputvmapfile:
       
   211 			error("No output vmap file name supplied")
       
   212 	
       
   213 		# Source files must be supplied
       
   214 		check_exists("source file", options.sourcefiles)
       
   215 	
       
   216 		# A valid preinclude file must be supplied
       
   217 		check_exists("pre-include file", options.preinclude)
       
   218 	
       
   219 		# Some feature lists are required
       
   220 		check_exists("feature list", options.featurelistfile)
       
   221 	
       
   222 		# A cpp tool is required
       
   223 		check_exists("cpp tool", options.cpplocation)
       
   224 
       
   225 		# if an essential option was missing then we should stop now
       
   226 		if exitCode != 0:
       
   227 			sys.exit(exitCode)
       
   228 			
       
   229 		# macro definitions
       
   230 		if options.defines:
       
   231 			for macro in options.defines:
       
   232 				definelist += " -D" + macro.replace('__SBS__QUOTE__', '\\"')
       
   233 
       
   234 		# Note that we have to use -isystem for user includes and system
       
   235 		# includes to match what happens in the compiler. Long story.
       
   236 
       
   237 		# Add each source directory as a user-include, so that our temporary
       
   238 		# concatenated source file can find includes that were next to the
       
   239 		# original source files.
       
   240 		# Check that all the specified source files exist
       
   241 		# and collect a set of all the source directories
       
   242 		sourcedirs = set()
       
   243 		for src in options.sourcefiles:
       
   244 			sourcedirs.add(os.path.dirname(src))
       
   245 			
       
   246 		for srcdir in sourcedirs:
       
   247 			user_includeslist += " -isystem " + srcdir
       
   248 
       
   249 		# Convert the include list to a string to be passed to cpp
       
   250 		if options.user_include:
       
   251 			for userinc in options.user_include:
       
   252 				user_includeslist += " -isystem " + userinc
       
   253 		if options.system_include:
       
   254 			for sysinc in options.system_include:
       
   255 				system_includeslist += " -isystem " + sysinc
       
   256 	
       
   257 		includeslist = user_includeslist + system_includeslist
       
   258 
       
   259 		# Get a list of all the features, from all the featurelist files
       
   260 		featurelist = getFeatures(options.featurelistfile)
       
   261 
       
   262 		# concatenate the source files together into a temporary file
       
   263 		try:
       
   264 			(tempfd, tempname) = tempfile.mkstemp()
       
   265 			temp = os.fdopen(tempfd, "w")
       
   266 			for src in options.sourcefiles:
       
   267 				sfile = open(src, "r")
       
   268 				for sline in sfile:
       
   269 					temp.write(sline)
       
   270 				sfile.close()
       
   271 			temp.close()
       
   272 		except Exception,e:
       
   273 			error("Could not write source files into temporary file %s : %s" % (tempname, str(e)))
       
   274 			return 1
       
   275 		
       
   276 		debug("Temporary file name : " + tempname)
       
   277 
       
   278 		# extract the macros from the concatenated source files
       
   279 		macro_dictionary = getVariationFeatures(featurelist,
       
   280 		                                        options.preinclude,
       
   281 								                tempname,
       
   282 								                options.cpplocation,
       
   283 								                definelist,
       
   284 								                includeslist)
       
   285 		debug("Macros extracted:") 
       
   286 		for key,values in macro_dictionary.iteritems():
       
   287 			debug(key + " " + str(values))
       
   288 
       
   289 		# if there were no macros then the vmap file will be empty...
       
   290 		if not macro_dictionary['FEATURENAME']:
       
   291 			warning("No feature macros were found in the source")
       
   292 			
       
   293 		# Get rid of the temporary file
       
   294 		try:
       
   295 			os.remove(tempname)
       
   296 		except:
       
   297 			error("Could not delete temporary %s" % tempname) 
       
   298 
       
   299 		createVmapFile(macro_dictionary, options.outputvmapfile)
       
   300 		
       
   301 		# exit with 0 if OK
       
   302 		return exitCode
       
   303 
       
   304 	except Exception,ex:
       
   305 		traceback.print_exc()
       
   306 		return 1
       
   307 
       
   308 if __name__ == "__main__":
       
   309     sys.exit(main())
       
   310