Preliminary scons support (in Tools dir)
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Wed, 21 Oct 2009 08:31:53 +0000 (10:31 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Wed, 21 Oct 2009 08:31:53 +0000 (10:31 +0200)
Tools/site_scons/site_tools/cython.py [new file with mode: 0644]
Tools/site_scons/site_tools/pyext.py [new file with mode: 0644]

diff --git a/Tools/site_scons/site_tools/cython.py b/Tools/site_scons/site_tools/cython.py
new file mode 100644 (file)
index 0000000..6e5151b
--- /dev/null
@@ -0,0 +1,67 @@
+"""
+Tool to run Cython files (.pyx) into .c and .cpp.
+
+TODO:
+ - Add support for dynamically selecting in-process Cython
+   through CYTHONINPROCESS variable.
+ - Have a CYTHONCPP option which turns on C++ in flags and
+   changes output extension at the same time
+
+VARIABLES:
+ - CYTHON - The path to the "cython" command line tool.
+ - CYTHONFLAGS - Flags to pass to the "cython" command line tool.
+
+AUTHORS:
+ - David Cournapeau
+ - Dag Sverre Seljebotn
+
+"""
+import SCons
+from SCons.Builder import Builder
+from SCons.Action import Action
+
+#def cython_action(target, source, env):
+#    print target, source, env
+#    from Cython.Compiler.Main import compile as cython_compile
+#    res = cython_compile(str(source[0]))
+
+cythonAction = Action("$CYTHONCOM")
+
+def create_builder(env):
+    try:
+        cython = env['BUILDERS']['Cython']
+    except KeyError:
+        cython = SCons.Builder.Builder(
+                  action = cythonAction,
+                  emitter = {},
+                  suffix = cython_suffix_emitter,
+                  single_source = 1)
+        env['BUILDERS']['Cython'] = cython
+
+    return cython
+
+def cython_suffix_emitter(env, source):
+    print 'emitter called'
+    return "$CYTHONCFILESUFFIX"
+
+def generate(env):
+    env["CYTHON"] = "cython"
+    env["CYTHONCOM"] = "$CYTHON $CYTHONFLAGS -o $TARGET $SOURCE"
+    env["CYTHONCFILESUFFIX"] = ".c"
+
+    c_file, cxx_file = SCons.Tool.createCFileBuilders(env)
+
+    c_file.suffix['.pyx'] = cython_suffix_emitter
+    c_file.add_action('.pyx', cythonAction)
+
+    c_file.suffix['.py'] = cython_suffix_emitter
+    c_file.add_action('.py', cythonAction)
+
+    create_builder(env)
+
+def exists(env):
+    try:
+#        import Cython
+        return True
+    except ImportError:
+        return False
diff --git a/Tools/site_scons/site_tools/pyext.py b/Tools/site_scons/site_tools/pyext.py
new file mode 100644 (file)
index 0000000..6079975
--- /dev/null
@@ -0,0 +1,233 @@
+"""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')", 
+                'PYEXTCFLAGS': "sysconfig.get_config_var('CFLAGS')", 
+                'PYEXTCCSHARED': "sysconfig.get_config_var('CCSHARED')", 
+                'PYEXTLINKFLAGS': "sysconfig.get_config_var('LDFLAGS')", 
+                'PYEXTLINK': "sysconfig.get_config_var('LDSHARED')", 
+                'PYEXTINCPATH': "sysconfig.get_python_inc()", 
+                'PYEXTSUFFIX': "sysconfig.get_config_var('SO')"}
+
+    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 in dist_cfg.items():
+            ifnotset(env, k, eval(v))
+    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