Home | History | Annotate | Download | only in site_tools
      1 """SCons.Tool.pyext
      2 
      3 Tool-specific initialization for python extensions builder.
      4 
      5 AUTHORS:
      6  - David Cournapeau
      7  - Dag Sverre Seljebotn
      8 
      9 """
     10 
     11 #
     12 # __COPYRIGHT__
     13 #
     14 # Permission is hereby granted, free of charge, to any person obtaining
     15 # a copy of this software and associated documentation files (the
     16 # "Software"), to deal in the Software without restriction, including
     17 # without limitation the rights to use, copy, modify, merge, publish,
     18 # distribute, sublicense, and/or sell copies of the Software, and to
     19 # permit persons to whom the Software is furnished to do so, subject to
     20 # the following conditions:
     21 #
     22 # The above copyright notice and this permission notice shall be included
     23 # in all copies or substantial portions of the Software.
     24 #
     25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
     26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
     27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     29 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     30 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     32 #
     33 
     34 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
     35 
     36 import sys
     37 
     38 import SCons
     39 from SCons.Tool import SourceFileScanner, ProgramScanner
     40 
     41 #  Create common python builders
     42 
     43 def createPythonObjectBuilder(env):
     44     """This is a utility function that creates the PythonObject Builder in an
     45     Environment if it is not there already.
     46 
     47     If it is already there, we return the existing one.
     48     """
     49 
     50     try:
     51         pyobj = env['BUILDERS']['PythonObject']
     52     except KeyError:
     53         pyobj = SCons.Builder.Builder(action = {},
     54                                       emitter = {},
     55                                       prefix = '$PYEXTOBJPREFIX',
     56                                       suffix = '$PYEXTOBJSUFFIX',
     57                                       src_builder = ['CFile', 'CXXFile'],
     58                                       source_scanner = SourceFileScanner,
     59                                       single_source = 1)
     60         env['BUILDERS']['PythonObject'] = pyobj
     61 
     62     return pyobj
     63 
     64 def createPythonExtensionBuilder(env):
     65     """This is a utility function that creates the PythonExtension Builder in
     66     an Environment if it is not there already.
     67 
     68     If it is already there, we return the existing one.
     69     """
     70 
     71     try:
     72         pyext = env['BUILDERS']['PythonExtension']
     73     except KeyError:
     74         import SCons.Action
     75         import SCons.Defaults
     76         action = SCons.Action.Action("$PYEXTLINKCOM", "$PYEXTLINKCOMSTR")
     77         action_list = [ SCons.Defaults.SharedCheck,
     78                         action]
     79         pyext = SCons.Builder.Builder(action = action_list,
     80                                       emitter = "$SHLIBEMITTER",
     81                                       prefix = '$PYEXTPREFIX',
     82                                       suffix = '$PYEXTSUFFIX',
     83                                       target_scanner = ProgramScanner,
     84                                       src_suffix = '$PYEXTOBJSUFFIX',
     85                                       src_builder = 'PythonObject')
     86         env['BUILDERS']['PythonExtension'] = pyext
     87 
     88     return pyext
     89 
     90 def pyext_coms(platform):
     91     """Return PYEXTCCCOM, PYEXTCXXCOM and PYEXTLINKCOM for the given
     92     platform."""
     93     if platform == 'win32':
     94         pyext_cccom = "$PYEXTCC /Fo$TARGET /c $PYEXTCCSHARED "\
     95                       "$PYEXTCFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\
     96                       "$_PYEXTCPPINCFLAGS $SOURCES"
     97         pyext_cxxcom = "$PYEXTCXX /Fo$TARGET /c $PYEXTCSHARED "\
     98                        "$PYEXTCXXFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\
     99                        "$_PYEXTCPPINCFLAGS $SOURCES"
    100         pyext_linkcom = '${TEMPFILE("$PYEXTLINK $PYEXTLINKFLAGS '\
    101                         '/OUT:$TARGET.windows $( $_LIBDIRFLAGS $) '\
    102                         '$_LIBFLAGS $_PYEXTRUNTIME $SOURCES.windows")}'
    103     else:
    104         pyext_cccom = "$PYEXTCC -o $TARGET -c $PYEXTCCSHARED "\
    105                       "$PYEXTCFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\
    106                       "$_PYEXTCPPINCFLAGS $SOURCES"
    107         pyext_cxxcom = "$PYEXTCXX -o $TARGET -c $PYEXTCSHARED "\
    108                        "$PYEXTCXXFLAGS $PYEXTCCFLAGS $_CCCOMCOM "\
    109                        "$_PYEXTCPPINCFLAGS $SOURCES"
    110         pyext_linkcom = "$PYEXTLINK -o $TARGET $PYEXTLINKFLAGS "\
    111                         "$SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_PYEXTRUNTIME"
    112 
    113     if platform == 'darwin':
    114         pyext_linkcom += ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
    115 
    116     return pyext_cccom, pyext_cxxcom, pyext_linkcom
    117 
    118 def set_basic_vars(env):
    119     # Set construction variables which are independant on whether we are using
    120     # distutils or not.
    121     env['PYEXTCPPPATH'] = SCons.Util.CLVar('$PYEXTINCPATH')
    122 
    123     env['_PYEXTCPPINCFLAGS'] = '$( ${_concat(INCPREFIX, PYEXTCPPPATH, '\
    124                                'INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
    125     env['PYEXTOBJSUFFIX'] = '$SHOBJSUFFIX'
    126     env['PYEXTOBJPREFIX'] = '$SHOBJPREFIX'
    127 
    128     env['PYEXTRUNTIME']   = SCons.Util.CLVar("")
    129     # XXX: this should be handled with different flags
    130     env['_PYEXTRUNTIME']  = '$( ${_concat(LIBLINKPREFIX, PYEXTRUNTIME, '\
    131                           'LIBLINKSUFFIX, __env__)} $)'
    132     # XXX: This won't work in all cases (using mingw, for example). To make
    133     # this work, we need to know whether PYEXTCC accepts /c and /Fo or -c -o.
    134     # This is difficult with the current way tools work in scons.
    135     pycc, pycxx, pylink = pyext_coms(sys.platform)
    136                             
    137     env['PYEXTLINKFLAGSEND'] = SCons.Util.CLVar('$LINKFLAGSEND')
    138 
    139     env['PYEXTCCCOM'] = pycc
    140     env['PYEXTCXXCOM'] = pycxx
    141     env['PYEXTLINKCOM'] = pylink
    142 
    143 def _set_configuration_nodistutils(env):
    144     # Set env variables to sensible values when not using distutils
    145     def_cfg = {'PYEXTCC' : '$SHCC',
    146                'PYEXTCFLAGS' : '$SHCFLAGS',
    147                'PYEXTCCFLAGS' : '$SHCCFLAGS',
    148                'PYEXTCXX' : '$SHCXX',
    149                'PYEXTCXXFLAGS' : '$SHCXXFLAGS',
    150                'PYEXTLINK' : '$LDMODULE',
    151                'PYEXTSUFFIX' : '$LDMODULESUFFIX',
    152                'PYEXTPREFIX' : ''}
    153 
    154     if sys.platform == 'darwin':
    155         def_cfg['PYEXTSUFFIX'] = '.so'
    156 
    157     for k, v in def_cfg.items():
    158         ifnotset(env, k, v)
    159 
    160     ifnotset(env, 'PYEXT_ALLOW_UNDEFINED', 
    161              SCons.Util.CLVar('$ALLOW_UNDEFINED'))
    162     ifnotset(env, 'PYEXTLINKFLAGS', SCons.Util.CLVar('$LDMODULEFLAGS'))
    163 
    164     env.AppendUnique(PYEXTLINKFLAGS = env['PYEXT_ALLOW_UNDEFINED'])
    165 
    166 def ifnotset(env, name, value):
    167     if not env.has_key(name):
    168         env[name] = value
    169 
    170 def set_configuration(env, use_distutils):
    171     """Set construction variables which are platform dependants.
    172 
    173     If use_distutils == True, use distutils configuration. Otherwise, use
    174     'sensible' default.
    175 
    176     Any variable already defined is untouched."""
    177 
    178     # We define commands as strings so that we can either execute them using
    179     # eval (same python for scons and distutils) or by executing them through
    180     # the shell.
    181     dist_cfg = {'PYEXTCC': ("sysconfig.get_config_var('CC')", False), 
    182                 'PYEXTCFLAGS': ("sysconfig.get_config_var('CFLAGS')", True), 
    183                 'PYEXTCCSHARED': ("sysconfig.get_config_var('CCSHARED')", False), 
    184                 'PYEXTLINKFLAGS': ("sysconfig.get_config_var('LDFLAGS')", True), 
    185                 'PYEXTLINK': ("sysconfig.get_config_var('LDSHARED')", False), 
    186                 'PYEXTINCPATH': ("sysconfig.get_python_inc()", False), 
    187                 'PYEXTSUFFIX': ("sysconfig.get_config_var('SO')", False)}
    188 
    189     from distutils import sysconfig
    190 
    191     # We set the python path even when not using distutils, because we rarely
    192     # want to change this, even if not using distutils
    193     ifnotset(env, 'PYEXTINCPATH', sysconfig.get_python_inc())
    194 
    195     if use_distutils:
    196         for k, (v, should_split) in dist_cfg.items():
    197             val = eval(v)
    198             if should_split:
    199                 val = val.split()
    200             ifnotset(env, k, val)
    201     else:
    202         _set_configuration_nodistutils(env)
    203 
    204 def generate(env):
    205     """Add Builders and construction variables for python extensions to an
    206     Environment."""
    207 
    208     if not env.has_key('PYEXT_USE_DISTUTILS'):
    209         env['PYEXT_USE_DISTUTILS'] = False
    210 
    211     # This sets all constructions variables used for pyext builders. 
    212     set_basic_vars(env)
    213 
    214     set_configuration(env, env['PYEXT_USE_DISTUTILS'])
    215 
    216     # Create the PythonObject builder
    217     pyobj = createPythonObjectBuilder(env)
    218     action = SCons.Action.Action("$PYEXTCCCOM", "$PYEXTCCCOMSTR")
    219     pyobj.add_emitter('.c', SCons.Defaults.SharedObjectEmitter)
    220     pyobj.add_action('.c', action)
    221 
    222     action = SCons.Action.Action("$PYEXTCXXCOM", "$PYEXTCXXCOMSTR")
    223     pyobj.add_emitter('$CXXFILESUFFIX', SCons.Defaults.SharedObjectEmitter)
    224     pyobj.add_action('$CXXFILESUFFIX', action)
    225 
    226     # Create the PythonExtension builder
    227     createPythonExtensionBuilder(env)
    228 
    229 def exists(env):
    230     try:
    231         # This is not quite right: if someone defines all variables by himself,
    232         # it would work without distutils
    233         from distutils import sysconfig
    234         return True
    235     except ImportError:
    236         return False
    237