Please note:The SCons wiki is in read-only mode due to ongoing spam/DoS issues. Also, new account creation is currently disabled. We are looking into alternative wiki hosts.

Building Python Extensions with SCons

Python provides the distutils tools to build Python extension modules.

This first example is very simple for a beginner new to SWIG and SCons, the sources are from the "SWIG tutorial":

   1 import distutils.sysconfig
   2 env = Environment(SWIGFLAGS=['-python'],
   3                   CPPPATH=[distutils.sysconfig.get_python_inc()],
   4                   SHLIBPREFIX="")
   5 env.SharedLibrary('_example.so', ['example.c', 'example.i'])

This example shows a way of using the distutils package build extension modules with SCons.

   1 Import("tool_prefix")
   2 import distutils.sysconfig, os
   3 vars = distutils.sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO')
   4 for i in range(len(vars)):
   5     if vars[i] is None:
   6         vars[i] = ""
   7 (cc, cxx, opt, basecflags, ccshared, ldshared, so_ext) = vars
   8 lib = SharedLibrary("dparser_swigc",
   9                     ["pydparser.c", "make_tables.c", "dparser_wrap.c"],
  10                     LIBS=['mkdparse', 'dparse'],
  11                     LIBPATH=["../"],
  12                     CC=cc,
  13                     SHLINK=ldshared,
  14                     SHLINKFLAGS=[],
  15                     SHLIBPREFIX="",
  16                     SHLIBSUFFIX=so_ext,
  17                     CPPPATH=[distutils.sysconfig.get_python_inc()],
  18                     CPPDEFINES={"SWIG_GLOBAL":None},
  19                     CPPFLAGS=basecflags + " " + opt)
  20 if type(lib) == type([]): lib = lib[0]
  21 dp1 = Install(os.path.join(tool_prefix, "lib"), "dparser.py")
  22 dp2 = Install(os.path.join(tool_prefix, "lib"), lib)
  23 Depends(dp1, dp2)

The following is a boost.python example to compile the Hello.cpp example. Needs to be expanded to other platforms and compilers. This example creates a compile environment to set the parameters.

   1 # Example build for Boost.python example hello
   2 # Tested on Windows VC7 (VC6.0 possible see below?) with Python 2.3
   3 # must put debug multi-threaded  boost_python.dll and .lib in current directory.
   4 # Currently compiles a debug version
   5 # following line gave me an error
   6 #Import("tool_prefix")
   7 import distutils.sysconfig, os
   8 # XXX: these should just set the defaults and let user override them with an Environment var
   9 boost_prefix=r"D:\usr\boost_1_33_1"
  10 boost_libdir=boost_prefix + "/libs/..../shared-linkable-true/"
  11 def TOOL_BOOST_DISTUTILS(env):
  12     """Add stuff needed to build Python extensions with boost.  """
  13     vars = distutils.sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO')
  14     for i in range(len(vars)):
  15         if vars[i] is None:
  16             vars[i] = ""
  17     (cc, cxx, opt, basecflags, ccshared, ldshared, so_ext) = vars
  18     #For some reason all but so_ext are zero
  19     #print 'cc',cc, 'cxx',cxx, 'opt',opt
  20     #print 'basecflags',basecflags, 'ccshared',ccshared,
  21     #print 'ldshared',ldshared, 'so_ext',so_ext
  22     #print distutils.sysconfig.get_python_inc()
  23     env.AppendUnique(CPPPATH=[distutils.sysconfig.get_python_inc(),boost_prefix])
  24     env.AppendUnique(CXXFLAGS=Split("/Zm800 -nologo /EHsc /DBOOST_PYTHON_DYNAMIC_LIB /Z7 /Od /Ob0 /EHsc /GR /MDd /Op  /wd4675 /Zc:forScope /Zc:wchar_t"))
  25     # Use the following for VC6.0
  26     #env.AppendUnique(CXXFLAGS=Split("/Zm800 /nologo /DBOOST_PYTHON_DYNAMIC_LIB /Z7 /Od /Ob0 /EHsc /GR /MDd"))
  27     env.AppendUnique(LIBPATH=[boost_libdir, distutils.sysconfig.PREFIX+"/libs"])
  28     env.AppendUnique(LIBS="boost_python")
  29     env['SHLIBPREFIX']=""   #gets rid of lib prefix
  30     env['SHLIBSUFFIX']=so_ext
  31 Default('.')
  32 env=Environment(tools=['default', TOOL_BOOST_DISTUTILS])
  33 hello = env.SharedLibrary(target='hello', source=['hello.cpp',])
  34 #TODO add install line

AlexanderBelchenko have created recipe to build Pyrex extensions for Python based on the last example. See PyrexPythonExtensions page for details.

Julien Boeuf noted that if you try to run the scons example on a Mac, it won't work because what you need on the Mac is a 'bundle' and not a dylib. The way to do it is to add the appropriate flags to your environment. It is also a good idea to do a universal build for both powerpc and x86 architectures. Then Greg Noel pointed out that Gary Oberbrunner has added a "LoadableModule" that captures the essence of a bundle in a platform-neutral way. You can use that together with the FRAMEWORKSFLAGS to get a much simpler invocation.

For the record, here's a fragment from a SConscript of Noel's that builds a SWIG library on Mac, Linux, Solaris, and other Unix-like platforms; it could be simplified a bit to remove the options for his specific configuration. It also doesn't include the rule to build sample.i from the *.h files; I leave that as an exercise for the reader.

# SWIG library for Python
## FIXME: produces sample.py as a side-effect which is not cleaned
Alias('swig', env.LoadableModule('sample', 'sample.i',
     SWIGFLAGS = '-c++ -python -shadow -Wall'.split(),
     CPPPATH = ['.', os.path.join(sys.prefix, 'include',
         'python%d.%d'%(sys.version_info[0],sys.version_info[1]))],
     CCFLAGS = '-O', LIBS = lib, OBJPREFIX = 'tmp/',
     LDMODULEPREFIX='_', LDMODULESUFFIX = '.so',
     FRAMEWORKSFLAGS = '-flat_namespace -undefined suppress',
     )
)

PythonExtensions (last edited 2008-12-04 14:33:20 by AlexanderBelchenko)