Commits

ariovistus committed 22e9fc8

hello world!

trying to resurrect pyd for a recent (~ dmd2.055) version of gdc.

this is a d2 only build, and I'm hoping mostly to get it to work with
python 2.7, although I am trying to make the python.d valid all the way back to 2.4.

Comments (0)

Files changed (165)

+syntax: glob
+*.pyc
Empty file added.

build_manifest.py

+import os, os.path
+
+
+FORBIDDEN_EXTENSIONS = [
+    '.pyc', '.pyo', # Python bytecode
+    '.marks', # jEdit bookmark files
+    '.map', # Created automatically by the DMD compiler; needn't distribute.
+    '.swp', # Vim swap files
+  ]
+
+FORBIDDEN_DIRECTORIES = [
+    lambda d: d.lower() in ('.svn', 'cvs', 'build', 'dist'),
+    lambda d: d.startswith('__'),
+  ]
+
+INCLUDE_ONLY_IN_SOURCE_DISTRIBUTION = [
+    'build_manifest.py',
+    'setup.py',
+  ]
+
+EXCLUDE_PATHS = [
+    'MANIFEST',
+  ]
+
+
+def buildManifest(outputStream, isForSourceDist):
+    includedPaths, excludedPaths = listFiles(isForSourceDist)
+    for path in includedPaths:
+        # print >> outputStream, 'include "%s"' % convertPathToDistutilsStandard(path)
+        print >> outputStream, convertPathToDistutilsStandard(path)
+
+
+def convertPathToDistutilsStandard(path):
+    return path.replace(os.sep, '/')
+
+
+def listFiles(isForSourceDist):
+    curDirAndSep = os.curdir + os.sep
+
+    includedPaths = []
+    excludedPaths = []
+    for rootPath, dirs, files in os.walk(os.curdir):
+        if rootPath.startswith(os.curdir + os.sep):
+            rootPath = rootPath[len(os.curdir + os.sep):]
+        elif rootPath.startswith(os.curdir):
+            rootPath = rootPath[len(os.curdir):]
+
+        # The os.walk interface specifies that destructively modifying dirs
+        # will influence which subdirs are visited, so we determine which
+        # subdirs are forbidden and remove them from dirs.
+        for subDir in dirs[:]:
+            for filterFunc in FORBIDDEN_DIRECTORIES:
+                if filterFunc(subDir):
+                    dirs.remove(subDir)
+
+        for f in sorted(files):
+            fPath = os.path.join(rootPath, f)
+            if os.path.splitext(f)[1].lower() in FORBIDDEN_EXTENSIONS:
+                excludedPaths.append(fPath)
+            else:
+                includedPaths.append(fPath)
+
+    if not isForSourceDist:
+        for path in INCLUDE_ONLY_IN_SOURCE_DISTRIBUTION:
+            if path in includedPaths:
+                includedPaths.remove(path)
+                excludedPaths.append(path)
+
+    for path in EXCLUDE_PATHS:
+        if path in includedPaths:
+            includedPaths.remove(path)
+            excludedPaths.append(path)
+
+    return includedPaths, excludedPaths
+
+
+if __name__ == '__main__':
+    import sys
+    buildManifest(sys.stdout, True)
+Python/D bindings:
+Deja Augustine, David Rushby, Kirk McDonald
+
+CeleriD:
+David Rushby, Kirk McDonald
+
+Pyd:
+Kirk McDonald
+
+meta:
+Tomasz Stachowiak, Don Clugston, Kirk McDonald
+
+StackThreads:
+Mikola Lysenko, Daniel Keep, Lars Ivar Igesund
+# DSR:2005.10.27.23.51
+
+# XXX:
+# These two will have to wait until DMD can create shared libraries on Linux,
+# because DSR doesn't have (the non-free version of) MSVC 2003, which is
+# necessary to create a debug build or a UCS4 build of Python 2.4 on Windows:
+# - Handle distutils debug builds responsibly (make sure both -debug and -g are
+#   passed through to DMD, even if optimizations are requested).  Also make
+#   sure that extensions built with this module work under debug builds of
+#   Python.
+# - Try out a UCS4 build of Python to make sure that works.
+
+import os, os.path, sys
+
+from distutils import ccompiler as cc
+from distutils.ccompiler import gen_lib_options
+from distutils.errors import (
+    DistutilsExecError, DistutilsFileError, DistutilsPlatformError,
+    CompileError, LibError, LinkError, UnknownFileError
+)
+
+_isPlatWin = sys.platform.lower().startswith('win')
+
+_infraDir = os.path.join(os.path.dirname(__file__), 'infrastructure')
+
+from pyd_support import make_pydmain, make_pyddef
+
+_pydFiles = [
+    'class_wrap.d',
+    'ctor_wrap.d',
+    'def.d',
+    'dg_convert.d',
+    'exception.d',
+    'func_wrap.d',
+    'iteration.d',
+    'lib_abstract.d',
+    'make_object.d',
+    'make_wrapper.d',
+    'op_wrap.d',
+    'pyd.d',
+    'pydobject.d',
+    'struct_wrap.d',
+]
+
+_stFiles = [
+    'coroutine.d',
+    'stackcontext.d',
+    'stackthread.d',
+    'tls.d',
+]
+
+_metaFiles = [
+    'Default.d',
+    'Demangle.d',
+    'Nameof.d',
+    'Util.d',
+]
+
+_pyVerXDotY = '.'.join(str(v) for v in sys.version_info[:2]) # e.g., '2.4'
+_pyVerXY = _pyVerXDotY.replace('.', '') # e.g., '24'
+
+
+class DCompiler(cc.CCompiler):
+
+    src_extensions = ['.d']
+    obj_extension = (_isPlatWin and '.obj') or '.o'
+    static_lib_extension = (_isPlatWin and '.lib') or '.a'
+    shared_lib_extension = (_isPlatWin and '.pyd') or '.so'
+    static_lib_format = (_isPlatWin and '%s%s') or 'lib%s%s'
+    shared_lib_format = '%s%s'
+    exe_extension = (_isPlatWin and '.exe') or ''
+
+    def __init__(self, *args, **kwargs):
+        cc.CCompiler.__init__(self, *args, **kwargs)
+        # Get DMD/GDC specific info
+        self._initialize()
+        # _binpath
+        try:
+            dBin = os.environ[self._env_var]
+            if not os.path.isfile(dBin):
+                self.warn("Environment variable %s provided, but file '%s' does not exist." % (self._env_var, dBin))
+                raise KeyError
+        except KeyError:
+            if _isPlatWin:
+                # The environment variable wasn't supplied, so search the PATH.
+                # Windows requires the full path for reasons that escape me at
+                # the moment.
+                dBin = _findInPath(self.compiler_type + self.exe_extension)
+                if dBin is None:
+                    raise DistutilsFileError('You must either set the %s'
+                        ' environment variable to the full path of the %s'
+                        ' executable, or place the executable on the PATH.' %
+                        (self._env_var, self.compiler_type)
+                    )
+            else:
+                # Just run it via the PATH directly in Linux
+                dBin = self.compiler_type
+        self._binpath = dBin
+        # _unicodeOpt
+        self._unicodeOpt = self._versionOpt % ('Python_Unicode_UCS' + ((sys.maxunicode == 0xFFFF and '2') or '4'))
+
+    def _initialize(self):
+        # It is intended that this method be implemented by subclasses.
+        raise NotImplementedError, "Cannot initialize DCompiler, use DMDDCompiler or GDCDCompiler instead."
+
+    def _def_file(self, output_dir, output_filename):
+        """A list of options used to tell the linker how to make a dll/so. In
+        DMD, it is the .def file. In GDC, it is
+        ['-shared', '-Wl,-soname,blah.so'] or similar."""
+        raise NotImplementedError, "Cannot initialize DCompiler, use DMDDCompiler or GDCDCompiler instead."
+
+    def _lib_file(self, libraries):
+        return ''
+
+    def find_library_file(self, dirs, lib, debug=0):
+        shared_f = self.library_filename(lib, lib_type='shared')
+        static_f = self.library_filename(lib, lib_type='static')
+
+        for dir in dirs:
+            shared = os.path.join(dir, shared_f)
+            static = os.path.join(dir, static_f)
+
+            if os.path.exists(shared):
+                return shared
+            elif os.path.exists(static):
+                return static
+
+        return None
+
+    def compile(self, sources,
+        output_dir=None, macros=None, include_dirs=None, debug=0,
+        extra_preargs=None, extra_postargs=None, depends=None
+    ):
+        macros = macros or []
+        include_dirs = include_dirs or []
+        extra_preargs = extra_preargs or []
+        extra_postargs = extra_postargs or []
+
+        if not os.path.exists(output_dir):
+            os.makedirs(output_dir)
+
+        binpath = _qp(self._binpath)
+        compileOpts = self._compileOpts
+        outputOpts = self._outputOpts
+
+        includePathOpts = []
+
+        # All object files will be placed in one of three directories:
+        # infra   - All of the infrastructure's object files.
+        # project - The project's own object files.
+        # outside - Any source files specified by the project which are not
+        #           contained in the project's own directory.
+        orig_sources = sources
+        sources = []
+        for source in orig_sources:
+            if os.path.abspath(source).startswith(os.getcwd()):
+                sources.append((source, 'project'))
+            else:
+                sources.append((source, 'outside'))
+
+        # To sources, add the appropriate D header file python.d, as well as
+        # any platform-specific boilerplate.
+        pythonHeaderPath = os.path.join(_infraDir, 'python', 'python.d')
+        # Add the python header's directory to the include path
+        includePathOpts += self._includeOpts
+        includePathOpts[-1] = includePathOpts[-1] % os.path.join(_infraDir, 'python')
+        if not os.path.isfile(pythonHeaderPath):
+            raise DistutilsPlatformError('Required D translation of Python'
+                ' header files "%s" is missing.' % pythonHeaderPath
+            )
+        sources.append((pythonHeaderPath, 'infra'))
+
+        # flags = (with_pyd, with_st, with_meta, with_main)
+        with_pyd, with_st, with_meta, with_main = [f for f, category in macros if category == 'aux'][0]
+        # And Pyd!
+        if with_pyd:
+            # If we're not using StackThreads, don't use iteration.d in Pyd
+            if not with_st or not self._st_support:
+                _pydFiles.remove('iteration.d');
+            for file in _pydFiles:
+                filePath = os.path.join(_infraDir, 'pyd', file)
+                if not os.path.isfile(filePath):
+                    raise DistutilsPlatformError("Required Pyd source file '%s' is"
+                        " missing." % filePath
+                    )
+                sources.append((filePath, 'infra'))
+        # If using PydMain, parse the template file
+        if with_main:
+            name = [n for n, category in macros if category == 'name'][0]
+            # Store the finished pydmain.d file alongside the object files
+            infra_output_dir = os.path.join(output_dir, 'infra')
+            if not os.path.exists(infra_output_dir):
+                os.makedirs(infra_output_dir)
+            mainFilename = os.path.join(infra_output_dir, 'pydmain.d')
+            make_pydmain(mainFilename, name)
+            sources.append((mainFilename, 'infra'))
+        # And StackThreads
+        if self._st_support and with_st:
+            for file in _stFiles:
+                filePath = os.path.join(_infraDir, 'st', file)
+                if not os.path.isfile(filePath):
+                    raise DistutilsPlatformError("Required StackThreads source"
+                        " file '%s' is missing." % filePath
+                    )
+                sources.append((filePath, 'infra'))
+            # Add the version conditional for st
+            macros.append(('Pyd_with_StackThreads', 'version'))
+        # And meta
+        if with_meta:
+            for file in _metaFiles:
+                filePath = os.path.join(_infraDir, 'meta', file)
+                if not os.path.isfile(filePath):
+                    raise DistutilsPlatformError("Required meta source file"
+                        " '%s' is missing." % filePath
+                    )
+                sources.append((filePath, 'infra'))
+        # Add the infraDir to the include path for pyd, st, and meta.
+        if True in (with_pyd, with_st, with_meta):
+            includePathOpts += self._includeOpts
+            includePathOpts[-1] = includePathOpts[-1] % os.path.join(_infraDir)
+        
+        # Add DLL/SO boilerplate code file.
+        if _isPlatWin:
+            boilerplatePath = os.path.join(_infraDir, 'd',
+                'python_dll_windows_boilerplate.d'
+            )
+        else:
+            boilerplatePath = os.path.join(_infraDir, 'd',
+                'python_so_linux_boilerplate.d'
+            )
+        if not os.path.isfile(boilerplatePath):
+            raise DistutilsFileError('Required supporting code file "%s"'
+                ' is missing.' % boilerplatePath
+            )
+        sources.append((boilerplatePath, 'infra'))
+
+        # Extension subclass DExtension will have packed any user-supplied
+        # version and debug flags into macros; we extract them and convert them
+        # into the appropriate command-line args.
+        versionFlags = [name for (name, category) in macros if category == 'version']
+        debugFlags = [name for (name, category) in macros if category == 'debug']
+        userVersionAndDebugOpts = (
+              [self._versionOpt % v for v in versionFlags] +
+              [self._debugOpt   % v for v in debugFlags]
+        )
+
+        # Python version option allows extension writer to take advantage of
+        # Python/C API features available only in recent version of Python with
+        # a version statement like:
+        #   version(Python_2_4_Or_Later) {
+        #     Py_ConvenientCallOnlyAvailableInPython24AndLater();
+        #   } else {
+        #     // Do it the hard way...
+        #   }
+        pythonVersionOpt = self._versionOpt % ('Python_%d_%d_Or_Later' % sys.version_info[:2])
+
+        # Optimization opts
+        args = [a.lower() for a in sys.argv[1:]]
+        optimize = ('-o' in args or '--optimize' in args)
+        if debug:
+            optimizationOpts = self._debugOptimizeOpts
+        elif optimize:
+            optimizationOpts = self._releaseOptimizeOpts
+        else:
+            optimizationOpts = self._defaultOptimizeOpts
+
+        print 'sources: ', [os.path.basename(s) for s, t in sources]
+
+        objFiles = []
+        for source, source_type in sources:
+            outOpts = outputOpts[:]
+            objFilename = os.path.splitext(source)[0] + self.obj_extension
+            if source_type == 'project':
+                objName = os.path.join(output_dir, 'project', objFilename)
+            elif source_type == 'outside':
+                objName = os.path.join(output_dir, 'outside', os.path.basename(objFilename))
+            else: # infra
+                objName = os.path.join(output_dir, 'infra', os.path.basename(objFilename))
+            if not os.path.exists(os.path.dirname(objName)):
+                os.makedirs(os.path.dirname(objName))
+            objFiles.append(objName)
+            outOpts[-1] = outOpts[-1] % _qp(objName)
+            cmdElements = (
+                [binpath] + extra_preargs + compileOpts +
+                [pythonVersionOpt, self._unicodeOpt] + optimizationOpts +
+                includePathOpts + outOpts + userVersionAndDebugOpts +
+                [_qp(source)] + extra_postargs
+            )
+            cmdElements = [el for el in cmdElements if el]
+            try:
+                self.spawn(cmdElements)
+            except DistutilsExecError, msg:
+                raise CompileError(msg)
+        return objFiles
+
+    def link (self,
+        target_desc, objects, output_filename,
+        output_dir=None,
+        libraries=None, library_dirs=None, runtime_library_dirs=None,
+        export_symbols=None, debug=0,
+        extra_preargs=None, extra_postargs=None,
+        build_temp=None, target_lang=None
+    ):
+        # Distutils defaults to None for "unspecified option list"; we want
+        # empty lists in that case (this substitution is done here in the body
+        # rather than by changing the default parameters in case distutils
+        # passes None explicitly).
+        libraries = libraries or []
+        library_dirs = library_dirs or []
+        runtime_library_dirs = runtime_library_dirs or []
+        export_symbols = export_symbols or []
+        extra_preargs = extra_preargs or []
+        extra_postargs = extra_postargs or []
+
+        binpath = self._binpath
+        outputOpts = self._outputOpts[:]
+        objectOpts = [_qp(fn) for fn in objects]
+
+        (objects, output_dir) = self._fix_object_args (objects, output_dir)
+        (libraries, library_dirs, runtime_library_dirs) = \
+            self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
+        if runtime_library_dirs:
+            self.warn('This CCompiler implementation does nothing with'
+                ' "runtime_library_dirs": ' + str(runtime_library_dirs)
+            )
+
+        if output_dir and os.path.basename(output_filename) == output_filename:
+            output_filename = os.path.join(output_dir, output_filename)
+        else:
+            if not output_filename:
+                raise DistutilsFileError, 'Neither output_dir nor' \
+                    ' output_filename was specified.'
+            output_dir = os.path.dirname(output_filename)
+            if not output_dir:
+                raise DistutilsFileError, 'Unable to guess output_dir on the'\
+                    ' bases of output_filename "%s" alone.' % output_filename
+
+        # Format the output filename option
+        # (-offilename in DMD, -o filename in GDC)
+        outputOpts[-1] = outputOpts[-1] % _qp(output_filename)
+
+        if not os.path.exists(output_dir):
+            os.makedirs(output_dir)
+
+        if not self._need_link(objects, output_filename):
+            print "All binary output files are up to date."
+            return
+
+        # The .def file (on Windows) or -shared and -soname (on Linux)
+        sharedOpts = self._def_file(build_temp, output_filename)
+
+        # The python .lib file, if needed
+        pythonLibOpt = self._lib_file(libraries)
+        if pythonLibOpt:
+            pythonLibOpt = _qp(pythonLibOpt)
+
+        if target_desc != cc.CCompiler.SHARED_OBJECT:
+            raise LinkError('This CCompiler implementation does not know'
+                ' how to link anything except an extension module (that is, a'
+                ' shared object file).'
+            )
+
+        # Library linkage options
+        print "library_dirs:", library_dirs
+        print "runtime_library_dirs:", runtime_library_dirs
+        print "libraries:", libraries
+        libOpts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries)
+
+        # Optimization opts
+        args = [a.lower() for a in sys.argv[1:]]
+        optimize = ('-o' in args or '--optimize' in args)
+        if debug:
+            optimizationOpts = self._debugOptimizeOpts
+        elif optimize:
+            optimizationOpts = self._releaseOptimizeOpts
+        else:
+            optimizationOpts = self._defaultOptimizeOpts
+
+        cmdElements = (
+            [binpath] + extra_preargs + self._linkOpts + optimizationOpts +
+            outputOpts + [pythonLibOpt] + objectOpts + libOpts + sharedOpts +
+            extra_postargs
+        )
+        cmdElements = [el for el in cmdElements if el]
+
+        try:
+            self.spawn(cmdElements)
+        except DistutilsExecError, msg:
+            raise CompileError(msg)
+
+class DMDDCompiler(DCompiler):
+    compiler_type = 'dmd'
+
+    executables = {
+        'preprocessor' : None,
+        'compiler'     : ['dmd'],
+        'compiler_so'  : ['dmd'],
+        'linker_so'    : ['dmd'],
+        'linker_exe'   : ['dmd'],
+    }
+
+    _env_var = 'DMD_BIN'
+
+    def _initialize(self):
+        # _compileOpts
+        self._compileOpts = ['-c']
+        # _outputOpts
+        self._outputOpts = ['-of%s']
+        # _linkOpts
+        self._linkOpts = []
+        # _includeOpts
+        self._includeOpts = ['-I%s']
+        # _versionOpt
+        self._versionOpt = '-version=%s'
+        # _debugOpt
+        self._debugOpt = '-debug=%s'
+        # _defaultOptimizeOpts
+        self._defaultOptimizeOpts = ['-debug']
+        # _debugOptimizeOpts
+        self._debugOptimizeOpts = self._defaultOptimizeOpts + ['-unittest', '-g']
+        # _releaseOptimizeOpts
+        self._releaseOptimizeOpts = ['-version=Optimized', '-release', '-O', '-inline']
+        # StackThreads support
+        self._st_support = True
+
+    #def link_opts(self, 
+
+    def _def_file(self, output_dir, output_filename):
+        if _isPlatWin:
+            # Automatically create a .def file:
+            defFilePath = os.path.join(output_dir, 'infra', 'python_dll_def.def')
+            make_pyddef(
+                defFilePath,
+                os.path.basename(output_filename)
+            )
+            return [defFilePath]
+        else:
+            return []
+
+    def _lib_file(self, libraries):
+        if _isPlatWin:
+            # The DMD-compatible .lib file can be generated with implib.exe
+            # (from the Digital Mars "Basic Utilities" package) using a command
+            # series similar to the following:
+            #   cd C:\Windows\system32
+            #   \path\to\dm\bin\implib.exe /system python24_digitalmars.lib python24.dll
+            #
+            # I chose not to incorporate automatic .lib generation into this
+            # code because Python X.Y releases are fairly infrequent, so it's
+            # more convenient to distribute a pre-extracted .lib file to the
+            # users and spare them the need for the "Basic Utilities" package.
+            pythonDMDLibPath = _qp(os.path.join(_infraDir, 'python',
+                'python%s_digitalmars.lib' % _pyVerXY
+            ))
+            if not os.path.isfile(pythonDMDLibPath):
+                raise DistutilsFileError('The DMD-compatible Python .lib file'
+                    ' which should be located at "%s" is missing.  Try'
+                    ' downloading a more recent version of celeriD that'
+                    ' contains a .lib file appropriate for your Python version.'
+                    % pythonDMDLibPath
+                )
+            pythonLibOpt = _qp(pythonDMDLibPath)
+
+            # distutils will normally request that the library 'pythonXY' be
+            # linked against.  Since D requires a different .lib file from the
+            # one used by the C compiler that built Python, and we've just
+            # dealt with that requirement, we take the liberty of removing the
+            # distutils-requested pythonXY.lib.
+            if 'python' + _pyVerXY in libraries:
+                libraries.remove('python' + _pyVerXY)
+            return pythonLibOpt
+        else:
+            return ''
+
+    def library_dir_option(self, dir):
+        self.warn("Don't know how to set library search path for DMD.")
+        #raise DistutilsPlatformError, "Don't know how to set library search path for DMD."
+
+    def runtime_library_dir_option(self, dir):
+        self.warn("Don't know how to set runtime library search path for DMD.")
+        #raise DistutilsPlayformError, "Don't know how to set runtime library search path for DMD."
+
+    def library_option(self, lib):
+        if _isPlatWin:
+            return self.library_filename(lib)
+        else:
+            return '-L-l' + lib
+
+class GDCDCompiler(DCompiler):
+    compiler_type = 'gdc'
+
+    executables = {
+        'preprocessor' : None,
+        'compiler'     : ['gdc'],
+        'compiler_so'  : ['gdc'],
+        'linker_so'    : ['gdc'],
+        'linker_exe'   : ['gdc'],
+    }
+
+    _env_var = 'GDC_BIN'
+
+    def _initialize(self):
+        # _compileOpts
+        self._compileOpts = ['-fPIC', '-c']
+        # _outputOpts
+        self._outputOpts = ['-o', '%s']
+        # _linkOpts
+        self._linkOpts = ['-fPIC', '-nostartfiles', '-shared']
+        # _includeOpts
+        self._includeOpts = ['-I', '%s']
+        # _versionOpt
+        self._versionOpt = '-fversion=%s'
+        # _debugOpt
+        self._debugOpt = '-fdebug=%s'
+        # _defaultOptimizeOpts
+        self._defaultOptimizeOpts = ['-fdebug']
+        # _debugOptimizeOpts
+        self._debugOptimizeOpts = self._defaultOptimizeOpts + ['-g', '-funittest']
+        # _releaseOptimizeOpts
+        self._releaseOptimizeOpts = ['-fversion=Optimized', '-frelease', '-O3', '-finline-functions']
+        # StackThreads support
+        self._st_support = False
+
+    def _def_file(self, output_dir, output_filename):
+        return ['-Wl,-soname,' + os.path.basename(output_filename)]
+
+    def library_dir_option(self, dir):
+        return '-L' + dir
+
+    def runtime_library_dir_option(self, dir):
+        return '-Wl,-R' + dir
+
+    def library_option(self, lib):
+        return '-l' + lib
+
+# Utility functions:
+def _findInPath(fileName, startIn=None):
+    # Find a file named fileName in the PATH, starting in startIn.
+    try:
+        path = os.environ['PATH']
+    except KeyError:
+        pass
+    else:
+        pathDirs = path.split(os.pathsep)
+        if startIn:
+            if startIn in pathDirs:
+                pathDirs.remove(startIn)
+            pathDirs.insert(0, startIn)
+
+        for pd in pathDirs:
+            tentativePath = os.path.join(pd, fileName)
+            if os.path.isfile(tentativePath):
+                return tentativePath
+
+    return None
+
+
+def _qp(path): # If path contains any whitespace, quote it.
+    if len(path.split()) == 1:
+        return path
+    else:
+        return '"%s"' % path

