TJahns
TJahns

Reputation: 299

How to override python distutils ccompiler.shared_lib_extension

I'm trying to make distutils build an extension with libtool by overriding CC, LDSHARED etc. This fails for one reason alone: I cannot, from the shell environment at least, change the extension stored in compiler.shared_lib_extension, but for libtool it must be .la for libtool to realize what it's supposed to do.

By deriving from build_ext I can override lots of things but I don't see an easy way to override what's in build_ext.run which both sets self.ccompiler and runs it.

Upvotes: 2

Views: 251

Answers (1)

TJahns
TJahns

Reputation: 299

Turns out overriding the build_ext class works:

from distutils.command.build_ext import build_ext
import re

# run the customize_compiler
class custom_build_ext(build_ext):
    def build_extension(self, ext):
        self.compiler.shared_lib_extension = '.la'
        self.compiler.obj_extension = '.lo'
        build_ext.build_extension(self,ext)

    def get_ext_filename(self, ext_name):
        name = build_ext.get_ext_filename(self, ext_name)
        name = re.sub('\.[^.]*$', '.la', name)
        return name

But installation still gives me a headache: I need to run libtool in install mode to install the .la files.

So I'm trying to override dir_util.copy_tree next.

class custom_install_lib(install_lib):
    # re-assemble libtool install command
    libtool_cmd = []
    for env_var in ['LIBTOOL', 'AM_LIBTOOLFLAGS', 'LIBTOOLFLAGS', 'INSTALL']:
        libtool_cmd += os.environ[env_var].split()

    def copy_tree(self, infile, outfile,
                  preserve_mode=1, preserve_times=1, preserve_symlinks=0,
                  level=1):
        """almost identical to dir_util.copy_tree but for the special
        treatment of .libs directories and .la files
        """
        from distutils.file_util import copy_file
        from distutils.dir_util import mkpath

        verbose=1
        update=0
        if not self.dry_run and not os.path.isdir(infile):
            raise DistutilsFileError, \
                "cannot copy tree '%s': not a directory" % infile
        try:
            names = os.listdir(infile)
        except os.error, (errno, errstr):
            if self.dry_run:
                names = []
            else:
                raise DistutilsFileError, \
                    "error listing files in '%s': %s" % (infile, errstr)

        if not self.dry_run:
            mkpath(outfile, verbose=verbose)

        outputs = []

        for n in names:
            infile_name = os.path.join(infile, n)
            outfile_name = os.path.join(outfile, n)

            if n.startswith('.nfs') or n == '.libs':
                # skip NFS rename files and libtool-internals
                continue

            if n.endswith('.la'):
                print('installing libtool library', n, file=sys.stderr)
                self.spawn(self.libtool_cmd + [infile_name, outfile_name])
                continue

            if preserve_symlinks and os.path.islink(infile_name):
                link_dest = os.readlink(infile_name)
                if verbose >= 1:
                    log.info("linking %s -> %s", outfile_name, link_dest)
                if not self.dry_run:
                    os.symlink(link_dest, outfile_name)
                outputs.append(outfile_name)

            elif os.path.isdir(infile_name):
                outputs.extend(
                    self.copy_tree(infile_name, outfile_name, preserve_mode,
                                   preserve_times, preserve_symlinks))
            else:
                copy_file(infile_name, outfile_name, preserve_mode,
                          preserve_times, update, verbose=verbose,
                          dry_run=self.dry_run)
                outputs.append(outfile_name)

        return outputs

This is obviously much more than I had hoped for and I also needed to print the python-computed installation directory to get the libtool -rpath argument correct.

Upvotes: 1

Related Questions