""" Python SWIG wrapper creation script Windows/LINUX/OSX platform

	--------------------------------------------------------------------------
	File:			buildSwigPython.py

	Overview: 		Creates SWIG Python C++ Script Bridge wrapper code. This
					script is called by build-swig-wrapper-classes.py in turn.
					
	Environment:	OS:			Windows Vista or newer, LINUX, OSX.
					IDE: 	    Visual Studio 2013 Plugin Python Tools (PTVS)
					Script:		Python 2.6/2.7.5 x64
					Other:		SWIG 2.0.11

	Gotchas:		Python debug complied pythonXX_d.lib is required for SWIG
					to build correct LLDBWrapperPython.cpp in order for Visual
					Studio to compile successfully. The release version of the 
					Python lib will not work. 
					LLDB (dir) CMakeLists.txt uses windows environmental
					variables $PYTHON_INCLUDE and $PYTHON_LIB to locate
					Python files required for the build.

	Copyright:		None.
	--------------------------------------------------------------------------
	
"""

# Python modules:
import os			# Provide directory and file handling, determine OS information
import sys			# sys.executable
import time			# Time access and conversions
import subprocess 	# Call external programs
import shutil		# File handling

# Third party modules:

# In-house modules:
import utilsOsType	# Determine the OS type this script is running on
import utilsDebug 	# Debug Python scripts

# User facing text:
strMsgLldbDisablePythonEnv = "Python build aborted as LLDB_DISABLE_PYTHON \
environmental variable is defined";
strMsgLldbDisableGccEnv = "Python build aborted as GCC_PREPROCESSOR_DEFINITIONS \
environmental variable is defined";
strMsgHdrFiles = "Header files are:";
strMsgIFaceFiles = "SWIG interface files are";
strErrMsgProgFail = "Program failure: ";     
strMsgFileNewrSwigOpFile = "\'%s\' is newer than \'%s\'\nSWIG file will need to be re-built";
strMsgFileNotExist = "\'%s\' could not be found\nSWIG file will need to be re-built";
strErrMsgOsTypeUnknown = "Unable to determine current OS type";
strMsgNotNeedUpdate = "Everything is up-to-date";
strMsgSwigNeedRebuild = "SWIG needs to be re-run";
strErrMsgSwigParamsMissing = "This script was not passed either '--swigExePath \
or the '--swigExeName' argument. Both are required.";
strMsgSwigExecute = "SWIG executing the following:\n\'%s'";
strErrMsgSwigExecute = "SWIG failed: %s";
strErrMsgPythonExecute = "Python script '%s' failed: %s";
strMsgSwigNoGenDep = "SWIG ran with no generated dependencies, script exit early";
strMsgSwigGenDep = "SWIG ran and generated dependencies, script exit early, deleted '%s'";
strErrMsgFrameWkPyDirNotExist = "Unable to find the LLDB. Framework directory is '%s'";
strMsgFoundLldbFrameWkDir = "Found '%s'";
strErrMsgModifyPythonLldbPyFileNotFound = "Unable to find '%s' in '%s'";

