[Distutils] Distributing (complicated) C extensions

James Porter jvporter at wisc.edu
Thu Feb 11 02:56:45 CET 2010


Before I get started with the meat of this message (it's pretty long - 
for me, anyway), I should give a brief overview. I'm developing Python 
bindings for a set of interfaces called ITAPS, which contains a few 
independent libraries. If you want to look at my setup.py file (it's 
pretty scary), you can download the source at 
<http://pypi.python.org/pypi/PyTAPS/0.9.1>.

Basically, I have three somewhat-related questions, which I wrote a big 
pile of words about below. The short version is:

* Are multiple distributions inherently better/saner than one 
distribution with a handful of optional features?
* What's the best way to detect whether libraries exist to turn said 
features on/off?
* How do I install header files when using setuptools (or easy_install)?

Ok, now for the long version:

First, this distribution is fairly complicated, with a handful of 
setuptools Features controlling the various libraries I want to work 
with. I've waffled on whether this should be one distribution or 
several, but the former is a little problematic because the "core" 
module doesn't actually correlate to an independent thing on the C side. 
It really just piggybacks on each of the libraries. So basically there's 
no reason for the "core" module to exist in isolation, and it would 
actually be impossible to compile unless one of the "real" libraries was 
present. Is rolling this all together a terrible idea? Or a good one?

Second, having a single distribution with multiple features that can be 
enabled/disabled obviously requires a bit of work for configuration. 
Right now, it tries to detect if each library is installed, and if not, 
it disables that feature automatically. I mostly do this to make 
easy_install "just work" even if you don't have everything.

I should explain how I do configuration now: each library has a Makefile 
fragment that defines useful variables, e.g. $MYLIB_INCLUDEDIRS, that I 
read in and add into the appropriate places in the Extension. Each of my 
Features has a global --feature-path option that lets you point to the 
Makefile fragment. If you don't specify that, it steps through some 
environment variables and tries to find it. If it still can't find it, 
it'll assume you specified all the stuff you need as options to 
build_ext. Then I try to compile a simple file with the necessary header 
to make sure I got the paths right.

All of this work is done in an overrided version of build_ext (grabbing 
the Makefile fragment happens during finalize_options and the 
compilation test happens during run). This seems pretty hacky to me, 
especially since there's a config command in distutils that does some of 
what I want. However, I'm not sure how to actually *use* this. I assume 
I override the command, but what would it look like from a user's 
perspective? How do I connect it up to the build process?

Finally, I'd like to be able to install header files from my 
distribution. Looking through the distutils docs, there's an 
install_headers command that gets run as a part of install, and I can 
just specify headers=['foo.h'] as an option to setup. However, this 
doesn't seem to work with setuptools/distribute; it looks like they 
hijack the install command and, instead of actually running it directly, 
they manually run install_lib, install_data, etc.

This is made worse by the fact that, even if I stuck with vanilla 
distutils, easy_install appears to inject its version of Distribution 
into my setup.py anyway. (There's a way to work around that, but it's 
really messy. Think yanking the distutils.core Distribution class - 
"_Distribution" in the code - out of setuptools.dist. Barf.)

If you got all the way here, thanks for reading! Hopefully someone with 
a little more experience than me in this can give me a few pointers.

- Jim



More information about the Distutils-SIG mailing list