Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setup.py: run build_ext before anything else

I'm working with a setup.py that creates a whole bunch of SWIG interface files during the build_ext step. This needs to run first, because subsequent build steps need a full list of the python files to work properly (like copying the python files to the package directory, creating the egg, creating the sources list, etc.).

This is what currently happens when you do setup.py install:

running install
running bdist_egg
running egg_info
running install_lib
running build_py
running build_ext

The build_py step tries to copy all the python files that it finds to the build directory. Those files don't exist until build_ext runs (swig creates a bunch of .py files).

This answer recommends changing sub_commands but that didn't appear to do anything.

I tried just subclassing the install command class like this to run build_ext before anything else:

class Build_ext_first(setuptools.command.install.install):
    def run(self):
        self.run_command("build_ext")
        super(Build_ext_first, self).run()

..and then working it in to setup with cmdclass:

setup(
    ...
    cmdclass = {'install' : Build_ext_first}
)

But that didn't work because super doesn't work with old-style classes and install apparently doesn't inherit from object.

How do I do build_ext first?

like image 582
sciencectn Avatar asked Apr 06 '15 18:04

sciencectn


People also ask

Is setup py outdated?

py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools. I found a very detailed write-up explaining this issue: "Why you shouldn't invoke setup.py directly" (October 2021).

What is Python setup py Build_ext?

python setup.py build_ext --inplace uses the setup.py to build our extension modules. The --inplace flag moves the compiled shared objects into the source tree so that they are in the Python search path.

What does setup py clean do?

As far as I know, it just removes the the build subdirectory, where Python puts all the files to be installed, including extensions that need to be compiled.


2 Answers

For fear of posting on a 2 year old post. I think the correct way to solve this would be to fix it during the "build" phase:

from setuptools import setup, find_packages, Extension
from setuptools.command.build_py import build_py as _build_py    

class build_py(_build_py):
    def run(self):
        self.run_command("build_ext")
        return super().run()

setup(...,
    cmdclass = {'build_py' : build_py},
)

That way it works for bdist_wheel as well as install (haven't tested other stuff).

Note the super syntax is a bit different in Python 2:

class build_py(_build_py):
    def run(self):
        self.run_command("build_ext")
        return _build_py.run(self)
like image 125
hmaarrfk Avatar answered Sep 17 '22 00:09

hmaarrfk


It appears the old way of doing super() is forwards-compatible so I just did that:

class Build_ext_first(setuptools.command.install.install):
    def run(self):
        self.run_command("build_ext")
        return setuptools.command.install.install.run(self)


setup(
    ...,
    cmdclass = {'install' : Build_ext_first}
)
like image 32
sciencectn Avatar answered Sep 19 '22 00:09

sciencectn