#++---------------------------------------------------------------------------
# Details:	Retrieve the list of hard coded lldb header file names and
#			put in the program's dictArgs map container. Make paths compatible
#			with the current OS. 
#			Note this does not necessarily match the content of those 
#			directories. The resultant header string is inserted into the 
#			dictionary vDictArgs key "--headerFiles".
# Args:		vDictArgs	- (RW) Program input parameters.
# Returns:	Bool		- True = success, False = failure.
# Throws:	None.
#--
def get_header_files( vDictArgs ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script get_header_files()" );
	listHeaderFiles = [ "/include/lldb/API/lldb.h", # .sh has /include/lldb/lldb.h 21/11/2013
						"/include/lldb/lldb-defines.h",
						"/include/lldb/lldb-enumerations.h",
						"/include/lldb/lldb-forward.h",
						"/include/lldb/lldb-forward-rtti.h",
						"/include/lldb/lldb-types.h",
						"/include/lldb/API/SBAddress.h",
						"/include/lldb/API/SBBlock.h",
						"/include/lldb/API/SBBreakpoint.h",
						"/include/lldb/API/SBBreakpointLocation.h",
						"/include/lldb/API/SBBroadcaster.h",
						"/include/lldb/API/SBCommandInterpreter.h",
						"/include/lldb/API/SBCommandReturnObject.h",
						"/include/lldb/API/SBCommunication.h",
						"/include/lldb/API/SBCompileUnit.h",
						"/include/lldb/API/SBData.h",
						"/include/lldb/API/SBDebugger.h",
						"/include/lldb/API/SBError.h",
						"/include/lldb/API/SBEvent.h",
						"/include/lldb/API/SBExpressionOptions.h",
						"/include/lldb/API/SBFileSpec.h",
						"/include/lldb/API/SBFrame.h",
						"/include/lldb/API/SBFunction.h",
						"/include/lldb/API/SBHostOS.h",
						"/include/lldb/API/SBInputReader.h",
						"/include/lldb/API/SBInstruction.h",
						"/include/lldb/API/SBInstructionList.h",
						"/include/lldb/API/SBLineEntry.h",
						"/include/lldb/API/SBListener.h",
						"/include/lldb/API/SBModule.h",
						"/include/lldb/API/SBModuleSpec.h",
						"/include/lldb/API/SBProcess.h",
						"/include/lldb/API/SBSourceManager.h",
						"/include/lldb/API/SBStream.h",
						"/include/lldb/API/SBStringList.h",
						"/include/lldb/API/SBSymbol.h",
						"/include/lldb/API/SBSymbolContext.h",
						"/include/lldb/API/SBSymbolContextList.h",
						"/include/lldb/API/SBTarget.h",
						"/include/lldb/API/SBThread.h",
						"/include/lldb/API/SBThreadCollection.h",
						"/include/lldb/API/SBType.h",
						"/include/lldb/API/SBTypeCategory.h",
						"/include/lldb/API/SBTypeFilter.h",
						"/include/lldb/API/SBTypeFormat.h",
						"/include/lldb/API/SBTypeNameSpecifier.h",
						"/include/lldb/API/SBTypeSummary.h",
						"/include/lldb/API/SBTypeSynthetic.h",
						"/include/lldb/API/SBValue.h",
						"/include/lldb/API/SBValueList.h",
						"/include/lldb/API/SBWatchpoint.h" ];
	bDebug = vDictArgs.has_key( "-d" );
	strRt = vDictArgs[ "--srcRoot" ];
	strRt = os.path.normcase( strRt );
	
	strHeaderFiles = "";
	for strHdr in listHeaderFiles[ 0: len( listHeaderFiles ) ]:
		strHdr = os.path.normcase( strHdr );
		strHeaderFiles += " %s%s" % (strRt, strHdr);
	
	if bDebug:
		print strMsgHdrFiles;
 		print strHeaderFiles;
		
	vDictArgs[ "--headerFiles" ] = strHeaderFiles;
	
	return True;

#++---------------------------------------------------------------------------
# Details:	Retrieve the list of hard coded lldb SWIG interface file names and
#			put in the program's dictArgs map container. Make paths compatible
#			with the current OS. 
#			Note this does not necessarily match the content of those 
#			directories. The resultant interface string is inserted into the 
#			dictionary vDictArgs key "--ifaceFiles".
# Args:		vDictArgs	- (RW) Program input parameters.
# Returns:	Bool		- True = success, False = failure.
# Throws:	None.
#--
def get_interface_files( vDictArgs ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script get_interface_files()" );
	listIFaceFiles = [ 	"/scripts/Python/interface/SBAddress.i",
						"/scripts/Python/interface/SBBlock.i",
						"/scripts/Python/interface/SBBreakpoint.i",
						"/scripts/Python/interface/SBBreakpointLocation.i",
						"/scripts/Python/interface/SBBroadcaster.i",
						"/scripts/Python/interface/SBCommandInterpreter.i",
						"/scripts/Python/interface/SBCommandReturnObject.i",
						"/scripts/Python/interface/SBCommunication.i",
						"/scripts/Python/interface/SBCompileUnit.i",
						"/scripts/Python/interface/SBData.i",
						"/scripts/Python/interface/SBDebugger.i",
						"/scripts/Python/interface/SBDeclaration.i",
						"/scripts/Python/interface/SBError.i",
						"/scripts/Python/interface/SBEvent.i",
						"/scripts/Python/interface/SBExpressionOptions.i",
						"/scripts/Python/interface/SBFileSpec.i",
						"/scripts/Python/interface/SBFrame.i",
						"/scripts/Python/interface/SBFunction.i",
						"/scripts/Python/interface/SBHostOS.i",
						"/scripts/Python/interface/SBInputReader.i",
						"/scripts/Python/interface/SBInstruction.i",
						"/scripts/Python/interface/SBInstructionList.i",
						"/scripts/Python/interface/SBLineEntry.i",
						"/scripts/Python/interface/SBListener.i",
						"/scripts/Python/interface/SBModule.i",
						"/scripts/Python/interface/SBModuleSpec.i",
						"/scripts/Python/interface/SBProcess.i",
						"/scripts/Python/interface/SBSourceManager.i",
						"/scripts/Python/interface/SBStream.i",
						"/scripts/Python/interface/SBStringList.i",
						"/scripts/Python/interface/SBSymbol.i",
						"/scripts/Python/interface/SBSymbolContext.i",
						"/scripts/Python/interface/SBTarget.i",
						"/scripts/Python/interface/SBThread.i",
						"/scripts/Python/interface/SBThreadCollection.i",
						"/scripts/Python/interface/SBType.i",
						"/scripts/Python/interface/SBTypeCategory.i",
						"/scripts/Python/interface/SBTypeFilter.i",
						"/scripts/Python/interface/SBTypeFormat.i",
						"/scripts/Python/interface/SBTypeNameSpecifier.i",
						"/scripts/Python/interface/SBTypeSummary.i",
						"/scripts/Python/interface/SBTypeSynthetic.i",
						"/scripts/Python/interface/SBValue.i",
						"/scripts/Python/interface/SBValueList.i",
						"/scripts/Python/interface/SBWatchpoint.i" ];	
	bDebug = vDictArgs.has_key( "-d" );
	strRt = vDictArgs[ "--srcRoot" ];
	strRt = os.path.normcase( strRt );
	
	strInterfaceFiles = "";
	for strIFace in listIFaceFiles[ 0: len( listIFaceFiles ) ]:
		strIFace = os.path.normcase( strIFace );
		strInterfaceFiles += " %s%s" % (strRt, strIFace);
	
	if bDebug:
		print strMsgIFaceFiles;
		print strInterfaceFiles;
	
	vDictArgs[ "--ifaceFiles" ] = strInterfaceFiles;
		
	return True;

#++---------------------------------------------------------------------------
# Details:	Compare which file is newer.
# Args:		vFile1	- (R) File name path.
#			vFile2 	- (R) File name path.
# Returns:	Int	- 0 = both not exist, 1 = file 1 newer, 2 = file 2 newer,
#			3 = file 1 not exist.
# Throws:	None.
#--
def which_file_is_newer( vFile1, vFile2 ):
	bF1 = os.path.exists( vFile1 );
	bF2	= os.path.exists( vFile2 );
	if bF1 == False and bF2 == False:
		return 0; # Both files not exist
	if bF1 == False:
		return 3; # File 1 not exist
	if bF2 == False:
		return 1; # File 1 is newer / file 2 not exist
	f1Stamp = os.path.getmtime( vFile1 );
	f2Stamp = os.path.getmtime( vFile2 );
	if f1Stamp > f2Stamp:
		return 1; # File 1 is newer 
		
	return 2; # File 2 is newer than file 1 
		
#++---------------------------------------------------------------------------
# Details:	Determine whether the specified file exists.
# Args:		vDictArgs			- (R) Program input parameters.
#			vstrFileNamePath	- (R) Check this file exists.
# Returns:	Bool	- True = Files exists, false = not found.
# Throws:	None.
#--
def check_file_exists( vDictArgs, vstrFileNamePath ):
	bExists = False;
	bDebug = vDictArgs.has_key( "-d" );
	
	if os.path.exists( vstrFileNamePath ):
		bExists = True;
	elif bDebug:
		print strMsgFileNotExist % vstrFileNamePath;
	
	return bExists;

#++---------------------------------------------------------------------------
# Details:	Determine whether the specified file is newer than the 
#			LLDBWrapPython.cpp file.
# Args:		vDictArgs				- (R) Program input parameters.
#			vstrSwigOpFileNamePath	- (R) LLDBWrapPython.cpp file.
#			vstrFileNamePath		- (R) Specific file.
# Returns:	Bool	- True = SWIG update required, false = no update required.
# Throws:	None.
#--
def check_newer_file( vDictArgs, vstrSwigOpFileNamePath, vstrFileNamePath ):
	bNeedUpdate = False;
	bDebug = vDictArgs.has_key( "-d" );
	
	strMsg = "";
	nResult = which_file_is_newer( vstrFileNamePath, vstrSwigOpFileNamePath );
	if nResult == 1:
		strMsg = strMsgFileNewrSwigOpFile % (vstrFileNamePath, 
											 vstrSwigOpFileNamePath);
		bNeedUpdate = True;
	elif nResult == 3:
		strMsg = strMsgFileNotExist % vstrFileNamePath;
		bNeedUpdate = True;
	
	if bNeedUpdate and bDebug:
		print strMsg;
	
	return bNeedUpdate;

#++---------------------------------------------------------------------------
# Details:	Determine whether the any files in the list are newer than the 
#			LLDBWrapPython.cpp file.
# Args:		vDictArgs				- (R) Program input parameters.
#			vstrSwigOpFileNamePath	- (R) LLDBWrapPython.cpp file.
#			vstrFiles				- (R) Multi string file names ' ' delimiter.
# Returns:	Bool	- True = SWIG update required, false = no update required.
# Throws:	None.
#--
def check_newer_files( vDictArgs, vstrSwigOpFileNamePath, vstrFiles ):
	bNeedUpdate = False;
	 
	listFiles = vstrFiles.split();
	for strFile in listFiles:
		if check_newer_file( vDictArgs, vstrSwigOpFileNamePath, strFile ):
			bNeedUpdate = True;
			break;
			
	return bNeedUpdate;

#++---------------------------------------------------------------------------
# Details:	Retrieve the directory path for Python's dist_packages/
#			site_package folder on a Windows platform.
# Args:		vDictArgs	- (R) Program input parameters.
# Returns:	Bool - True = function success, False = failure.
#			Str	- Python Framework directory path.
#			strErrMsg - Error description on task failure.
# Throws:	None.
#--
def get_framework_python_dir_windows( vDictArgs ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script get_framework_python_dir_windows()" );
	bOk = True;
	strWkDir = "";
	strErrMsg = "";
	 
	# We are being built by LLVM, so use the PYTHON_INSTALL_DIR argument,
	# and append the python version directory to the end of it.  Depending 
	# on the system other stuff may need to be put here as well.
	from distutils.sysconfig import get_python_lib;
	strPythonInstallDir = "";
	bHaveArgPrefix = vDictArgs.has_key( "--prefix" );
	if bHaveArgPrefix: 
		strPythonInstallDir = vDictArgs[ "--prefix" ];
	if strPythonInstallDir.__len__() != 0:
		strWkDir = get_python_lib( True, False, strPythonInstallDir );
	else:
		strWkDir = get_python_lib( True, False );
	strWkDir += "/lldb";
	strWkDir = os.path.normcase( strWkDir );
	
	return (bOk, strWkDir, strErrMsg);

#++---------------------------------------------------------------------------
# Details:	Retrieve the directory path for Python's dist_packages/
#			site_package folder on a UNIX style platform.
# Args:		vDictArgs	- (R) Program input parameters.
# Returns:	Bool - True = function success, False = failure.
#			Str	- Python Framework directory path.
#			strErrMsg - Error description on task failure.
# Throws:	None.
#--
def get_framework_python_dir_other_platforms( vDictArgs ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script get_framework_python_dir_other_platform()" );
	bOk = True;
	strWkDir = "";
	strErrMsg = "";
	bDbg = vDictArgs.has_key( "-d" );
	
	bMakeFileCalled = vDictArgs.has_key( "-m" );
	if bMakeFileCalled:
		dbg.dump_text( "Built by LLVM" );
		return get_framework_python_dir_windows( vDictArgs );
	else:
		dbg.dump_text( "Built by XCode" );
		# We are being built by XCode, so all the lldb Python files can go
		# into the LLDB.framework/Resources/Python subdirectory.
		strWkDir = vDictArgs[ "--targetDir" ];
		strWkDir += "/LLDB.framework";
		if os.path.exists( strWkDir ):
			if bDbg:
				print strMsgFoundLldbFrameWkDir % strWkDir;
			strWkDir += "/Resources/Python/lldb";
			strWkDir = os.path.normcase( strWkDir );
		else:
			bOk = False;
			strErrMsg = strErrMsgFrameWkPyDirNotExist % strWkDir;	
	
	return (bOk, strWkDir, strErrMsg);

#++---------------------------------------------------------------------------
# Details:	Retrieve the directory path for Python's dist_packages/
#			site_package folder depending on the type of OS platform being 
#			used.
# Args:		vDictArgs	- (R) Program input parameters.
# Returns:	Bool - True = function success, False = failure.
#			Str	- Python Framework directory path.
#			strErrMsg - Error description on task failure.
# Throws:	None.
#--
def get_framework_python_dir( vDictArgs ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script get_framework_python_dir()" );
	bOk = True;
	strWkDir = "";
	strErrMsg = "";
	 
	eOSType = utilsOsType.determine_os_type();
	if eOSType == utilsOsType.EnumOsType.Unknown:
		bOk = False;
		strErrMsg = strErrMsgOsTypeUnknown;
	elif eOSType == utilsOsType.EnumOsType.Windows:
		bOk, strWkDir, strErrMsg = get_framework_python_dir_windows( vDictArgs );
	else:
		bOk, strWkDir, strErrMsg = get_framework_python_dir_other_platforms( vDictArgs );
			
	return (bOk, strWkDir, strErrMsg);

#++---------------------------------------------------------------------------
# Details:	Retrieve the configuration build path if present and valid (using
#			parameter --cfgBlddir or copy the Python Framework directory.
# Args:		vDictArgs				- (R) Program input parameters.
#			vstrFrameworkPythonDir	- (R) Python framework directory.
# Returns:	Bool - True = function success, False = failure.
#			Str	- Config directory path.
#			strErrMsg - Error description on task failure.
# Throws:	None.
#--
def get_config_build_dir( vDictArgs, vstrFrameworkPythonDir ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script get_config_build_dir()" );
	bOk = True;
	strErrMsg = "";
	
	strConfigBldDir = "";
	bHaveConfigBldDir = vDictArgs.has_key( "--cfgBldDir" );
	if bHaveConfigBldDir:
		strConfigBldDir = vDictArgs[ "--cfgBldDir" ];
	if (bHaveConfigBldDir == False) or (strConfigBldDir.__len__() == 0):
		strConfigBldDir = vstrFrameworkPythonDir;
	
	return (bOk, strConfigBldDir, strErrMsg);

#++---------------------------------------------------------------------------
# Details:	Do a SWIG code rebuild. Any number returned by SWIG which is not
#			zero is treated as an error. The generate dependencies flag decides
#			how SWIG is rebuilt and if set false will cause the script to exit
#			immediately with the exit status + 200 if status is not zero. 
# Args:		vDictArgs			- (R) Program input parameters.
#			vstrSwigDepFile		- (R) SWIG dependency file.
#			vstrCfgBldDir		- (R) Configuration build directory.
#			vstrSwigOpFile		- (R) SWIG output file.
#			vstrSwigIpFile		- (R) SWIG input file.
# Returns:	Bool 		- True = function success, False = failure.
#			strMsg 		- Error or status message.
#			nExitResult	- Exit result of SWIG executable.
#						- 0 = Success.
#						- 1 = Success, exit this script and parent script.
#						- +200 = A SWIG error status result.
# Throws:	None.
#--
def do_swig_rebuild( vDictArgs, vstrSwigDepFile, vstrCfgBldDir, 
					 vstrSwigOpFile, vstrSwigIpFile ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script do_swig_rebuild()" );
	bOk = True;
	strMsg = "";
	bDbg = vDictArgs.has_key( "-d" );
	bGenDependencies = vDictArgs.has_key( "-M" );
	strSwigExePath = vDictArgs[ "--swigExePath" ];
	strSwigExeName = vDictArgs[ "--swigExeName" ];
	strSrcRoot = vDictArgs[ "--srcRoot" ];
	
	# Build SWIG path to executable
	if strSwigExePath != "":
		strSwig = "%s/%s" % (strSwigExePath, strSwigExeName);
		strSwig = os.path.normcase( strSwig );
	else:
		strSwig = strSwigExeName;
	
	strCfg = vstrCfgBldDir;
	strOp = vstrSwigOpFile;
	strIp = vstrSwigIpFile;
	strSi = os.path.normcase( "./." );
	strRoot = strSrcRoot + "/include";
	strRoot = os.path.normcase( strRoot );
	strDep = "";
	if bGenDependencies:
		strDep = vstrSwigDepFile + ".tmp";
	
	# Build the SWIG args list
	strCmd = "%s " % strSwig;
	strCmd += "-c++ ";
	strCmd += "-shadow ";
	strCmd += "-python ";
	strCmd += "-threads ";
	strCmd += "-I\"%s\" " % strRoot;
	strCmd += "-I\"%s\" " % strSi;
	strCmd += "-D__STDC_LIMIT_MACROS ";
	strCmd += "-D__STDC_CONSTANT_MACROS ";
	if bGenDependencies:
		strCmd += "-MMD -MF \"%s\" " % strDep;
	strCmd += "-outdir \"%s\" " % strCfg;
	strCmd += "-o \"%s\" " % strOp;
	strCmd += "\"%s\" " % strIp;
	if bDbg:
		print strMsgSwigExecute % strCmd;

	# Execute SWIG
	process = subprocess.Popen( strCmd, stdout=subprocess.PIPE, 
								stderr=subprocess.PIPE, shell=True );
	# Wait for SWIG process to terminate
	strStdOut, strStdErr = process.communicate();
	nResult = process.returncode;
	if nResult != 0:
		bOk = False;
		nResult += 200;
		strMsg = strErrMsgSwigExecute % strStdErr; 
	else:
		if bDbg and (strStdOut.__len__() != 0):
			strMsg = strStdOut;
	
	if bGenDependencies:
		if bOk:
			if os.path.exists( strDep ):
				shutil.move( strDep, vstrSwigDepFile );
		else:
			os.remove( strDep ); 
			nResult = 1; # Exit this script and parent script
			if bDbg:
				strMsg = strMsgSwigGenDep % strDep;
	else:
		strMsg = strMsgSwigNoGenDep + strMsg;
		
	return bOk, strMsg, nResult;

#++---------------------------------------------------------------------------
# Details:	Execute another Python script from this script in a separate 
#			process. No data is passed back to the caller script. It is 
#			assumed should any exit result be returned that -ve numbers are
#			error conditions. A zero or +ve numbers mean ok/warning/status.
# Args:		vDictArgs	- (R) Program input parameters.
#			vstrArgs	- (R) Space separated parameters passed to python.
# Returns:	Bool - True = function success, False = failure.
#			strMsg - Error or status message.
# Throws:	None.
#--
def run_python_script( vDictArgs, vstrArgs ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script run_python_script()" );
	bOk = True;
	strMsg = "";
	bDbg = vDictArgs.has_key( "-d" );
	
	strPy = "%s %s" % (sys.executable, vstrArgs);
	process = subprocess.Popen( strPy, shell=True );
	strStdOut, strStdErr = process.communicate();
	nResult = process.returncode;
	if nResult < 0:
		bOk = False;
		strErr = strStdErr;
		if strErr == None:
			strErr = "No error given";
		strMsg = strErrMsgPythonExecute % (vstrArgs, strErr); 
	else:
		if bDbg:
			strOut = strStdOut;
			if strOut == None:
				strOut = "No status given";
			strMsg = strOut;
				
	return bOk, strMsg;
	
#++---------------------------------------------------------------------------
# Details:	Implement the iterator protocol and/or eq/ne operators for some 
#			lldb objects.
# 			Append global variable to lldb Python module.
# 			And initialize the lldb debugger subsystem.
# Args:		vDictArgs		- (R) Program input parameters.
#			vstrCfgBldDir	- (R) Configuration build directory.
# Returns:	Bool - True = function success, False = failure.
#			strMsg - Error or status message.
# Throws:	None.
#--
def do_modify_python_lldb( vDictArgs, vstrCfgBldDir ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script do_modify_python_lldb()" );
	bOk = True;
	strMsg = "";
	bDbg = vDictArgs.has_key( "-d" );
	strCwd = vDictArgs[ "--srcRoot" ]; # /llvm/tools/lldb
	strCwd += "/scripts/Python";
	strPyScript = "modify-python-lldb.py";
	strPath = "%s/%s" % (strCwd, strPyScript);
	strPath = os.path.normcase( strPath );
	
	bOk = os.path.exists( strPath );
	if not bOk:
		strMsg = strErrMsgModifyPythonLldbPyFileNotFound % (strPyScript, strPath);
		return bOk, strMsg;
		
	strPyArgs = "%s %s" % (strPath, vstrCfgBldDir);
	bOk, strMsg = run_python_script( vDictArgs, strPyArgs );
	
	return bOk, strMsg;

#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------

""" Details: Program main entry point fn. Called by another Python script.
	
	--------------------------------------------------------------------------
	Details: This script is to be called by another Python script. It is not
			 intended to be called directly i.e from the command line.
			 If environmental variable "LLDB_DISABLE_PYTHON" is defined/exists 
			 it will cause the script to end early creating nothing.
			 If environmental variable "GCC_PREPROCESSOR_DEFINITIONS" is  
			 defined/exists it will cause the script to end early creating 
			 nothing.
	Args:	vDictArgs	- (R) Map of parameter names to values. Used to for the
							  the SWIG required parameters to create code. Note
							  this container does get amended with more data.
			-d (optional)	Determines whether or not this script 
							outputs additional information when running.
			-m (optional) 	Specify called from Makefile system. If given locate
							the LLDBWrapPython.cpp in --srcRoot/source folder 
							else in the	--targetDir folder.
			-M (optional) 	Specify want SWIG to generate a dependency file.
			--srcRoot		The root of the lldb source tree.
			--targetDir 	Where the lldb framework/shared library gets put.
			--cfgBldDir 	Where the buildSwigPythonLLDB.py program will 
			(optional)		put the lldb.py file it generated from running 
							SWIG.
			--prefix  		Is the root directory used to determine where 
			(optional)		third-party modules for scripting languages should 
							be installed. Where non-Darwin systems want to put 
							the .py and .so files so that Python can find them 
							automatically. Python install directory.
			--swigExePath	File path the SWIG executable. (Determined and 
							passed by buildSwigWrapperClasses.py to here)
			--swigExeName	The file name of the SWIG executable. (Determined  
							and passed by buildSwigWrapperClasses.py to 
							here)
	Results:	0 		Success
				1		Success, generated dependencies removed 
						LLDBWrapPython.cpp.d.
				-100+	Error from this script to the caller script.
				-100	Error program failure with optional message.
				-200+	- 200 +- the SWIG exit result.
		
	--------------------------------------------------------------------------
							
"""
def main( vDictArgs ):
	dbg = utilsDebug.CDebugFnVerbose( "Python script main()" );
	bOk = True;
	strMsg = "";
	strErrMsgProgFail = "";
	
	if not( vDictArgs.has_key( "--swigExePath" ) and vDictArgs.has_key( "--swigExeName" ) ):
		strErrMsgProgFail += strErrMsgSwigParamsMissing;
		return (-100, strErrMsgProgFail );	
	
	bDebug = vDictArgs.has_key( "-d" );
	
	strSwigDepFile = "";
	strSwigDepOptions = "";
	bGenDependencies = vDictArgs.has_key( "-M" );
	if bGenDependencies:
		strSwigDepFile = vDictArgs[ "--targetDir" ] + "/LLDBWrapPython.cpp.d";
		strSwigDepOptions = "-MMD -MF \"%s.tmp\"" % strSwigDepFile;
		strSwigDepFile = os.path.normcase( strSwigDepFile );
		strSwigDepOptions = os.path.normcase( strSwigDepOptions );
		
	bMakeFileCalled = vDictArgs.has_key( "-m" );			
	strSwigOutputFile = ""
	if bMakeFileCalled:
		strSwigOutputFile = vDictArgs[ "--targetDir" ] + "/LLDBWrapPython.cpp";
	else:
		strSwigOutputFile = vDictArgs[ "--srcRoot" ] + "/source/LLDBWrapPython.cpp";
	strSwigOutputFile = os.path.normcase( strSwigOutputFile );
	
	strRt = vDictArgs[ "--srcRoot" ];
	strSwigInputFile = strRt + "/scripts/lldb.swig";
	strSwigPythonExtensions = strRt + "/scripts/Python/python-extensions.swig";
	strSwigPythonWrapper = strRt + "/scripts/Python/python-wrapper.swig";
	strSwigPythonTypemaps = strRt + "/scripts/Python/python-typemaps.swig";
	strSwigPythonSwigsafecast = strRt + "/scripts/Python/python-swigsafecast.swig";
	strSwigInputFile = os.path.normcase( strSwigInputFile );
	strSwigPythonExtensions = os.path.normcase( strSwigPythonExtensions );
	strSwigPythonWrapper = os.path.normcase( strSwigPythonWrapper );
	strSwigPythonTypemaps = os.path.normcase( strSwigPythonTypemaps );
	strSwigPythonSwigsafecast = os.path.normcase( strSwigPythonSwigsafecast );

	strEnvVarLLDBDisablePython = os.getenv( "LLDB_DISABLE_PYTHON", None );
	# We don't want Python for this build, but touch the output file so we 
	# don't have to conditionalize the build on this as well.
    # Note, at present iOS doesn't have Python, so if you're building for 
    # iOS be sure to set LLDB_DISABLE_PYTHON to 1.
	if (strEnvVarLLDBDisablePython != None) and \
	   (strEnvVarLLDBDisablePython == "1"):
		os.remove( strSwigOutputFile );
		open( strSwigOutputFile, 'w' ).close(); # Touch the file
		if bDebug:
			strMsg = strMsgLldbDisablePython;
		return (0, strMsg );
		
	# If this project is being built with LLDB_DISABLE_PYTHON defined,
	# don't bother generating Python swig bindings -- we don't have
	# Python available.
	strEnvVarGccPreprocessDefs = os.getenv( "GCC_PREPROCESSOR_DEFINITIONS", 
											None );
	if (strEnvVarGccPreprocessDefs != None) or \
	   (strEnvVarLLDBDisablePython != None):
		os.remove( strSwigOutputFile );
		open( strSwigOutputFile, 'w' ).close(); # Touch the file
		if bDebug:
			strMsg = strMsgLldbDisableGccEnv;
		return (0, strMsg);
		
	bOk = bOk and get_header_files( vDictArgs );
	bOk = bOk and get_interface_files( vDictArgs );
	
	strFrameworkPythonDir = "";
	if bOk: 
		bNeedUpdate = (check_file_exists( vDictArgs, strSwigOutputFile ) == False);
		dbg.dump_object( "check_file_exists strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		if bNeedUpdate == False:
			bNeedUpdate = check_newer_files( vDictArgs, strSwigOutputFile, vDictArgs[ "--headerFiles" ] );
			dbg.dump_object( "check_newer_files header files than strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		if bNeedUpdate == False:
			bNeedUpdate = check_newer_files( vDictArgs, strSwigOutputFile, vDictArgs[ "--ifaceFiles" ] );
			dbg.dump_object( "check_newer_files iface files than strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		if bNeedUpdate == False:
			bNeedUpdate = check_newer_file( vDictArgs, strSwigOutputFile, strSwigInputFile );
			dbg.dump_object( "check_newer_files strSwigInputFile than strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		if bNeedUpdate == False:
			bNeedUpdate = check_newer_file( vDictArgs, strSwigOutputFile, strSwigPythonExtensions );
			dbg.dump_object( "check_newer_files strSwigPythonExtensions than strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		if bNeedUpdate == False:
			bNeedUpdate = check_newer_file( vDictArgs, strSwigOutputFile, strSwigPythonWrapper );
			dbg.dump_object( "check_newer_files strSwigPythonWrapper than strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		if bNeedUpdate == False:
			bNeedUpdate = check_newer_file( vDictArgs, strSwigOutputFile, strSwigPythonTypemaps );
			dbg.dump_object( "check_newer_files strSwigPythonTypemaps than strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		if bNeedUpdate == False:
			bNeedUpdate = check_newer_file( vDictArgs, strSwigOutputFile, strSwigPythonSwigsafecast );
			dbg.dump_object( "check_newer_files strSwigPythonSwigsafecast than strSwigOutputFile, bNeedUpdate =", bNeedUpdate);
		
		# Determine where to put the files
		bOk, strFrameworkPythonDir, strMsg = get_framework_python_dir( vDictArgs );
		
	if bOk:
		bOk, strCfgBldDir, strMsg = get_config_build_dir( vDictArgs, strFrameworkPythonDir );
	
	if bOk and (bNeedUpdate == False):
		strDllPath = strFrameworkPythonDir + "/_lldb.so";
		strDllPath = os.path.normcase( strDllPath );
		bSymbolicLink = check_file_exists( vDictArgs, strDllPath ) and os.path.islink( strDllPath );
		bNeedUpdate = not bSymbolicLink;
		dbg.dump_object( "check_file_exists( vDictArgs, strDllPath ) and os.path.islink( strDllPath ), bNeedUpdate =", bNeedUpdate);
		
	if bOk and (bNeedUpdate == False):
		strInitPiPath = strFrameworkPythonDir + "/__init__.py";
		strInitPiPath = os.path.normcase( strInitPiPath );
		print strInitPiPath
		bNeedUpdate = not check_file_exists( vDictArgs, strInitPiPath );
		dbg.dump_object( "check_file_exists( vDictArgs, strInitPiPath ), bNeedUpdate =", bNeedUpdate);
		
	if bOk: 
		if (bNeedUpdate == False):
			strMsg = strMsgNotNeedUpdate;
			return (0, strMsg );
		else:
			print strMsgSwigNeedRebuild;
			bOk, strMsg, nExitResult = do_swig_rebuild( vDictArgs, strSwigDepFile, 
														strCfgBldDir, 
														strSwigOutputFile,
														strSwigInputFile );
			bGenDependencies = vDictArgs.has_key( "-M" );
			if bGenDependencies == True:
				return (nExitResult, strMsg);
				   	
	if bOk:
		bOk, strMsg = do_modify_python_lldb( vDictArgs, strCfgBldDir );
	
	if bOk:
		return (0, strMsg );
	else:
		strErrMsgProgFail += strMsg;
		return (-100, strErrMsgProgFail );	
	
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------

# This script can be called by another Python script by calling the main() 
# function directly
if __name__ == "__main__":
	print "Script cannot be called directly, called by buildSwigWrapperClasses.py";
	