examples/arraytest/arraytest.d

+module arraytest;
+
+import pyd.pyd;
+import std.stdio : writefln, writef;
+import std.string : format, toString;
+
+class Foo {
+    int i;
+    this(int j) { i = j; }
+    void bar() {
+        writefln("Foo.bar: %s", i);
+    }
+    char[] toString() {
+        return "{" ~ .toString(i) ~ "}";
+    }
+}
+
+Foo[] global_array;
+
+Foo[] get() {
+    writefln("get: %s", global_array);
+    return global_array;
+}
+void set(Foo[] a) {
+    writefln("set: a: %s, global: %s", a, global_array);
+    global_array = a;
+    writefln("set: global now: %s", global_array);
+}
+Foo test() {
+    return new Foo(10);
+}
+
+extern(C) void PydMain() {
+    global_array.length = 5;
+    for (int i=0; i<5; ++i) {
+        global_array[i] = new Foo(i);
+    }
+    def!(get);
+    def!(set);
+    def!(test);
+    module_init();
+    wrap_class!(
+        Foo,
+        Init!(void function(int)),
+        Repr!(Foo.toString),
+        Def!(Foo.bar)
+    );
+}

examples/arraytest/readme.txt

+This is an example of using arrays with Pyd.
+
+Execute the conventional distutils command
+    python setup.py build
+to build.
+
+Then execute
+    python test.py
+to exercise this example extension.

