OOF2: The Manual

7.4. Internal Extensions

This section describes the files that must be created in the SRC/EXTENSIONS directory in order to add an internal extension to OOF2. Internal extensions are somewhat easier to build, and can be imported automatically when OOF2 is started, but they are less flexible because they require that the author has permission to create files in the OOF2 source and installation directories.

Because internal extensions are built by the main OOF2 setup.py file, there is less flexibility in how they're constructed.

7.4.1. Directory Structure

Figure 7.3. File Arrangement for Internal Extensions

File Arrangement for Internal Extensions

The file layout for internal extensions. Names in red are directories, and lines between them indicate nested subdirectories. Blue arrows indicate the information flow during the build process. Green arrows show run-time dependencies, and are equivalent to the black arrows in Figure 7.1.

Only the files listed in bold need to be created by hand. The setup.py script creates the rest.


The source files for an internal OOF2 extension must reside in the SRC/EXTENSIONS directory within the main OOF2 directory. The files can be placed directly in that directory, or within subdirectories of it. EXTENSIONS and all of its subdirectories must each have a file called DIR.py, which is read by the main OOF2 setup.py script and instructs it on what to do with each file. Each subdirectory must also contain an __init__.py file, which may be empty.

EXTENSIONS and the Python files within it form a Python package[44], which will be copied at installation time to oof2.EXTENSIONS in the Python library directory.

C++ files in the EXTENSIONS directory are compiled into a shared library, which will be installed alongside of the main OOF2 shared libraries. (It is possible, but not necessarily recommended, to simply add the C++ files to an existing OOF2 library.)

Swig processes its input files from the EXTENSIONS directory and writes output files to SRC/SWIG/EXTENSIONS. These files are the source for wrapper libraries and Python extension modules in the oof2.SWIG.EXTENSIONS package.

EXTENSIONS contains a file called initialize.py which is imported when OOF2 starts, after all other OOF2 components have been initialized. Authors of internal extensions should place an import statement in this file if they wish the extension code to be loaded automatically when OOF2 starts.

7.4.2. The DIR.py File

The DIR.py file in each EXTENSIONS subdirectory tells the OOF2 setup script how to build the program. DIR.py is itself a Python script, containing a number of variable and function definitions. setup.py expects to find certain definitions in DIR.py. If it finds definitions that it doesn't recognize, it will print a warning message. On the other hand, all of the entries in DIR.py are optional. setup.py will not complain about an empty DIR.py, but it won't do anything useful either.

Here is an example of a DIR.py file, from the OOF2 source code. DIR.py files from EXTENSIONS have exactly the same structure.

dirname = 'image'
clib = 'oof2image'
clib_order = 2
subdirs = ['IO', 'GRAINBDY']

cfiles = ['oofimage.C', 'burn.C', 'evenlyilluminate.C',
'pixelselectioncourieri.C']

swigfiles = ['oofimage.swg', 'burn.swg', 'pixelselectioncourieri.swg']

swigpyfiles = ['oofimage.spy', 'burn.spy']

pyfiles = ['initialize.py', 'pixelselectionmethod.py',
'pixelselectionmod.py', 'imagemodifier.py']

hfiles = ['oofimage.h', 'burn.h', 'pixelselectioncourieri.h']

def set_clib_flags(c_lib):
    import oof2setuputils
    if oof2setuputils.check_exec('Magick++-config'):
        oof2setuputils.add_third_party_includes('Magick++-config --cppflags',
     					   c_lib)
        oof2setuputils.add_third_party_libs('Magick++-config --ldflags --libs',
     				       c_lib)
    else:
        print "Can't find Magick++-config!"
    c_lib.externalLibs.append('oof2common')
	

DIR.py can contain the following entries:

subdirs

A list of the names of the subdirectories of the current directory. setup.py will not process directories that aren't listed in their parent's DIR.py file.

cfiles

A list of the C and C++ files in the current directory that need to be compiled into a shared library. Omit the list or set it to [] if there are no C or C++ files.

hfiles

A list of the header files that are included in the C and C++ files. This list isn't actually used (at the moment).

swigfiles

A list of the swig input files in the current directory. The python wrapper generated from each file in the list will be importable as

import oof2.SWIG.EXTENSIONS.subdirectory.filename
		

The C++ wrapper library that's generated from the swig output will automatically link to the shared library built from the files in cfiles.

pyfiles

A list of the python files in the current directory. Files in this list will be importable as

import oof2.EXTENSIONS.subdirectory.filename
		

swigpyfiles

A list of Python files that aren't to be installed as modules, but are instead included in the swig output files. The list is used to ensure that the swig output is regenerated when the Python file changes. It's a good idea to give these files a suffix other than .py, so that distutils won't install them. (The main OOF2 code uses .spy.)

clib

This is the name of the shared library that will be built from the C and C++ files listed in cfiles. The library name should not have a 'lib' prefix or any suffix. DIR.py files from more than one subdirectory can use the same clib — the cfiles lists from each of the subdirectories will be combined to build the library.

clib_order

An integer indicating the order in which the shared libraries are to be built. Libraries will small order numbers will be built first, so that libraries with large orders can link to them. The core OOF2 libraries have small clib_orders. Extensions should use large numbers (say 10000). If more than one DIR.py file refers to the same clib, then only one of them should define clib_order.

set_clib_flags

set_clib_flags is a function that is called to set compilation and link flags for building the shared library. It's described in more detail below. If more than one DIR.py file refers to the same clib, then only one of them should define set_clib_flags.

7.4.2.1. set_clib_flags

The set_clib_flags function that can optionally be defined in a DIR.py script has the job of setting extra compilation and link flags required to build a shared library from the C and C++ files in the subdirectory.

The argument to set_clib_flags is an object of the CLibInfo class, which holds information about how to build a shared library. It contains the following data members which can be altered by set_clib_flags:

externalLibs

A list of other libraries that should be linked. The names of the libraries should be specified without a 'lib' prefix or any suffix. It's safe to include other OOF2 libraries in the list, as long as those other libraries have a smaller clib_order.

externalLibDirs

A list of directories in which to search for the libraries specified by externalLibs. It's not necessary to specify the location of other OOF2 libraries.

includeDirs

A list of directories to search for C and C++ header files. The OOF2 source directories are included automatically.

Other compilation arguments can be specified in the usual way when OOF2 is built.

The module oof2setuputils contains a few functions that are convenient to use in set_clib_flags:

  • pkg_check adds options for linking to external libraries that use the pkg-config program to retrieve their configuration options.

  • add_third_party_includes can be used to get the header file directories for external libraries that don't use pkg-config.

  • add_third_party_libs can be used to get the library names and directories for external libraries that don't use pkg-config.

  • check_exec checks for the existence of external utility functions.