'''togl_setup.py
Compiles and installs Togl.
We create a sub-class of the standard build_ext command,
named build_togl, which is responsible for compiling the
Tk Togl widget. Our sub-class of install then takes care
of installing the resulting .dll/.so into the Python
installation against which we have compiled.
The setup process uses the headers from asource import
distribution of tcl (from thetclprojectonsourceforge import
and the .lib files from thePythonTkinterdirectory. import
'''
# created 2000/08/01, Rene Liebscher <R.Liebscher@gmx.de>
import sys,os,string, os.path
import distutils.command.install
import distutils.command.build_ext
from distutils.dep_util import newer_group
# this is also a simple test if we need to build Togl
# without Tkinter it is not neccessary
try:
import Tkinter
tk = Tkinter.Tk()
if tk.getvar('tk_version') < '8.1' or tk.getvar('tcl_version') < '8.1':
Togl = 'Togl-1.5'
togl_version_decimal = '1.5.0'
else:
Togl = 'Togl-1.6'
togl_version_decimal = '1.6.0'
## if tk.getvar( 'tk_version' ) >= '8.4':
## raise ImportError( """Preventing (doomed) attempts to build togl with Tk 8.4""" )
# if the Togl sources are not included then don't build
if not os.path.exists(os.path.join('src', Togl)):
tk = None
except ImportError:
tk = None
Togl = None
togl_version_decimal = ''
except Exception, err:
sys.stderr.write( """Unable to initialise Tk: %s\n"""%(err,))
tk = None
Togl = None
togl_version_decimal = ''
if Togl:
print 'Togl to be built:', Togl
else:
print 'Togl not to be built change config/%s.cfg to enable'%(sys.platform,)
class build_togl( distutils.command.build_ext.build_ext):
"""Build the togl.dll/togl.so shared library for Tk/Tkinter
The build_togl extension is a pretty minimal sub-class
of build_ext. It has a two extra options for specifying
the tk-source and tcl-source directories which will be
used for adding new directories to the include path for
the command.
The command also makes sure that the Python Tkinter .lib
files are in the command's lib
"""
user_options = distutils.command.build_ext.build_ext.user_options + [
('tk-source=', None,
"The Tk source directory (e.g. the tk8.4.5 directory from a source distribution)"),
('tcl-source=', None,
"The Tcl source directory (e.g. the tcl8.4.5 directory from a source distribution)"),
]
def build_extensions(self):
"""Do the actual creation of the togl shared library"""
if tk is not None and self.distribution.BUILD_TOGL:
self.togl_build(
self.distribution.togl_libs,
)
def initialize_options (self):
"""Do normal initialisation and initialise our own options"""
distutils.command.build_ext.build_ext.initialize_options( self )
self.tk_source = None
self.tcl_source = None
def finalize_options (self):
"""Finalise the options for building, we add Togl-specific includes/libs"""
distutils.command.build_ext.build_ext.finalize_options( self )
self.distribution._set_command_options(
self, self.distribution.get_option_dict('build_togl')
)
if not Togl or not self.distribution.BUILD_TOGL:
return
tkDirs = ['generic', 'xlib' ]
tclDirs = [ 'generic', 'win', ] #'include', ]
newIncludes = [
os.path.join( 'src', Togl ),
os.path.join(tk.getvar('tk_library'), '..', '..', 'include'),
]
if not (self.tk_source or self.tcl_source):
tk_version = tk.getvar( 'tk_version' )
self.warn(
"""Neither --tk-source nor --tcl-source specified for build_togl
Unless your Tk and Tcl source-distribution headers and libraries are
already on the system search path the building of Togl will likely
fail. To remedy the situation, download the Tk and Tcl sources from:
https://sourceforge.net/project/showfiles.php?group_id=10894
for version %(tk_version)s and unpack them into some directory
somewhere. Then specify:
setup.py build_togl --tk-source=/path/to/source --tcl-source=/path/to/source
on the command line for building PyOpenGL.""" % locals())
if self.tk_source:
if not self.tcl_source:
tkDirs = tkDirs + tclDirs
for fragment in tkDirs:
directory = os.path.join( self.tk_source, fragment )
if os.path.isdir( directory ):
newIncludes.append( directory )
else:
self.warn(
"""Warning, build_togl tk_source/%s (%s) doesn't exist, Togl build will likely fail!"""%(
fragment, directory,
))
if self.tcl_source:
if not self.tk_source:
tclDirs = tkDirs + tclDirs
for fragment in tclDirs:
directory = os.path.join( self.tcl_source, fragment )
if os.path.isdir( directory ):
newIncludes.append( directory )
else:
self.warn(
"""Warning, build_togl tcl_source/%s (%s) doesn't exist, Togl build will likely fail!"""%(
fragment, directory,
))
self.include_dirs.extend( newIncludes )
self.library_dirs.append( os.path.normpath(os.path.join(tk.getvar('tk_library'), '..')) )
self.include_dirs.extend( self.distribution.include_dirs )
self.library_dirs.extend( self.distribution.library_dirs )
extra_compile_args = []
if sys.platform == 'win32':
# VC++ 6.0 needs this, why togl doesn't use _WIN32?
extra_compile_args.append('-DWIN32=1')
self.libraries.append('tcl' + string.replace(tk.getvar('tcl_version'), '.', ''))
self.libraries.append('tk' + string.replace(tk.getvar('tk_version'), '.', ''))
if Togl == 'Togl-1.6':
self.libraries.append('tclstub' + string.replace(tk.getvar('tcl_version'), '.', ''))
self.libraries.append('tkstub' + string.replace(tk.getvar('tk_version'), '.', ''))
else:
self.include_dirs.append(os.path.normpath(os.path.join(tk.getvar('tcl_library'), '..', '..', 'include')))
self.library_dirs.append(os.path.normpath(os.path.join(tk.getvar('tcl_library'), '..')))
self.libraries.append('tcl' + tk.getvar('tcl_version'))
self.libraries.append('tk' + tk.getvar('tk_version'))
if os.environ.has_key('CFLAGS'):
extra_compile_args.extend(string.split(os.environ['CFLAGS']))
# these should really be coming from the setup, shouldn't they?
self.extra_compile_args = extra_compile_args
def togl_build(self, libs):
"""Core functionality of the togl_build command"""
# we subclass build_ext because need an initialized
# compiler object from build_ext, but we also need a pointer
# to the build command instance
build = self.get_finalized_command ('build')
libs = libs + []
extra_link_args = [] # ['-s']
# Name for the shared lib: (distutils will change it to Togl.{so|dll})
output_name = 'Togl'
# where to put the built shared object (only for build process)
output_dir = Togl + '-tk' + tk.getvar('tk_version')
export_symbols = ['Togl_Init']
sources = [os.path.join('src',Togl,'togl.c')]
runtime_library_dirs = None
# rest of this function was inspired by build_ext.py , build_extensions()
if not self.inplace:
output_dir = os.path.join (build.build_base, output_dir)
# what is the name of the resulting file
output_filename = self.compiler.shared_object_filename(
basename=output_name,
output_dir=output_dir)
if not (self.force or newer_group(sources, output_filename, 'newer')):
self.announce ('skipping "%s" (up-to-date)' % output_name)
else:
self.announce ('building "%s"' % output_name)
# compile source files
objects = self.compiler.compile (sources,
output_dir=self.build_temp,
macros=[
('USE_TCL_STUBS',1),
('USE_TK_STUBS',1),
],
include_dirs=self.include_dirs,
debug=self.debug,
extra_postargs=self.extra_compile_args)
# link all together
self.compiler.link_shared_object (
objects,
output_filename,
'', # <= output_dir
libraries=libs,
library_dirs=self.library_dirs,
runtime_library_dirs=runtime_library_dirs,
extra_postargs=extra_link_args,
export_symbols=export_symbols,
debug=self.debug,
build_temp=self.build_temp)
class install(distutils.command.install.install):
togl_outfiles = None
def run(self):
distutils.command.install.install.run(self)
# togl_install can read instance variables of install_lib
# it has to return the filenames of all installed files
if tk is not None and self.distribution.BUILD_TOGL:
self.togl_outfiles = togl_install(self)
def get_outputs(self):
if self.togl_outfiles is None:
if tk is not None and self.distribution.BUILD_TOGL:
self.togl_outfiles = togl_install(self,dry_run=1)
else:
self.togl_outfiles = []
return distutils.command.install.install.get_outputs(self) + self.togl_outfiles
def replace_lib(include_dirs, path):
components = [path]
rep = 0
while 1:
head, tail = os.path.split(components[0])
if tail:
if tail == 'lib':
rep = 1
components[0] = 'include'
else:
components[0] = tail
components.insert(0, head)
else:
break
if rep:
include_dirs.append(apply(os.path.join, components))
# build togl
# building togl shared library
# togl_build
from distutils.util import change_root
# install togl
#
# It is possibly to do this all in the build step, but then
# it is not included in a RPM distribution.
#
pkgIndex_tcl = r"""if {![package vsatisfies [package provide Tcl] 8]} {return}
package ifneeded Togl %(togl_version)s \
[list load [file join $dir %(togl)s] Togl]"""
def togl_install(self,dry_run=0): # a simple function, not a class !!!
outfiles = [] # we have to return all files we have installed
# get path to Tk directory
togl_dir = os.path.normpath(os.path.join(self.install_lib,'OpenGL','Tk', \
sys.platform + '-tk' + tk.getvar('tk_version')))
self.mkpath(togl_dir)
# how are the built files called, and
# which names should have the installed files
if sys.platform == 'win32':
togl = 'Togl.dll'
else:
togl = 'Togl.so'
togl_src = os.path.join(self.build_base,
Togl + '-tk' + tk.getvar('tk_version'), togl)
togl_dst = os.path.join(togl_dir,togl)
# copy togl in tk directory
if not dry_run:
from types import TupleType
out = self.copy_file(togl_src, togl_dst)
if type(out) is TupleType:
out = out[0]
else:
out = togl_dst
outfiles.append(out)
# make package index for tcl/tk
indexFile = os.path.join( togl_dir, 'pkgIndex.tcl' )
if not dry_run:
# only if real install
self.announce( 'creating pkgIndex.tcl in %(togl_dir)s for %(togl)s'%locals())
file = open( indexFile, 'w')
togl_version = togl_version_decimal
file.write( pkgIndex_tcl % locals())
file.close()
outfiles.append(indexFile)
return outfiles
|