examples/arraytest/setup.py

+from celerid.support import setup, Extension
+
+projName = 'arraytest'
+
+setup(
+    name=projName,
+    version='0.1',
+    ext_modules=[
+        Extension(projName, ['arraytest.d'])
+    ],
+)

examples/arraytest/test.py

+import os.path, sys
+import distutils.util
+
+# Append the directory in which the binaries were placed to Python's sys.path,
+# then import the D DLL.
+libDir = os.path.join('build', 'lib.%s-%s' % (
+    distutils.util.get_platform(),
+    '.'.join(str(v) for v in sys.version_info[:2])
+))
+sys.path.append(os.path.abspath(libDir))
+from arraytest import Foo, get, set, test
+
+#set([Foo(1), Foo(2), Foo(3)])
+print ">>> get()"
+print `get()`
+print ">>> set([Foo(10), Foo(20)])"
+set([Foo(10), Foo(20)])
+print ">>> get()"
+print `get()`
+

examples/hello/hello.d

+// A minimal "hello world" Pyd module.
+module hello;
+
+import pyd.pyd;
+import std.stdio;
+
+void hello() {
+    writefln("Hello, world!");
+}
+
+extern(C) void PydMain() {
+    def!(hello);
+    module_init();
+}

examples/hello/makefile

+all: 
+	echo 'import sys; sys.path.append("../../build/lib/");' > tsetup.py
+	cat setup.py >> tsetup.py
+	python tsetup.py build

