| """SCons.Tool.pyext |
| |
| Tool-specific initialization for python extensions builder. |
| |
| AUTHORS: |
| - David Cournapeau |
| - Dag Sverre Seljebotn |
| |
| """ |
| |
| # |
| # __COPYRIGHT__ |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining |
| # a copy of this software and associated documentation files (the |
| # "Software"), to deal in the Software without restriction, including |
| # without limitation the rights to use, copy, modify, merge, publish, |
| # distribute, sublicense, and/or sell copies of the Software, and to |
| # permit persons to whom the Software is furnished to do so, subject to |
| # the following conditions: |
| # |
| # The above copyright notice and this permission notice shall be included |
| # in all copies or substantial portions of the Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| # |
| |
| __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" |
| |
| import sys |
| |
| import SCons |
| from SCons.Tool import SourceFileScanner, ProgramScanner |
| |
| # Create common python builders |
| |
| def createPythonObjectBuilder(env): |
| """This is a utility function that creates the PythonObject Builder in an |
| Environment if it is not there already. |
| |
| If it is already there, we return the existing one. |
| """ |
| |
| try: |
| pyobj = env['BUILDERS']['PythonObject'] |
| except KeyError: |
| pyobj = SCons.Builder.Builder(action = {}, |
| emitter = {}, |
| prefix = '$PYEXTOBJPREFIX', |
| suffix = '$PYEXTOBJSUFFIX', |
| src_builder = ['CFile', 'CXXFile'], |
| source_scanner = SourceFileScanner, |
| single_source = 1) |
| env['BUILDERS']['PythonObject'] = pyobj |
| |
| return pyobj |
| |
| def createPythonExtensionBuilder(env): |
| """This is a utility function that creates the PythonExtension Builder in |
| an Environment if it is not there already. |
| |
| If it is already there, we return the existing one. |
| """ |
| |
| try: |
| pyext = env['BUILDERS']['PythonExtension'] |
| except KeyError: |
| import SCons.Action |
| import SCons.Defaults |
| action = SCons.Action.Action("$PYEXTLINKCOM", "$PYEXTLINKCOMSTR") |
| action_list = [ SCons.Defaults.SharedCheck, |
| action] |
| pyext = SCons.Builder.Builder(action = action_list, |
| emitter = "$SHLIBEMITTER", |
| prefix = '$PYEXTPREFIX', |
| suffix = '$PYEXTSUFFIX', |
| target_scanner = ProgramScanner, |
| src_suffix = '$PYEXTOBJSUFFIX', |
| src_builder = 'PythonObject') |
| env['BUILDERS']['PythonExtension'] = pyext |
| |
| return pyext |
| |
| def pyext_coms(platform): |
| """Return PYEXTCCCOM, PYEXTCXXCOM and PYEXTLINKCOM for the given |
| platform.""" |
| if platform == 'win32': |
| pyext_cccom = "$PYEXTCC /Fo$TARGET /c $PYEXTCCSHARED "\ |
| "$PYEXTCFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\ |
| "$_PYEXTCPPINCFLAGS $SOURCES" |
| pyext_cxxcom = "$PYEXTCXX /Fo$TARGET /c $PYEXTCSHARED "\ |
| "$PYEXTCXXFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\ |
| "$_PYEXTCPPINCFLAGS $SOURCES" |
| pyext_linkcom = '${TEMPFILE("$PYEXTLINK $PYEXTLINKFLAGS '\ |
| '/OUT:$TARGET.windows $( $_LIBDIRFLAGS $) '\ |
| '$_LIBFLAGS $_PYEXTRUNTIME $SOURCES.windows")}' |
| else: |
| pyext_cccom = "$PYEXTCC -o $TARGET -c $PYEXTCCSHARED "\ |
| "$PYEXTCFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\ |
| "$_PYEXTCPPINCFLAGS $SOURCES" |
| pyext_cxxcom = "$PYEXTCXX -o $TARGET -c $PYEXTCSHARED "\ |
| "$PYEXTCXXFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\ |
| "$_PYEXTCPPINCFLAGS $SOURCES" |
| pyext_linkcom = "$PYEXTLINK -o $TARGET $PYEXTLINKFLAGS "\ |
| "$SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_PYEXTRUNTIME" |
| |
| if platform == 'darwin': |
| pyext_linkcom += ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS' |
| |
| return pyext_cccom, pyext_cxxcom, pyext_linkcom |
| |
| def set_basic_vars(env): |
| # Set construction variables which are independant on whether we are using |
| # distutils or not. |
| env['PYEXTCPPPATH'] = SCons.Util.CLVar('$PYEXTINCPATH') |
| |
| env['_PYEXTCPPINCFLAGS'] = '$( ${_concat(INCPREFIX, PYEXTCPPPATH, '\ |
| 'INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' |
| env['PYEXTOBJSUFFIX'] = '$SHOBJSUFFIX' |
| env['PYEXTOBJPREFIX'] = '$SHOBJPREFIX' |
| |
| env['PYEXTRUNTIME'] = SCons.Util.CLVar("") |
| # XXX: this should be handled with different flags |
| env['_PYEXTRUNTIME'] = '$( ${_concat(LIBLINKPREFIX, PYEXTRUNTIME, '\ |
| 'LIBLINKSUFFIX, __env__)} $)' |
| # XXX: This won't work in all cases (using mingw, for example). To make |
| # this work, we need to know whether PYEXTCC accepts /c and /Fo or -c -o. |
| # This is difficult with the current way tools work in scons. |
| pycc, pycxx, pylink = pyext_coms(sys.platform) |
| |
| env['PYEXTLINKFLAGSEND'] = SCons.Util.CLVar('$LINKFLAGSEND') |
| |
| env['PYEXTCCCOM'] = pycc |
| env['PYEXTCXXCOM'] = pycxx |
| env['PYEXTLINKCOM'] = pylink |
| |
| def _set_configuration_nodistutils(env): |
| # Set env variables to sensible values when not using distutils |
| def_cfg = {'PYEXTCC' : '$SHCC', |
| 'PYEXTCFLAGS' : '$SHCFLAGS', |
| 'PYEXTCCFLAGS' : '$SHCCFLAGS', |
| 'PYEXTCXX' : '$SHCXX', |
| 'PYEXTCXXFLAGS' : '$SHCXXFLAGS', |
| 'PYEXTLINK' : '$LDMODULE', |
| 'PYEXTSUFFIX' : '$LDMODULESUFFIX', |
| 'PYEXTPREFIX' : ''} |
| |
| if sys.platform == 'darwin': |
| def_cfg['PYEXTSUFFIX'] = '.so' |
| |
| for k, v in def_cfg.items(): |
| ifnotset(env, k, v) |
| |
| ifnotset(env, 'PYEXT_ALLOW_UNDEFINED', |
| SCons.Util.CLVar('$ALLOW_UNDEFINED')) |
| ifnotset(env, 'PYEXTLINKFLAGS', SCons.Util.CLVar('$LDMODULEFLAGS')) |
| |
| env.AppendUnique(PYEXTLINKFLAGS = env['PYEXT_ALLOW_UNDEFINED']) |
| |
| def ifnotset(env, name, value): |
| if not env.has_key(name): |
| env[name] = value |
| |
| def set_configuration(env, use_distutils): |
| """Set construction variables which are platform dependants. |
| |
| If use_distutils == True, use distutils configuration. Otherwise, use |
| 'sensible' default. |
| |
| Any variable already defined is untouched.""" |
| |
| # We define commands as strings so that we can either execute them using |
| # eval (same python for scons and distutils) or by executing them through |
| # the shell. |
| dist_cfg = {'PYEXTCC': ("sysconfig.get_config_var('CC')", False), |
| 'PYEXTCFLAGS': ("sysconfig.get_config_var('CFLAGS')", True), |
| 'PYEXTCCSHARED': ("sysconfig.get_config_var('CCSHARED')", False), |
| 'PYEXTLINKFLAGS': ("sysconfig.get_config_var('LDFLAGS')", True), |
| 'PYEXTLINK': ("sysconfig.get_config_var('LDSHARED')", False), |
| 'PYEXTINCPATH': ("sysconfig.get_python_inc()", False), |
| 'PYEXTSUFFIX': ("sysconfig.get_config_var('SO')", False)} |
| |
| from distutils import sysconfig |
| |
| # We set the python path even when not using distutils, because we rarely |
| # want to change this, even if not using distutils |
| ifnotset(env, 'PYEXTINCPATH', sysconfig.get_python_inc()) |
| |
| if use_distutils: |
| for k, (v, should_split) in dist_cfg.items(): |
| val = eval(v) |
| if should_split: |
| val = val.split() |
| ifnotset(env, k, val) |
| else: |
| _set_configuration_nodistutils(env) |
| |
| def generate(env): |
| """Add Builders and construction variables for python extensions to an |
| Environment.""" |
| |
| if not env.has_key('PYEXT_USE_DISTUTILS'): |
| env['PYEXT_USE_DISTUTILS'] = False |
| |
| # This sets all constructions variables used for pyext builders. |
| set_basic_vars(env) |
| |
| set_configuration(env, env['PYEXT_USE_DISTUTILS']) |
| |
| # Create the PythonObject builder |
| pyobj = createPythonObjectBuilder(env) |
| action = SCons.Action.Action("$PYEXTCCCOM", "$PYEXTCCCOMSTR") |
| pyobj.add_emitter('.c', SCons.Defaults.SharedObjectEmitter) |
| pyobj.add_action('.c', action) |
| |
| action = SCons.Action.Action("$PYEXTCXXCOM", "$PYEXTCXXCOMSTR") |
| pyobj.add_emitter('$CXXFILESUFFIX', SCons.Defaults.SharedObjectEmitter) |
| pyobj.add_action('$CXXFILESUFFIX', action) |
| |
| # Create the PythonExtension builder |
| createPythonExtensionBuilder(env) |
| |
| def exists(env): |
| try: |
| # This is not quite right: if someone defines all variables by himself, |
| # it would work without distutils |
| from distutils import sysconfig |
| return True |
| except ImportError: |
| return False |