From f144196ffe4582e611b9abf0e910e6c0e888080f Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 3 Jun 2004 17:43:44 +0000 Subject: [PATCH] new genPyCode --- direct/src/ffi/FFIConstants.py | 2 +- direct/src/ffi/FFIEnvironment.py | 2 +- direct/src/ffi/FFIInterrogateDatabase.py | 76 +++++++++-- direct/src/ffi/Sources.pp | 12 +- direct/src/ffi/genPyCode | 124 ------------------ direct/src/ffi/genPyCode.pp | 141 ++++++++++++++++++++ direct/src/ffi/generatePythonCode | 157 ----------------------- 7 files changed, 218 insertions(+), 296 deletions(-) delete mode 100755 direct/src/ffi/genPyCode create mode 100644 direct/src/ffi/genPyCode.pp delete mode 100644 direct/src/ffi/generatePythonCode diff --git a/direct/src/ffi/FFIConstants.py b/direct/src/ffi/FFIConstants.py index b203e8bcb3..1ace18472e 100644 --- a/direct/src/ffi/FFIConstants.py +++ b/direct/src/ffi/FFIConstants.py @@ -4,7 +4,7 @@ from direct.directnotify.DirectNotifyGlobal import * notify = directNotify.newCategory("FFI") # This is the name of the file that the importing code will be stored -importModuleName = 'PandaModulesUnsqueezed' +importModuleName = 'PandaModules' # A header for all the generated files generatedHeader = '# This file is automatically generated. It would be unwise to edit.\n\n' diff --git a/direct/src/ffi/FFIEnvironment.py b/direct/src/ffi/FFIEnvironment.py index 3284696914..443a2cbb81 100644 --- a/direct/src/ffi/FFIEnvironment.py +++ b/direct/src/ffi/FFIEnvironment.py @@ -13,7 +13,7 @@ class FFIEnvironment: def addType(self, typeDescriptor, name): if self.types.has_key(name): - FFIConstants.notify.warning('Redefining type named: ' + name) + FFIConstants.notify.info('Redefining type named: ' + name) self.types[name] = typeDescriptor def getTypeNamed(self, name): diff --git a/direct/src/ffi/FFIInterrogateDatabase.py b/direct/src/ffi/FFIInterrogateDatabase.py index 7d99a11f37..407c5520ae 100644 --- a/direct/src/ffi/FFIInterrogateDatabase.py +++ b/direct/src/ffi/FFIInterrogateDatabase.py @@ -5,7 +5,7 @@ import string import os -import compileall +import glob import FFIEnvironment import FFITypes @@ -15,8 +15,8 @@ import FFIConstants import FFIOverload from direct.showbase.PythonUtil import * -# FFIConstants.notify.setDebug(1) FFIConstants.notify.info('Importing interrogate library: ' + FFIConstants.InterrogateModuleName) + # Note: we do a from lib import * here because we do not want # to be dependent on the name of the interrogate library in this code exec('from ' + FFIConstants.InterrogateModuleName + ' import *') @@ -220,7 +220,14 @@ def getTypeName(typeIndex, scoped=0): class FFIInterrogateDatabase: - def __init__(self): + def __init__(self, etcPath = []): + # Temporary try..except for old Panda. + try: + for dir in etcPath: + interrogate_add_search_directory(dir) + except: + pass + self.typeIndexMap = {} self.environment = FFIEnvironment.FFIEnvironment() @@ -230,7 +237,7 @@ class FFIInterrogateDatabase: def constructDescriptor(self, typeIndex): if interrogate_type_is_atomic(typeIndex): return self.constructPrimitiveTypeDescriptor(typeIndex) - + elif interrogate_type_is_enum(typeIndex): return self.constructEnumTypeDescriptor(typeIndex) @@ -377,7 +384,6 @@ class FFIInterrogateDatabase: descriptor.foreignTypeName = typeName if (typeName == "TypedObject"): - print "Found typed object descriptor" FFITypes.TypedObjectDescriptor = descriptor descriptor.isNested = interrogate_type_is_nested(typeIndex) @@ -586,9 +592,11 @@ class FFIInterrogateDatabase: funcSpec.index = funcIndex return funcSpec - def addTypes(self): + def addTypes(self, CModuleName): for i in range(interrogate_number_of_global_types()): - self.constructDescriptor(interrogate_get_global_type(i)) + typeIndex = interrogate_get_global_type(i) + if self.typeInCModule(typeIndex, CModuleName): + self.constructDescriptor(typeIndex) def addEnvironmentTypes(self): for descriptor in self.typeIndexMap.values(): @@ -599,6 +607,11 @@ class FFIInterrogateDatabase: moduleName = 'lib' + interrogate_function_module_name(funcIndex) return (moduleName == CModuleName) + def typeInCModule(self, typeIndex, CModuleName): + if interrogate_type_has_module_name(typeIndex): + moduleName = 'lib' + interrogate_type_module_name(typeIndex) + return (moduleName == CModuleName) + def constructGlobal(self, globalIndex, CModuleName): # We really do not need the descriptor for the value, just @@ -724,18 +737,57 @@ class FFIInterrogateDatabase: file = open(init, 'w') file.close() - # Commented out based upon assumption that squeeze will do the compile - #FFIConstants.notify.info( 'Compiling code...') - #compileall.compile_dir(codeDir) + def squeezeGeneratedCode(self, outputDir): + + # Since we will be squeezing the importModuleName file, rename + # the original to something we can import from within the + # squeezed version. + squeezedName = FFIConstants.importModuleName + unsqueezedName = FFIConstants.importModuleName + 'Unsqueezed' + + os.rename(os.path.join(outputDir, squeezedName + '.py'), + os.path.join(outputDir, unsqueezedName + '.py')) + + # Get the list of files to squeeze. This is all of the .py + # files in the output directory except for the __init__.py + # file. + + files = glob.glob(os.path.join(outputDir, '*.py')) + init = os.path.join(outputDir, '__init__.py') + try: + files.remove(init) + except: + pass + + print "Squeezing %s files." % (len(files)) + + from direct.showbase import pandaSqueezeTool + + pandaSqueezeTool.squeeze(squeezedName, unsqueezedName, + files, outputDir) + + # Remove the now-squeezed source files. + for file in files: + os.remove(file) + def generateCodeLib(self, codeDir, extensionsDir, CModuleName): # Reset the environment so we are clean from any old modules self.environment.reset() FFIConstants.notify.info('='*50) - FFIConstants.notify.info('Importing code library: ' + CModuleName) + FFIConstants.notify.warning('Importing code library: ' + CModuleName) exec('import ' + CModuleName) + # Temporary try..except for old Panda. + try: + errorFlag = interrogate_error_flag() + except: + errorFlag = False + + if errorFlag: + FFIConstants.notify.error("Error reading interrogate database; can't continue.") + self.updateBindings(CModuleName) FFIConstants.notify.info( 'Generating type code...') @@ -803,7 +855,7 @@ class FFIInterrogateDatabase: def updateBindings(self, CModuleName): FFIConstants.notify.info( 'Updating Bindings') FFIConstants.notify.info( 'Adding Types...') - self.addTypes() + self.addTypes(CModuleName) FFIConstants.notify.info( 'Adding global values...') self.addGlobalValues(CModuleName) FFIConstants.notify.info( 'Adding global functions...') diff --git a/direct/src/ffi/Sources.pp b/direct/src/ffi/Sources.pp index 68d8f87c06..f66f402092 100644 --- a/direct/src/ffi/Sources.pp +++ b/direct/src/ffi/Sources.pp @@ -1 +1,11 @@ -#define INSTALL_SCRIPTS generatePythonCode genPyCode +#define INSTALL_SCRIPTS genPyCode.py + +// If we're on Win32 without Cygwin, install the genPyCode.bat file; +// for all other platforms, install the genPyCode sh script. +#if $[eq $[PLATFORM],Win32] + #define INSTALL_SCRIPTS $[INSTALL_SCRIPTS] genPyCode.bat +#else + #define INSTALL_SCRIPTS $[INSTALL_SCRIPTS] genPyCode +#endif + +#include $[THISDIRPREFIX]genPyCode.pp diff --git a/direct/src/ffi/genPyCode b/direct/src/ffi/genPyCode deleted file mode 100755 index ebb742777d..0000000000 --- a/direct/src/ffi/genPyCode +++ /dev/null @@ -1,124 +0,0 @@ -#! /bin/bash - -# This is just a helper script to generatePythonCode to cover -# the three or four cases we use all the time -# usage: genPyCode [opts] [linux|win-debug|win-release|win-publish|install|release] [other libs] - -# -g adds libgateway -# -t adds libtoontown -# -p adds libpirates -# -v adds libvrpn -# -e adds libpandaegg -# -n doesn't perform a squeeze - -base_dir=$(pwd) -extra_genPyCode_libs="" -squeezeFlag="" -optimizeFlag="" -ppython=ppython -ppythonOptimizeFlag="" - -while getopts ogtpven flag; do - case $flag in - o) extra_genPyCode_libs="$extra_genPyCode_libs libotp" ;; - g) extra_genPyCode_libs="$extra_genPyCode_libs libgateway" ;; - t) extra_genPyCode_libs="$extra_genPyCode_libs libtoontown" ;; - p) extra_genPyCode_libs="$extra_genPyCode_libs libpirates" ;; - v) extra_genPyCode_libs="$extra_genPyCode_libs libvrpn" ;; - e) extra_genPyCode_libs="$extra_genPyCode_libs libpandaegg" ;; - n) doSqueeze="-n" ;; - esac -done - -shift `expr $OPTIND - 1` - -buildType="$1" -shift -extra_genPyCode_libs="$extra_genPyCode_libs $*" - -if [ "$INSTALL_DIR" != "" ]; then - install_dir="$INSTALL_DIR" -elif [ "$PANDA_INSTALL" != "" ]; then - install_dir="$PANDA_INSTALL" -elif [ "$DIRECT" != "" ]; then - install_dir="$DIRECT" -else - install_dir=./install -fi - -if [ "$DIRECT" == "" ]; then - if [ "$PLAYER" != "" -a -d "$PLAYER/direct" ]; then - DIRECT="$PLAYER/direct" - elif [ -d direct ]; then - DIRECT=direct - else - echo "Define PLAYER to point to the panda & direct source root." - exit 1 - fi -fi - -pyDir=$DIRECT/lib/pandac -extDir=$DIRECT/src/extensions -pSqueezer=$DIRECT/src/showbase/pandaSqueezer.py - -if [ "$buildType" = "linux" ]; then - cd $DIRECT/bin - ppython -d generatePythonCode -v -d $pyDir $doSqueeze -e $extDir -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect $extra_genPyCode_libs || exit - pSqueezer=$DIRECT/src/showbase/pandaSqueezer.py - -elif [ "$buildType" = "win-debug" ]; then - cd $DIRECT/bin - pyDir="$(cygpath -w $pyDir)" - extDir="$(cygpath -w $extDir)" - pSqueezer="$(cygpath -w $pSqueezer)" - ppython -d generatePythonCode -v -d $pyDir $doSqueeze -e $extDir -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect $extra_genPyCode_libs || exit -elif [ "$buildType" = "win-release" ]; then - cd $DIRECT/bin - pyDir="$(cygpath -w $pyDir)" - extDir="$(cygpath -w $extDir)" - pSqueezer="$(cygpath -w $pSqueezer)" - ppython generatePythonCode -v -d $pyDir $doSqueeze -e $extDir -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect $extra_genPyCode_libs || exit -elif [ "$buildType" = "win-publish" ]; then - # no assertions, no comments, no docstrings - cd $DIRECT/bin - pyDir="$(cygpath -w $pyDir)" - extDir="$(cygpath -w $extDir)" - pSqueezer="$(cygpath -w $pSqueezer)" - ppython -OO generatePythonCode -O -v -d $pyDir $doSqueeze -e $extDir -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect $extra_genPyCode_libs || exit - optimizeFlag="-O" - ppythonOptimizeFlag="-OO" - -elif [ "$buildType" = "install" ]; then - # Use relative paths; as installed on a machine without ctattach etc. - pyDir=$install_dir/lib/pandac - ppython=$install_dir/bin/ppython - pSqueezer=$DIRECT/src/showbase/pandaSqueezer.py - $ppython -d $install_dir/bin/generatePythonCode -O -v -d $pyDir $doSqueeze -e $DIRECT/src/extensions -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect $extra_genPyCode_libs || exit -elif [ "$buildType" = "release" ]; then - # Use relative paths; as installed on a machine without ctattach etc. - pyDir=$install_dir/lib/pandac - ppython=$install_dir/bin/ppython - pSqueezer=$DIRECT/src/showbase/pandaSqueezer.py - $ppython $install_dir/bin/generatePythonCode -v -d $pyDir $doSqueeze -e $DIRECT/src/extensions -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect $extra_genPyCode_libs || exit -else - echo "Invalid parameter: $buildType" - exit 1 -fi - -# The squeeze step is now performed as part of generatePythonCode. - -#if [ "$fSqueeze" = "squeezeMe" ]; then -# echo SQUEEZING PandaModules -# rm -f $pyDir/PandaModules.py* $pyDir/__init__.py || exit -# $ppython $ppythonOptimizeFlag $pSqueezer $optimizeFlag -d $pyDir || exit -# touch $pyDir/__init__.py || exit -#else -# # renaming PandaModulesUnsqueezed.py to PandaModules.py -# cd $pyDir || exit -# rm -f PandaModules.py* || exit -# echo # junk line needed to keep mv from failing -# mv PandaModulesUnsqueezed.py PandaModules.py || exit -#fi - -echo DONE - diff --git a/direct/src/ffi/genPyCode.pp b/direct/src/ffi/genPyCode.pp new file mode 100644 index 0000000000..f8a6a86dba --- /dev/null +++ b/direct/src/ffi/genPyCode.pp @@ -0,0 +1,141 @@ +// +// genPyCode.pp +// +// This file defines the script to auto-generate a sensible genPyCode +// for the user based on the Config.pp variables in effect at the time +// ppremake is run. The generated script will know which directories +// to generate its output to, as well as which source files to read +// for the input. +// + +#define hash # + +#define install_dir $[$[upcase $[PACKAGE]]_INSTALL] +#define install_lib_dir $[or $[INSTALL_LIB_DIR],$[install_dir]/lib] +#define install_bin_dir $[or $[INSTALL_BIN_DIR],$[install_dir]/bin] +#define install_igatedb_dir $[or $[INSTALL_IGATEDB_DIR],$[install_dir]/etc] + +// If we're on Win32 without Cygwin, generate a genPyCode.bat file; +// for all other platforms, generate a genPyCode sh script. Although +// it's true that on non-Win32 platforms we don't need the script +// (since the python file itself could be made directly executable), +// we generate the script anyway to be consistent with Win32, which +// does require it. + +#if $[eq $[PLATFORM],Win32] + +#output genPyCode.bat +@echo off +python $[osfilename $[install_bin_dir]/genPyCode.py] +#end genPyCode.bat + +#else // Win32 + +#output genPyCode +$[hash]! /bin/sh +python $[install_bin_dir]/genPyCode.py +#end genPyCode + +#endif // Win32 + +#output genPyCode.py +$[hash]! /usr/bin/env python + +import os +import sys +import glob + +#if $[CTPROJS] +# This script was generated while the user was using the ctattach +# tools. That had better still be the case. + +ctprojs = os.getenv('CTPROJS') +if not ctprojs: + print "You are no longer attached to any trees!" + sys.exit(1) + +directDir = os.getenv('DIRECT') +if not directDir: + print "You are not attached to DIRECT!" + sys.exit(1) + +# Make sure that direct/src/showbase/sitecustomize.py gets loaded. +parent, base = os.path.split(directDir) + +if parent not in sys.path: + sys.path.append(parent) + +import direct.showbase.sitecustomize + +#endif + +from direct.ffi import DoGenPyCode +from direct.ffi import FFIConstants + +# The following parameters were baked in to this script at the time +# ppremake was run in Direct. +DoGenPyCode.outputDir = '$[osfilename $[install_lib_dir]/pandac]' +DoGenPyCode.extensionsDir = '$[osfilename $[TOPDIR]/src/extensions]' +DoGenPyCode.interrogateLib = 'libdtoolconfig' +DoGenPyCode.codeLibs = '$[GENPYCODE_LIBS]'.split() +DoGenPyCode.etcPath = ['$[osfilename $[install_igatedb_dir]]'] + +#if $[>= $[OPTIMIZE], 4] +FFIConstants.wantComments = 0 +FFIConstants.wantTypeChecking = 0 +#endif + +#if $[CTPROJS] + +# Actually, the user is expected to be using ctattach, so never mind +# on the baked-in stuff--replace it with the dynamic settings from +# ctattach. +DoGenPyCode.outputDir = os.path.join(directDir, 'lib', 'pandac') +DoGenPyCode.extensionsDir = os.path.join(directDir, 'src', 'extensions') +DoGenPyCode.etcPath = [] + +# Look for additional packages (other than the basic three) +# that the user might be dynamically attached to. +packages = [] +for proj in ctprojs.split(): + projName = proj.split(':')[0] + packages.append(projName) +packages.reverse() + +for package in packages: + packageDir = os.getenv(package) + if packageDir: + etcDir = os.path.join(packageDir, 'etc') + try: + inFiles = glob.glob(os.path.join(etcDir, '*.in')) + except: + inFiles = [] + if inFiles: + DoGenPyCode.etcPath.append(etcDir) + + if package not in ['DTOOL', 'DIRECT', 'PANDA']: + libDir = os.path.join(packageDir, 'lib') + try: + files = os.listdir(libDir) + except: + files = [] + for file in files: + if os.path.isfile(os.path.join(libDir, file)): + basename, ext = os.path.splitext(file) + + # Try to import the library. If we can import it, + # instrument it. + try: + __import__(basename, globals(), locals()) + isModule = True + except: + isModule = False + + if isModule: + if basename not in DoGenPyCode.codeLibs: + DoGenPyCode.codeLibs.append(basename) +#endif + +DoGenPyCode.run() + +#end genPyCode.py diff --git a/direct/src/ffi/generatePythonCode b/direct/src/ffi/generatePythonCode deleted file mode 100644 index 4283b75491..0000000000 --- a/direct/src/ffi/generatePythonCode +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/local/bin/python - - -import getopt -import sys -import os -import glob -from direct.ffi import FFIConstants - -# Define a help string for the user -helpString =""" -generatePythonCode [opts] -i libtool libcode1 libcode2 ... - -Generates Python code for the C++ libraries listed. - -Example: -Linux: - ppython -d generatePythonCode -v -d $DIRECT/lib/py -e $DIRECT/src/extensions -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect libtoontown - -Windows debug: - ppython -d generatePythonCode -v -d `cygpath -w $DIRECT/lib/py` -e `cygpath -w $DIRECT/src/extensions` -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect libtoontown - -Windows release: - ppython generatePythonCode -v -d `cygpath -w $DIRECT/lib/py` -e `cygpath -w $DIRECT/src/extensions` -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect libtoontown - -Windows publish (no assertions, no comments, no docstrings): - ppython -OO generatePythonCode -O -v -d `cygpath -w $DIRECT/lib/py` -e `cygpath -w $DIRECT/src/extensions` -i libdtoolconfig libpandaexpress libpanda libpandaphysics libdirect libtoontown - - -Options: - -h print this message - -v verbose - -d dir directory to write output code - -e dir directory to pull extension code from - -i lib interrogate library - -O no C++ comments or assertion statements - -n Don't use squeezeTool to squeeze the result into one .pyz file -""" - -# Initialize variables -outputDir = '' -extensionsDir = '' -interrogateLib = '' -codeLibs = [] -doSqueeze = True - - -# Extract the args the user passed in -try: - opts, pargs = getopt.getopt(sys.argv[1:], 'hvOd:e:i:n') -except Exception, e: - # User passed in a bad option, print the error and the help, then exit - print e - print helpString - sys.exit() - -if len(opts)==0: - print helpString - sys.exit() - - -# Store the option values into our variables -for opt in opts: - flag, value = opt - if (flag == '-h'): - print helpString - sys.exit() - elif (flag == '-v'): - FFIConstants.notify.setInfo(1) - elif (flag == '-d'): - outputDir = value - elif (flag == '-e'): - extensionsDir = value - elif (flag == '-i'): - interrogateLib = value - elif (flag == '-O'): - FFIConstants.wantComments = 0 - FFIConstants.wantTypeChecking = 0 - elif (flag == '-n'): - doSqueeze = False - else: - FFIConstants.notify.error('illegal option: ' + flag) - -# Store the program arguments into the codeLibs -codeLibs = pargs - -# Now do some error checking and verbose output -if (not interrogateLib): - FFIConstants.notify.error('You must specify an interrogate library (-i lib)') -else: - FFIConstants.notify.info('Setting interrogate library to: ' + interrogateLib) - FFIConstants.InterrogateModuleName = interrogateLib - -if (not outputDir): - FFIConstants.notify.info('Setting output directory to current directory') - outputDir = '.' -elif (not os.path.exists(outputDir)): - FFIConstants.notify.info('Directory does not exist, creating: ' + outputDir) - os.mkdir(outputDir) - FFIConstants.notify.info('Setting output directory to: ' + outputDir) -else: - FFIConstants.notify.info('Setting output directory to: ' + outputDir) - - -if (not extensionsDir): - FFIConstants.notify.info('Setting extensions directory to current directory') - extensionsDir = '.' -elif (not os.path.exists(extensionsDir)): - FFIConstants.notify.error('Directory does not exists: ' + extensionsDir) -else: - FFIConstants.notify.info('Setting extensions directory to: ' + extensionsDir) - - -if (not codeLibs): - FFIConstants.notify.error('You must specify one or more libraries to generate code from') -else: - FFIConstants.notify.info('Generating code for: ' + `codeLibs`) - FFIConstants.CodeModuleNameList = codeLibs - -# Ok, now we can start generating code -from direct.ffi import FFIInterrogateDatabase -db = FFIInterrogateDatabase.FFIInterrogateDatabase() -db.generateCode(outputDir, extensionsDir) - - -# Remove any leftover junk files in outputDir from a previous run. -print "outputDir = %s, doSqueeze = %s" % (outputDir, doSqueeze) -for file in glob.glob(os.path.join(outputDir, 'PandaModules.py*')): - print "removing junk %s" % (file) - os.remove(file) - -if doSqueeze: - # Invoke the squeezer. - files = glob.glob(os.path.join(outputDir, '*.py')) - init = os.path.join(outputDir, '__init__.py') - try: - files.remove(init) - except: - pass - - print "Squeezing %s files." % (len(files)) - - from direct.showbase import pandaSqueezeTool - pandaSqueezeTool.squeeze("PandaModules", "PandaModulesUnsqueezed", - files, outputDir) - - # Remove the squeezed source files. - for file in files: - os.remove(file) - -else: - print "Not squeezing." - os.rename(os.path.join(outputDir, 'PandaModulesUnsqueezed.py'), - os.path.join(outputDir, 'PandaModules.py')) - - -