examples/hello/readme.txt

+This is an example of a simple, one-function Python extension with Pyd.
+
+Execute the conventional distutils command
+    python setup.py build
+to build.
+
+Then execute
+    python test.py
+to exercise this example extension.

examples/hello/setup.py

+from celerid.support import setup, Extension
+
+projName = 'hello'
+
+setup(
+    name=projName,
+    version='0.1',
+    ext_modules=[
+        Extension(projName, ['hello.d'])
+    ],
+)

examples/hello/test.py

+import os.path, sys
+import distutils.util
+
+# Append the directory in which the binaries were placed to Python's sys.path,
+# then import the D DLL.
+libDir = os.path.join('build', 'lib.%s-%s' % (
+    distutils.util.get_platform(),
+    '.'.join(str(v) for v in sys.version_info[:2])
+))
+sys.path.append(os.path.abspath(libDir))
+import hello
+
+hello.hello()
+

examples/inherit/inherit.d

+module inherit;
+
+import pyd.pyd;
+import std.stdio;
+
+class Base {
+    this(int i) { writefln("Base.this(): ", i); }
+    void foo() {
+        writefln("Base.foo");
+    }
+    void bar() {
+        writefln("Base.bar");
+    }
+}
+
+class Derived : Base {
+    this(int i) { super(i); writefln("Derived.this(): ", i); }
+    void foo() {
+        writefln("Derived.foo");
+    }
+}
+
+void call_poly(Base b) {
+    writefln("call_poly:");
+    b.foo();
+}
+
+Base b1, b2, b3;
+
+Base return_poly_base() {
+    if (b1 is null) b1 = new Base(1);
+    return b1;
+}
+
+Base return_poly_derived() {
+    if (b2 is null) b2 = new Derived(2);
+    return b2;
+}
+
+extern(C) void PydMain() {
+    def!(call_poly);
+    def!(return_poly_base);
+    def!(return_poly_derived);
+
+    module_init();
+
+    wrap_class!(
+        Base,
+        Init!(void function(int)),
+        Def!(Base.foo),
+        Def!(Base.bar)
+    );
+
+    wrap_class!(
+        Derived,
+        Init!(void function(int)),
+        Def!(Derived.foo)
+    );
+}
+

examples/inherit/readme.txt

+This example illustrates the basic automatic inheritance support provided by
+Pyd.
+
+Execute the conventional distutils command
+    python setup.py build
+to build.
+
+Then execute
+    python test.py
+to exercise this example extension.

examples/inherit/setup.py

+from celerid.support import setup, Extension
+
+projName = 'inherit'
+
+setup(
+    name=projName,
+    version='0.1',
+    ext_modules=[
+        Extension(projName, ['inherit.d'])
+    ],
+)

examples/inherit/test.py

+import os.path, sys
+import distutils.util
+
+# Append the directory in which the binaries were placed to Python's sys.path,
+# then import the D DLL.
+libDir = os.path.join('build', 'lib.%s-%s' % (
+    distutils.util.get_platform(),
+    '.'.join(str(v) for v in sys.version_info[:2])
+))
+sys.path.append(os.path.abspath(libDir))
+
+import inherit
+
+b = inherit.Base(1)
+d = inherit.Derived(2)
+
+b.foo()
+b.bar()
+d.foo()
+d.bar()
+
+print "issubclass(inherit.Derived, inherit.Base)"
+print issubclass(inherit.Derived, inherit.Base)
+
+inherit.call_poly(b)
+inherit.call_poly(d)
+
+#w = inherit.WrapDerive()
+#inherit.call_poly(w)
+
+class PyClass(inherit.Derived):
+    def foo(self):
+        print 'PyClass.foo'
+
+p = PyClass(3)
+#print "The basic inheritance support breaks down here:"
+inherit.call_poly(p)
+
+print
+
+b1 = inherit.return_poly_base()
+print "inherit.return_poly_base returned instance of Base"
+b1.foo()
+b1.bar()
+#assert type(b1) == inherit.Base
+b2 = inherit.return_poly_derived()
+b2a = inherit.return_poly_derived()
+print "inherit.return_poly_derived returned instance of Derived"
+#assert type(b2) == inherit.Derived
+print "inherit.return_poly_derived returned the same object twice"
+assert b2 is b2a
+
+print
+print '-------'
+print 'SUCCESS'
+print '-------'

examples/rawexample/rawexample.d

