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?
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).
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.
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.
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)
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}
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With