[mod_python] New setup.py.in for mod_python - builds mod_python extension from distutils

David Fraser davidf at sjsoft.com
Fri Mar 5 18:21:20 EST 2004


I've been working on the mod_python dist/setup.py.in (mostly to make it 
work for win32) and have added some important functionality...

1) it no longer requires configure (so it could just be setup.py) - it 
either scans config.status or calculates the information itself (e.g. it 
scans through the source file to find the mod_python version number). On 
Windows it uses the APACHESRC environment variables to find the apache 
include and lib directories (just like the VC++ project does)
2) it is now able to build mod_psp on Windows as well as Linux
3) most importantly, it is now able to build mod_python directly from 
the setup.py (on Windows)
    this should be possible on non-Windows system too but will require 
some work (we may have to make a distutils compiler class for apxs)

There are a few notes:
- the build of the mod_python extension produces a mod_python_so.pyd 
file, instead of the mod_python.so file we want. But at least on 
Windows, I have modified win32_postinstall to install this one instead 
of the other... (I call it mod_python_so.pyd instead of mod_python.pyd 
so that when it is put in the site-packages directory it does not 
confuse importing packages from mod_python)
- I have also added code to win32_postinstall to automatically detect 
the currently installed versions of Apache from the registry. It would 
be nice to let the user choose one of these. As a start, it just selects 
the latest version as the starting point for the tkinter file selection 
dialog (the win32 shell classes don't seem to let you do this...)

I have attached the modified setup.py.in (easier than a patch as almost 
everything has changed) and win32_postinstall.py

Any comments appreciated


-------------- next part --------------

# $Id: setup.py.in,v 1.5 2003/07/24 17:46:09 grisha Exp $

from distutils.core import setup, Extension

import sys
import re
import os.path

def getmp_rootdir():
    """gets the root directory of the mod_python source tree..."""
    return os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))

def getmp_srcdir():
    """gets the src subdirectory of the mod_python source tree..."""
    return os.path.join(getmp_rootdir(), 'src')

def getmp_includedir():
    """gets the src subdirectory of the mod_python source tree..."""
    return os.path.join(getmp_rootdir(), 'src', 'include')

def getconfigure_option(option_name):
    """gets an option from the config.status file"""
    config_status_file = os.path.join(getmp_rootdir(), 'config.status')
    if not os.path.exists(config_status_file):
        raise AssertionError("config.status not found in expected location (%s)" % config_status_file)
    header = open(config_status_file,'r')
    r = re.compile('s,@%s@,(?P<OPTION_STRING>[^,]+),' % (option_name))
    for line in header.readlines():
        m = r.search(line)
        if m is not None:
            return m.group('OPTION_STRING')
    raise AssertionError("unable to find @%s@ definition in %s", (option_name, config_status_file))

def getmp_version():
    """finds out the version of mod_python"""
    # if that fails, read it from the source file ourselves...
    mpversion_file = os.path.join(getmp_includedir(), 'mpversion.h')
    if not os.path.exists(mpversion_file):
        raise AssertionError("mpversion.h not found in expected location (%s)" % mpversion_file)
    header = open(mpversion_file,'r')
    r = re.compile('#define\s+MPV_STRING\s+"(?P<MPV_STRING>[^"]+)"')
    for line in header.readlines():
        m = r.search(line)
        if m is not None:
            return m.group('MPV_STRING')
    raise AssertionError("unable to find MPV_STRING in %s", mpversion_file)

def getapxs_location():
    """finds the location of apxs from the config.status file"""
    return getconfigure_option("APXS")

def getapxs_option(option):
    APXS = getapxs_location()
    import commands
    return commands.getoutput("%s -q %s" % (APXS, option))

def getapache_srcdir():
    """returns apache src directory"""
    return os.getenv("APACHESRC")

def getapache_includedir():
    """returns apache include directory"""
    apache_srcdir = getapache_srcdir()
    if apache_srcdir is None:
        return getapxs_option("INCLUDEDIR")
        return os.path.join(getapache_srcdir(), "include")

def getapache_libdir():
    """returns apache lib directory"""
    apache_srcdir = getapache_srcdir()
    if apache_srcdir is None:
        return ""
        return os.path.join(apache_srcdir, "lib")

VER = getmp_version()

# TODO: improve the intelligence here...
winbuild = (len(sys.argv) > 1 and sys.argv[1] == "bdist_wininst") or (os.name == "nt")

class PSPExtension(Extension):
    """a class that helps build the PSP extension"""
    def __init__(self, source_dir, include_dirs):
        Extension.__init__(self, "mod_python._psp",
                               [os.path.join(source_dir, source_file) for source_file in
                                    ("psp_string.c", "psp_parser.c", "_pspmodule.c")],

PSPModule = PSPExtension(getmp_srcdir(), [getmp_includedir()])

modpy_src_files = ("mod_python.c", "_apachemodule.c", "connobject.c", "filterobject.c",
                   "hlist.c", "hlistobject.c", "requestobject.c", "serverobject.c", "tableobject.c",

class finallist(list):
  """this represents a list that cannot be appended to..."""
  def append(self, object):

class ModPyExtension(Extension):
    """a class that actually builds the mod_python.so extension for Apache (yikes)"""
    def __init__(self, source_dir, include_dirs, library_dirs):
        Extension.__init__(self, "mod_python_so",
            sources = [os.path.join(source_dir, source_file) for source_file in modpy_src_files],
            libraries = ['libhttpd','libapr','libaprutil','ws2_32'],
        if winbuild:
            self.sources.append(os.path.join(source_dir, "Version.rc"))
            # TODO: fix this to autodetect if required...
        # this is a hack to prevent build_ext from trying to append "initmod_python" to the export symbols
        self.export_symbols = finallist(self.export_symbols)

ModPyModule = ModPyExtension(getmp_srcdir(), [getmp_includedir(), getapache_includedir()], [getapache_libdir()])

if winbuild:
    scripts = ["win32_postinstall.py"]
    # put the mod_python.so file in the Python root ...
    # win32_postinstall.py will pick it up from there...
    # data_files = [("", [(os.path.join(getmp_srcdir(), 'Release', 'mod_python.so'))])]
    data_files = []
    # mpso = "../src/mod_python.so"
    scripts = []
    data_files = []

      description="Apache/Python Integration",
      author="Gregory Trubetskoy et al",
      author_email="mod_python at modpython.org",
      package_dir={'mod_python': os.path.join(getmp_rootdir(), 'lib', 'python', 'mod_python')},
      ext_modules=[ModPyModule, PSPModule])

# makes emacs go into python mode
### Local Variables:
### mode:python
### End:
-------------- next part --------------
A non-text attachment was scrubbed...
Name: win32_postinstall.py
Type: text/x-python
Size: 4908 bytes
Desc: not available
Url : http://mailman.modpython.org/pipermail/mod_python/attachments/20040305/b415eb65/win32_postinstall.py

More information about the Mod_python mailing list