+// A module written to the raw Python/C API.
+module rawexample;
+
+import python;
+import std.stdio;
+
+static PyTypeObject Base_type;
+static PyTypeObject Derived_type;
+
+struct Base_object {
+    mixin PyObject_HEAD;
+}
+
+struct Derived_object {
+    mixin PyObject_HEAD;
+}
+
+extern(C)
+PyObject* Base_foo(PyObject* self, PyObject* args) {
+    writefln("Base.foo");
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+extern(C)
+PyObject* Base_bar(PyObject* self, PyObject* args) {
+    writefln("Base.bar");
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyMethodDef[] Base_methods = [
+    {"foo", &Base_foo, METH_VARARGS, ""},
+    {"bar", &Base_bar, METH_VARARGS, ""},
+    {null, null, 0, null}
+];
+
+extern(C)
+PyObject* Derived_bar(PyObject* self, PyObject* args) {
+    writefln("Derived.bar");
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyMethodDef[] Derived_methods = [
+    {"bar", &Derived_bar, METH_VARARGS, ""},
+    {null, null, 0, null}
+];
+
+extern(C)
+PyObject* hello(PyObject* self, PyObject* args) {
+    writefln("Hello, world!");
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyMethodDef[] rawexample_methods = [
+    {"hello", &hello, METH_VARARGS, ""},
+    {null, null, 0, null}
+];
+
+extern(C)
+export void initrawexample() {
+    PyObject* m = Py_InitModule("rawexample", rawexample_methods.ptr);
+
+    Base_type.ob_type = PyType_Type_p;
+    Base_type.tp_basicsize = Base_object.sizeof;
+    Base_type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
+    Base_type.tp_methods = Base_methods.ptr;
+    Base_type.tp_name = "rawexample.Base";
+    Base_type.tp_new = &PyType_GenericNew;
+    PyType_Ready(&Base_type);
+    Py_INCREF(cast(PyObject*)&Base_type);
+    PyModule_AddObject(m, "Base", cast(PyObject*)&Base_type);
+
+    Derived_type.ob_type = PyType_Type_p;
+    Derived_type.tp_basicsize = Derived_object.sizeof;
+    Derived_type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
+    Derived_type.tp_methods = Derived_methods.ptr;
+    Derived_type.tp_name = "rawexample.Derived";
+    Derived_type.tp_new = &PyType_GenericNew;
+    Derived_type.tp_base = &Base_type;
+    PyType_Ready(&Derived_type);
+    Py_INCREF(cast(PyObject*)&Derived_type);
+    PyModule_AddObject(m, "Derived", cast(PyObject*)&Derived_type);
+}
+

examples/rawexample/readme.txt

+This is an example of a simple Python extension written with the raw Python/C
+API, using CeleriD. Note that this module's setup.py specifies the raw_only
+option.
+
+Execute the conventional distutils command
+    python setup.py build
+to build.
+
+Then execute
+    python test.py
+to exercise this example extension.

examples/rawexample/setup.py

+from celerid.support import setup, Extension
+
+projName = 'rawexample'
+
+setup(
+    name=projName,
+    version='0.1',
+    ext_modules=[
+        Extension(projName, ['rawexample.d'], raw_only=True)
+    ],
+)

examples/rawexample/test.py

+import os.path, sys
+import distutils.util
+
+# Append the directory in which the binaries were placed to Python's sys.path,
+# then import the D DLL.
+libDir = os.path.join('build', 'lib.%s-%s' % (
+    distutils.util.get_platform(),
+    '.'.join(str(v) for v in sys.version_info[:2])
+))
+sys.path.append(os.path.abspath(libDir))
+import rawexample
+
+rawexample.hello()
+
+b = rawexample.Base()
+d = rawexample.Derived()
+
+b.foo()
+b.bar()
+d.foo()
+d.bar()
+

examples/testdll/readme.txt

+This example runs through many of the advanced features of Pyd.
+
+Execute the conventional distutils command
+    python setup.py build
+to build.
+
+Then execute
+    python test.py
+to exercise this example extension.

examples/testdll/setup.py

+from celerid.support import setup, Extension
+
+projName = 'testdll'
+
+setup(
+    name=projName,
+    version='0.1',
+    ext_modules=[
+        Extension(projName, [projName + '.d'])
+    ],
+  )

examples/testdll/test.py

+import os.path, sys
+import distutils.util
+
+# Append the directory in which the binaries were placed to Python's sys.path,
+# then import the D DLL.
+libDir = os.path.join('build', 'lib.%s-%s' % (
+    distutils.util.get_platform(),
+    '.'.join(str(v) for v in sys.version_info[:2])
+  ))
+sys.path.append(os.path.abspath(libDir))
+import testdll
+
+testdll.foo()
+
+print
+
+print testdll.bar(12)
+
+print
+
+print "testdll.baz():"
+testdll.baz()
+print "testdll.baz(20):"
+testdll.baz(20)
+print "testdll.baz(30, 'cat'):"
+testdll.baz(30, 'cat')
+
+print
+
+print "Testing callback support"
+def foo():
+    print "Callback works!"
+testdll.dg_test(foo)
+print "Testing delegate wrapping"
+dg = testdll.func_test()
+dg()
+
+print
+
+print "Testing class wrapping"
+a = testdll.Foo(10)
+print "Class instantiated!"
+print "Testing method wrapping:"
+a.foo()
+print "Testing property wrapping:"
+print a.i
+a.i = 50
+print a.i
+
+print "Testing opApply wrapping:"
+try:
+    for i in a:
+        print i
+except TypeError, e:
+    print "opApply not supported on this platform"
+
+print
+
+print "Testing exception wrapping"
+try:
+    testdll.throws()
+except RuntimeError, e:
+    print "Success: Exception caught!"
+    print e
+
+print
+
+S = testdll.S
+s = S()
+print "s.s = 'hello'"
+s.s = 'hello'
+print "s.s"
+print s.s
+print "s.write_s()"
+s.write_s()
+
+print
+
+print "Testing custom conversion function"
+print testdll.conv1()
+testdll.conv2(20)
+
+print
+
+print '--------'
+print 'SUCCESS'
+print '--------'

examples/testdll/testdll.d

+module testdll;
+
+import python;
+import pyd.pyd;
+import std.stdio, std.string;
+
+void foo() {
+    writefln("20 Monkey");
+}
+
+void foo(int i) {
+    writefln("You entered %s", i);
+}
+
+string bar(int i) {
+    if (i > 10) {
+        return "It's greater than 10!";
+    } else {
+        return "It's less than 10!";
+    }
+}
+
+void baz(int i=10, string s="moo") {
+    writefln("i = %s\ns = %s", i, s);
+}
+
+class Foo {
+    int m_i;
+    this() { }
+    this(int i) {
+        m_i = i;
+    }
+    this(int i, int j) {
+        m_i = i + j;
+    }
+    void foo() {
+        writefln("Foo.foo(): i = %s", m_i);
+    }
+    int length() { return 10; }
+    int opSlice(int i1, int i2) {
+        writefln(i1, " ", i2);
+        return 12;
+    }
+    int opIndex(int x, int y) {
+        writefln(x, " ", y);
+        return x+y;
+    }
+    Foo opAdd(Foo f) { return new Foo(m_i + f.m_i); }
+    int opApply(int delegate(inout int, inout int) dg) {
+        int result = 0;
+        int j;
+        for (int i=0; i<10; ++i) {
+            j = i+1;
+            result = dg(i, j);
+            if (result) break;
+        }
+        return result;
+    }
+    int i() { return m_i; }
+    void i(int j) { m_i = j; }
+    void a() {}
+    void b() {}
+    void c() {}
+    void d() {}
+    void e() {}
+    void f() {}
+    void g() {}
+    void h() {}
+    void j() {}
+    void k() {}
+    void l() {}
+    void m() {}
+    void n() {}
+    void o() {}
+    void p() {}
+    void q() {}
+    void r() {}
+    void s() {}
+    void t() {}
+    void u() {}
+    void v() {}
+    void w() {}
+    void x() {}
+    void y() {}
+    void z() {}
+}
+
+void delegate() func_test() {
+    return { writefln("Delegate works!"); };
+}
+
+void dg_test(void delegate() dg) {
+    dg();
+}
+
+class Bar {
+    int[] m_a;
+    this() { }
+    this(int[] i ...) { m_a = i; }
+    int opApply(int delegate(inout int) dg) {
+        int result = 0;
+        for (int i=0; i<m_a.length; ++i) {
+            result = dg(m_a[i]);
+            if (result) break;
+        }
+        return result;
+    }
+}
+
+struct S {
+    int i;
+    char[] s;
+    void write_s() {
+        writefln(s);
+    }
+}
+
+
+struct A {
+    int i;
+}
+
+Foo spam(Foo f) {
+    f.foo();
+    Foo g = new Foo(f.i + 10);
+    return g;
+}
+
+void throws() {
+    throw new Exception("Yay! An exception!");
+}
+
+A conv1() {
+    A a;
+    a.i = 12;
+    return a;
+}
+void conv2(A a) {
+    writefln(a.i);
+}
+
+mixin _wrap_class!(
+    Foo,
+    "Foo",
+    Init!(void delegate(int), void delegate(int, int)),
+    Property!(Foo.i, "A sample property of Foo."),
+    Def!(Foo.foo, "A sample method of Foo."),
+    Def!(Foo.a),
+    Def!(Foo.b),
+    Def!(Foo.c),
+    Def!(Foo.d),
+    Def!(Foo.e),
+    Def!(Foo.f),
+    Def!(Foo.g),
+    Def!(Foo.h),
+    Def!(Foo.j),
+    Def!(Foo.k),
+    Def!(Foo.l),
+    Def!(Foo.m),
+    Def!(Foo.n)/*, // Maximum length
+    Def!(Foo.o),
+    Def!(Foo.p),
+    Def!(Foo.q),
+    Def!(Foo.r),
+    Def!(Foo.s),
+    Def!(Foo.t),
+    Def!(Foo.u),
+    Def!(Foo.v),
+    Def!(Foo.w),
+    Def!(Foo.x),
+    Def!(Foo.y),
+    Def!(Foo.z)*/
+) F;
+
+extern(C) void PydMain() {
+    pragma(msg, "testdll.PydMain");
+    d_to_python(delegate int(A a) { return a.i; });
+    python_to_d(delegate A(int i) { A a; a.i = i; return a; });
+
+    def!(foo);
+    // Python does not support function overloading. This allows us to wrap
+    // an overloading function under a different name. Note that if the
+    // overload accepts a different number of minimum arguments, that number
+    // must be specified.
+    def!(foo, "foo2", void function(int), 1);
+    def!(bar);
+    // Default argument support - Now implicit!
+    def!(baz);
+    def!(spam);
+    def!(func_test);
+    def!(dg_test);
+    def!(throws);
+    def!(conv1);
+    def!(conv2);
+
+    module_init();
+
+    F.wrap_class("A sample class.");
+
+    wrap_struct!(
+        S,
+        Def!(S.write_s, "A struct member function."),
+        Member!("i", "One sample data member of S."),
+        Member!("s", "Another sample data member of S.")
+    ) ("A sample struct.");
+}
+

html_doc/adv_conversion.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+    <link href="pyd.css" rel="stylesheet" type="text/css">
+    <title>Advanced type conversion</title>
+</head>
+
+<body>
+<div id="nav">
+<p><big>Contents</big></p>
+<ul>
+<li><a class="nav" href="index.html">Main</a></li>
+<li><a class="nav" href="install.html">Installation</a></li>
+<li><a class="nav" href="basics.html">The basics</a></li>
+<li><a class="nav" href="celerid.html">CeleriD</a></li>
+<li><a class="nav" href="conversion.html">Type conversion</a></li>
+<li><a class="navcur" href="adv_conversion.html">Advanced type conversion</a></li>
+<li><a class="nav" href="func_wrapping.html">Function wrapping</a></li>
+<li><a class="nav" href="class_wrapping.html">Class wrapping</a></li>
+<li><a class="nav" href="inherit.html">Inheritance</a></li>
+<li><a class="nav" href="struct_wrapping.html">Struct wrapping</a></li>
+<li><a class="nav" href="except_wrapping.html">Exception wrapping</a></li>
+<li><a class="nav" href="pydobject.html">PydObject</a></li>
+<li><a class="nav" href="vsboost.html">vs. Boost.Python</a></li>
+<li><a class="nav" href="credits.html">Credits</a></li>
+</ul>
+</div>
+
+<div id="content">
+
+<h1>Advanced type conversion</h1>
+
+<p>It is frequently useful to extend Pyd's type conversion mechanisms. The usual way to do this is to wrap classes or structs. Pyd has two additional mechanisms for more complex situations.</p>
+
+<dl>
+<dt><code>void d_to_python(<span class="t_arg">dg_t</span>) (<span class="t_arg">dg_t</span> <span class="arg">dg</span>);</code></dt>
+<dd>This allows the user to define a function for returning a D type to Python. The <span class="arg">dg</span> may be either a function pointer or a delegate. The argument to the function pointer is of the type to convert. The return type of the function pointer can be any convertible type.</dd>
+
+<dt><code>void python_to_d(<span class="t_arg">dg_t</span>) (<span class="t_arg">dg_t</span> <span class="arg">dg</span>);</code></dt>
+<dd>This allows the user to define a function for converting a Python object to a D type. The <span class="arg">dg</span> may be either a function pointer or a delegate. The argument to the function pointer can be any convertible type. The return type of the function pointer is the type to convert.</dd>
+</dl>
+
+<p>Conversion functions defined with either of the above functions only take effect if Pyd's regular type conversion mechanisms fail. This would usually happen if a wrapped function returns or has a parameter of some un-wrapped class or struct type.</p>
+
+<h3><a class="anchor" name="examples">Examples</a></h3>
+
+<pre class="code"><span class="keyword">import</span> std.stdio;
+
+<span class="keyword">struct</span> S {
+    <span class="keyword">int</span> i;
+}
+
+S foo() {
+    S s;
+    s.i = <span class="number">12</span>;
+}
+<span class="keyword">void</span> bar(S s) {
+    writefln(s);
+}
+
+<span class="keyword">extern</span> (C) <span class="keyword">void</span> PydMain() {
+    d_to_python(<span class="keyword">delegate int</span>(S s) { <span class="keyword">return</span> s.i; });
+    python_to_d(<span class="keyword">delegate</span> S(<span class="keyword">int</span> i) { S s; s.i = i; <span class="keyword">return</span> s; });
+
+    def!(foo);
+    def!(bar);
+    module_init();
+}</pre>
+
+<p>And in Python:</p>
+
+<pre class="code">&gt;&gt;&gt; foo()
+12
+&gt;&gt;&gt; bar(<span class="number">20</span>)
+20</pre>
+
+</div>
+
+</body>
+</html>

html_doc/basics.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+    <link href="pyd.css" rel="stylesheet" type="text/css">
+    <title>Starting out with Pyd</title>
+</head>
+
+<body>
+<div id="nav">
+<p><big>Contents</big></p>
+<ul>
+<li><a class="nav" href="index.html">Main</a></li>
+<li><a class="nav" href="install.html">Installation</a></li>
+<li><a class="navcur" href="basics.html">The basics</a></li>
+<li><a class="nav" href="celerid.html">CeleriD</a></li>
+<li><a class="nav" href="conversion.html">Type conversion</a></li>
+<li><a class="nav" href="adv_conversion.html">Advanced type conversion</a></li>
+<li><a class="nav" href="func_wrapping.html">Function wrapping</a></li>
+<li><a class="nav" href="class_wrapping.html">Class wrapping</a></li>
+<li><a class="nav" href="inherit.html">Inheritance</a></li>
+<li><a class="nav" href="struct_wrapping.html">Struct wrapping</a></li>
+<li><a class="nav" href="except_wrapping.html">Exception wrapping</a></li>
+<li><a class="nav" href="pydobject.html">PydObject</a></li>
+<li><a class="nav" href="vsboost.html">vs. Boost.Python</a></li>
+<li><a class="nav" href="credits.html">Credits</a></li>
+</ul>
+</div>
+
+<div id="content">
+
+<h1>The basics</h1>
+
+<h3>Module basics</h3>
+
+<p>The most minimal working Pyd module looks something like this:</p>
+
+<pre class="code"><span class="keyword">import</span> pyd.pyd;
+
+<span class="keyword">extern</span> (C) <span class="keyword">void</span> PydMain() {
+    module_init();
+}</pre>
+
+<p>The first line imports Pyd:</p>
+
+<pre class="code"><span class="keyword">import</span> pyd.pyd;</pre>
+
+<p>The <code>pyd</code> module in the <code>pyd</code> package publicly imports all of the other components of Pyd.</p>
+
+<p>The <code>PydMain</code> function is called when the module is imported by Python. You will call most of Pyd's API from here. At the very least, <code>PydMain</code> <em>must</em> contain a call to <code>module_init</code>. The <code>module_init</code> function has the following form:</p>
+
+<p><code>PyObject* module_init(char[] <span class="arg">docstring</span>="");</code></p>
+
+<p>It does little more than call <a href="http://docs.python.org/api/allocating-objects.html">Py_InitModule</a> and return the new module object. This object is also available via the <code>Pyd_Module_p</code> property once you've called <code>module_init</code>.</p>
+
+<p>Due to the way in which Pyd implements function and class wrapping, any calls to <code>def</code> must occur <em>before</em> the call to <code>module_init</code>, and any calls to <code>wrap_class</code> must occur <em>after</em> the call. I know this seems like a rather arbitrary rule, but it is important. Calls to <code>def</code> in the wrong place will simply be ignored, and calls to <code>wrap_class</code> in the wrong place will throw an assert.</p>
+
+<p><code>PydMain</code> will catch any D exception that is thrown from inside it, and <a href="except_wrapping.html">safely pass that exception to Python</a>.</p>
+</div>
+
+</body>
+</html>

html_doc/celerid.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+    <link href="pyd.css" rel="stylesheet" type="text/css">
+    <title>CeleriD: Building Python Extensions With D</title>
+</head>
+
+<body>
+<div id="nav">
+<p><big>Contents</big></p>
+<ul>
+<li><a class="nav" href="index.html">Main</a></li>
+<li><a class="nav" href="install.html">Installation</a></li>
+<li><a class="nav" href="basics.html">The basics</a></li>
+<li><a class="navcur" href="celerid.html">CeleriD</a></li>
+<li><a class="nav" href="conversion.html">Type conversion</a></li>
+<li><a class="nav" href="adv_conversion.html">Advanced type conversion</a></li>
+<li><a class="nav" href="func_wrapping.html">Function wrapping</a></li>
+<li><a class="nav" href="class_wrapping.html">Class wrapping</a></li>
+<li><a class="nav" href="inherit.html">Inheritance</a></li>
+<li><a class="nav" href="struct_wrapping.html">Struct wrapping</a></li>
+<li><a class="nav" href="except_wrapping.html">Exception wrapping</a></li>
+<li><a class="nav" href="pydobject.html">PydObject</a></li>
+<li><a class="nav" href="vsboost.html">vs. Boost.Python</a></li>
+<li><a class="nav" href="credits.html">Credits</a></li>
+</ul>
+</div>
+
+<div id="content">
+
+<h1>CeleriD</h1>
+
+<p>CeleriD is an extension to Python's <a href="http://docs.python.org/dist/dist.html">distutils</a>, originally written by David Rushby. It extends distutils to know about the DMD compiler (on Windows) and the GDC compiler (on Linux). The following trivial example setup.py file is enough to compile a simple one-file extension module:</p>
+
+<pre class="code"><span class="comment"># Import from celerid instead of distutils</span>
+<span class="keyword">from</span> celerid.support <span class="keyword">import</span> setup, Extension
+
+project = '<span class="string">testdll</span>'
+
+setup(
+    name=project,
+    ext_modules=[
+        Extension(project, [project + '<span class="string">.d</span>'])
+    ],
+)</pre>
+
+<p>Compiling the module is a simple matter of running this:</p>
+
+<pre class="code">&gt;python setup.py build</pre>
+
+<p>The Python module <code>celerid.support</code>, when imported, hot-patches distutils to know about the D compiler. It also provides the following:</p>
+
+<dl>
+<dt><code>setup</code></dt> <dd>This is simply an alias of <code>distutils.core.setup</code>, included here so you only have to import <code>celerid.support</code> in your setup.py module.</dd>
+
+<dt><code>Extension</code></dt> <dd>This is a subclass of <code>distutils.core.Extension</code>. It supports all of the arguments of the base class, with the exception of <code>define_macros</code> and <code>undef_macros</code>. D does not have a preprocessor, so an exception will be raised if you attempt to use either of these options. This class also supports these additional arguments beyond the base class:
+    <dl>
+    <dt><code>version_flags</code></dt> <dd>This should be a list of strings, which will be passed to the D compiler as version flags.</dd>
+    <dt><code>debug_flags</code></dt> <dd>Similar to <code>version_flags</code>, the strings in this list will be passed to D as debug flags.</dd>
+    <dt><code>raw_only</code></dt> <dd>This flag defaults to <code>False</code>. When <code>True</code>, it supresses the compilation and linkage of Pyd, StackThreads, and meta. This is useful if you only want to write a raw Python/C extension without the overhead of Pyd and its auxiliary packages. This is equivalent to specifying <code>False</code> to the next four flags.</dd>
+    <dt><code>with_pyd</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the compilation and linkage of Pyd. This is useful if you want to write a raw Python/C extension and don't want the overhead of compiling Pyd.</dd>
+    <dt><code>with_st</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the compilation and linkage of StackThreads. Pyd uses StackThreads for its iteration wrapping support. By setting this to <code>False</code>, opApply wrapping, <code>Iter</code>, and <code>AltIter</code> will be unavailable. If <code>with_pyd</code> and this are <code>True</code>, then the <code>Pyd_with_StackThreads</code> version flag will be defined (which is used internally by Pyd). <b>Important note:</b> StackThreads does not currently work with GDC! CeleriD will always set this flag to <code>False</code> when using GDC! This means that opApply wrapping is not available on Linux at this time.</dd>
+    <dt><code>with_meta</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the compilation and linkage of <code>meta</code> (Pyd's metaprogramming package). Because Pyd depends on meta, an exception will be raised if <code>with_pyd</code> is <code>True</code> and this is not.</dd>
+    <dt><code>with_main</code></dt> <dd>This flag defaults to <code>True</code>. When <code>False</code>, it supresses the use of the "magic" <code>PydMain</code> function. (Instead, users must manually declare a C-style <code>init</code> function.) Do not use this unless you know what you are doing. If <code>with_pyd</code> is <code>False</code>, this will silently be set to <code>False</code> as well. <code>PydMain</code> can only be used if Pyd itself is in use.</dd>
+    </dl>
+</dd>
+</dl>
+</div>
+
+</body>
+</html>

html_doc/class_wrapping.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+    <link href="pyd.css" rel="stylesheet" type="text/css">
+    <title>Wrapping classes</title>
+</head>
+
+<body>
+<div id="nav">
+<p><big>Contents</big></p>
+<ul>
+<li><a class="nav" href="index.html">Main</a></li>
+<li><a class="nav" href="install.html">Installation</a></li>
+<li><a class="nav" href="basics.html">The basics</a></li>
+<li><a class="nav" href="celerid.html">CeleriD</a></li>
+<li><a class="nav" href="conversion.html">Type conversion</a></li>
+<li><a class="nav" href="adv_conversion.html">Advanced type conversion</a></li>
+<li><a class="nav" href="func_wrapping.html">Function wrapping</a></li>
+<li><a class="navcur" href="class_wrapping.html">Class wrapping</a></li>
+<li><a class="nav" href="inherit.html">Inheritance</a></li>
+<li><a class="nav" href="struct_wrapping.html">Struct wrapping</a></li>
+<li><a class="nav" href="except_wrapping.html">Exception wrapping</a></li>
+<li><a class="nav" href="pydobject.html">PydObject</a></li>
+<li><a class="nav" href="vsboost.html">vs. Boost.Python</a></li>
+<li><a class="nav" href="credits.html">Credits</a></li>
+</ul>
+</div>
+
+<div id="content">
+
+<h1>Class wrapping</h1>
+
+<p>Exposing D classes to Python is easy! The heart of Pyd's class wrapping features is the <code>wrap_class</code> function template:</p>
+
+<p><code>void wrap_class(<span class="t_arg">T</span>, char[] <span class="t_arg">classname</span> = symbolnameof!(T), <span class="t_arg">Params</span>...) ();</code></p>
+    <ul>
+    <li><span class="t_arg">T</span> is the class being wrapped.</li>
+    <li><span class="t_arg">classname</span> is the name of the class as it will appear in Python. It defaults to the name of the D class. If you are wrapping an instance of a class template, you will have to provide this explicitly.</li>
+    <li><span class="t_arg">Params</span> is a series of struct types (defined below), which define the various members of the class.</li>
+    </ul>
+
+<p>Calls to <code>wrap_class</code> must occur <em>after</em> calling <code>module_init</code>.</p>
+
+<p>To expose the constructors, methods, and properties of the class, you must pass <code>wrap_class</code> instantiations of these struct templates.</p>
+
+<dl>
+<dt><code>struct Def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&amp;fn));</code></dt>
+<dd>This wraps a method of the class. It functions very much like the <code>def</code> function used to <a href="func_wrapping.html">wrap regular functions</a>, with one very important difference: There is no support for default arguments. (This is a side-effect of the fact that you cannot call an alias of a method in D, and delegates do not understand default arguments.)</dd>
+
+<dt><code>struct StaticDef(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&amp;fn), uint <span class="t_arg">MIN_ARGS</span> = minArgs!(fn));</code></dt>
+<dd>This wraps a static member function of the class. It also functions exactly like the <code>def</code> function used to wrap regular functions, and even includes support for default arguments.</dd>
+
+<dt><code>struct Property(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), bool <span class="t_arg">RO</span> = false);</code></dt>
+<dd>This wraps a property. See the examples below for more details.
+    <ul>
+    <li><span class="t_arg">fn</span> is the name of the property. <code>prop</code> will automatically attempt to wrap both the "get" and "set" forms of the property, unless <span class="t_arg">RO</span> is specified.</li>
+    <li><span class="t_arg">name</span> is the name of the property as it will appear in Python. As with <code>def</code>, <code>prop</code> will attempt to derive this automatically.</li>
+    <li><span class="t_arg">RO</span> specifies whether this is a <i>read-only</i> property. If true, it will only wrap the "get" form of the property. If false, it will wrap both the "get" and "set" forms. <i>(This is a little hackish, and I will probably try to make this detection more automatic in the future. It also means it cannot support a property that only has a "set" form.)</i></li>
+    </ul>
+</dd>
+
+<dt><code>struct Init(<span class="t_arg">C</span> ...);</code></dt>
+<dd>This allows you to expose the class's constructors to Python. If the class provides a zero-argument constructor, there is no need to specify it; it is always available. Each element of <span class="t_arg">C</span> should be a function type. Each function type should correspond to a constructor. (That is, the arguments to the function type should be the same as the arguments to the class constructor. The return type is ignored.) There is an additional limitation at this time: No two constructors may have the same number of arguments. Pyd will always attempt to call the first constructor with the right number of arguments. If you wish to support a constructor with default arguments, you must specify each possible constructor call as a different template argument to this function. The examples show a few uses of <code>Init</code>.</dd>
+
+<dt><code>struct Repr(alias <span class="t_arg">fn</span>);</code></dt>
+<dd>This allows you to expose a member function of the class as the Python type's <code>__repr__</code> function. The member function must have the signature <code>char[] function()</code>.</dd>
+
+<dt><code>struct Iter(<span class="t_arg">iter_t</span>);</code></dt>
+<dd>This allows the user to specify a different overload of opApply than the default. (The default is always the one that is lexically first.) The <span class="t_arg">iter_t</span> argument should be the type of the delegate that forms the argument to opApply. This might be e.g. <code>int delegate(inout int)</code>. Don't forget the <code>inout</code> modifiers! (This is not available in Linux; see the note below on opApply wrapping.)</dd>
+
+<dt><code>struct AltIter(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">iter_t</span> = <i>implementationDetail</i>);</code></dt>
+<dd>This wraps alternate iterator methods as Python methods that return iterator objects. The wrapped methods should have a signature like that of opApply. (In other words, they should be methods intended to be used with D's ability to iterate over delgates.) The <span class="t_arg">iter_t</span> argument should be the type of the delegate argument to the method. This will usually be derived automatically. (This is not available in Linux; see the note below on opApply wrapping.)
+</dd>
+</dl>
+
+<p>If you ever wish to check whether a given class has been wrapped, Pyd helpfully registers all wrapped classes with the <code>is_wrapped</code> template, which is just a templated <code>bool</code>:</p>
+
+<p><code>template is_wrapped(<span class="t_arg">T</span>);</code></p>
+
+<p>If you have a class <code>Foo</code>, you can check whether it is wrapped by simply checking whether <code>is_wrapped!(Foo)</code> is true. It is important to note that this is <em>not</em> a <code>const bool</code>, it is a <em>runtime</em> check.</p>
+
+<h3><a class="anchor" name="opwrap">Automatic operator overloading</a></h3>
+
+<p>Pyd will automatically wrap most of D's operator overload functions with appropriate Python operator overloads. There are some caveats:</p>
+
+<ul>
+<li>Pyd will only automatically wrap the lexically first <i>opFunc</i> defined for a given <i>opFunc</i>. <i>(In the future, I may add a mechanism allowing a user to specifiy a specific overload of an opFunc.)</i></li>
+<li>The usual rules for function wrapping apply: Only an <i>opFunc</i> whose return type and arguments are <a href="conversion.html">convertable</a> may be wrapped. <i>(The current implementation is pretty dumb: If the lexically first opFunc has an unconvertable return type or argument, the operator overload will still be wrapped, but won't work.)</i></li>
+</ul>
+
+<p>At the moment, only the following operator overloads are supported:</p>
+
+<p><code>opNeg, opPos, opCom, opAdd, opSub, opMul, opDiv, opMod, opAnd, opOr, opXor, opShl, opShr, opCat, opAddAssign, opSubAssign, opMulAssign, opDivAssign, opModAssign, opAndAssign, opOrAssign, opXorAssign, opShlAssign, opShrAssign, opCatAssign, opIn_r, opCmp, opCall, opApply, opIndex, opIndexAssign, opSlice, opSliceAssign</code></p>
+
+<p>Missing from this list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>Def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>AltIter</code>.</p>
+
+<p>Also missing from the list is <code>opAssign</code>. Python has strict reference semantics for its objects, so overloading the assignment operator is not possible. You must explicitly wrap <code>opAssign</code> with a regular method.</p>
+
+<p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code> and the special <code>__len__</code> method. You may still wrap it with <code>Property</code> or <code>Def</code> if you wish it to be available as a normal property or method.</p>
+
+<p><b>Notes on wrapped operators</b></p>
+
+<dl>
+<dt><code>opApply</code></dt> <dd>Pyd wraps D's iteration protocol with the help of Mikola Lysenko's StackThreads package. This package does not work in GDC, and so opApply wrapping is not available in Linux. See also the <a href="celerid.html"><code>with_st</code></a> option offered by CeleriD.</dd>
+<dt><code>opSlice, opSliceAssign</code></dt> <dd>Pyd only supports these overloads if both of their two indexes are implicitly convertable to type <code>int</code>. This is a limitation of the Python/C API. Note that this means the zero-argument form of opSlice (for allowing the "empty slice," e.g. <code>foo[]</code>) cannot be wrapped. <i>(I may work around this in the future.)</i> Because Pyd can only automatically wrap the lexically-first method in a class, it will fail to wrap opSlice and opSliceAssign if you define an empty form first.</dd>
+<dt><code>opCat, opCatAssign</code></dt> <dd>Python does not have a dedicated array concatenation operator. The plus sign (<code>+</code>) is reused for this purpose. Therefore, odd behavior may result with classes that define both <code>opAdd/opAddAssign</code> and one or both of these operators. (Consider yourself warned.) However, the Python/C API considers addition and concatenation distinct operations, and so both of these sets of operator overloads are supported.</dd>
+<dt><code>opIn_r</code></dt> <dd>Python expects the <code>in</code> operator to return a boolean value (it is a containment test). D convention is for <code>in</code> to search for the value in the container, and to return a pointer to the found item, or <code>null</code> if the item is not found. That said, D does not enforce any particular signature on the <code>in</code> overload, while the Python/C API does. Pyd will check the boolean result of a call to <code>opIn_r</code>, and return that value to Python.</dd>
+</dl>
+
+<h3><a class="anchor" name="examples">Examples</a></h3>
+
+<p>Suppose we have the following simple class:</p>
+
+<pre class="code"><span class="keyword">import</span> std.stdio;
+
+<span class="keyword">class</span> Foo {
+    <span class="keyword">int</span> m_i;
+
+    <span class="keyword">this</span>() { m_i = <span class="number">0</span>; }
+    <span class="keyword">this</span>(<span class="keyword">int</span> j) { m_i = j; }
+    <span class="keyword">this</span>(<span class="keyword">int</span> j, <span class="keyword">int</span> k) { m_i = j + k; }
+
+    <span class="keyword">int</span> i() { <span class="keyword">return</span> m_i; }
+    <span class="keyword">void</span> i(<span class="keyword">int</span> j) { m_i = j; }
+
+    <span class="keyword">void</span> foo(<span class="keyword">char</span>[] s) {
+        writefln(s, m_i);
+    }
+
+    Foo opAdd(Foo rhs) {
+        <span class="keyword">return new</span> Foo(m_i + rhs.m_i);
+    }
+}</pre>
+
+<p>We would expose this class to Python by putting this code in <code>PydMain</code> after the call to <code>module_init</code>:</p>
+
+<pre class="code"><span class="comment">// Call wrap_class</span>
+wrap_class!(
+    Foo,
+    <span class="comment">// Wrap the "foo" method</span>
+    Def!(Foo.foo),
+    <span class="comment">// Wrap the "i" property</span>
+    Property!(Foo.i),
+    <span class="comment">// Wrap the constructors.</span>
+    Init!(<span class="keyword">void function</span>(<span class="keyword">int</span>), <span class="keyword">void function</span>(<span class="keyword">int</span>, <span class="keyword">int</span>))
+);</pre>
+
+<p>Now we can use this type from within Python like any other type.</p>
+
+<pre class="code">&gt;&gt;&gt; <span class="keyword">from</span> testmodule <span class="keyword">import</span> Foo
+&gt;&gt;&gt; f = Foo()
+&gt;&gt;&gt; f.i
+0
+&gt;&gt;&gt; f.i = <span class="number">20</span>
+&gt;&gt;&gt; f.foo(<span class="string">"Hello! i is "</span>)
+Hello! i is 20
+&gt;&gt;&gt; f = Foo(<span class="number">10</span>, <span class="number">10</span>)
+&gt;&gt;&gt; f.i
+20
+&gt;&gt;&gt; g = Foo(<span class="number">30</span>)
+&gt;&gt;&gt; g.i
+30
+&gt;&gt;&gt; e = f + g
+&gt;&gt;&gt; e.i
+50
+&gt;&gt;&gt; <span class="comment"># We can even subclass our D type</span>
+&gt;&gt;&gt; <span class="keyword">class</span> MyFoo(Foo):
+... 	<span class="keyword">def</span> bar(self):
+... 		<span class="keyword">print</span> <span class="string">"Hey, i+3 is"</span>, self.i + <span class="number">3</span>
+... 
+&gt;&gt;&gt; h = MyFoo(<span class="number">3</span>)
+&gt;&gt;&gt; h.bar()
+Hey, i+3 is 6
+&gt;&gt;&gt; </pre>
+
+</div>
+
+</body>
+</html>
+

html_doc/conversion.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
+    <link href="pyd.css" rel="stylesheet" type="text/css">
+    <title>Converting types to and from Python</title>
+</head>
+
+<body>
+<div id="nav">
+<p><big>Contents</big></p>
+<ul>
+<li><a class="nav" href="index.html">Main</a></li>
+<li><a class="nav" href="install.html">Installation</a></li>
+<li><a class="nav" href="basics.html">The basics</a></li>
+<li><a class="nav" href="celerid.html">CeleriD</a></li>
+<li><a class="navcur" href="conversion.html">Type conversion</a></li>
+<li><a class="nav" href="adv_conversion.html">Advanced type conversion</a></li>
+<li><a class="nav" href="func_wrapping.html">Function wrapping</a></li>
+<li><a class="nav" href="class_wrapping.html">Class wrapping</a></li>
+<li><a class="nav" href="inherit.html">Inheritance</a></li>
+<li><a class="nav" href="struct_wrapping.html">Struct wrapping</a></li>
+<li><a class="nav" href="except_wrapping.html">Exception wrapping</a></li>
+<li><a class="nav" href="pydobject.html">PydObject</a></li>
+<li><a class="nav" href="vsboost.html">vs. Boost.Python</a></li>
+<li><a class="nav" href="credits.html">Credits</a></li>
+</ul>
+</div>
+
+<div id="content">
+
+<h1>Type conversion</h1>
+
+<p>Pyd provides a series of template functions for converting types to and from Python. Template arguments are in <span class="t_arg">boldface</span>, function arguments are in <span class="arg">italics</span>.</p>
+
+<dl>
+<dt><code>PyObject* _py(<span class="t_arg">T</span>) (<span class="t_arg">T</span> <span class="arg">t</span>);</code></dt>
+<dd>Converts D item <span class="arg">t</span> of type <span class="t_arg">T</span> to a PyObject. The returned pointer is a new, owned reference. The following conversions are possible:
+
+<table border=1>
+<tr><th>D type</th>                             <th>Python type</th></tr>
+<tr><td>bool</td>                               <td>bool</td>       </tr>
+<tr><td>C_long (usually <tt>int</tt>)</td>      <td>int</td>        </tr>
+<tr><td>C_longlong (usually <tt>long</tt>)</td> <td>long</td>       </tr>
+<tr><td>double</td>                             <td>float</td>      </tr>
+<tr><td>idouble, cdouble</td>                   <td>complex</td>    </tr>
+<tr><td>char[] (as ASCII string)</td>           <td>str</td>        </tr>
+<!--<tr><td>wchar[] (as UCS2 string)</td>           <td>unicode</td>    </tr>-->
+<tr><td>dynamic array</td>                      <td>list</td>       </tr>
+<tr><td>associative array</td>                  <td>dict</td>       </tr>