I am building a example_package
on which I would like to customize the installing process in both normal
and develop
mode. Here is the project structure:
.
├── cpp
│ ├── CMakeLists.txt
│ └── helloworld.cpp
├── pyproject.toml
├── setup.py
└── src
└── example_package
└── __init__.py
The content of each file is shown below
pyproject.toml
: A minimum information is added.
[build-system]
requires = ["setuptools>=62.0.0", "wheel", "cmake>=3.20"]
build-backend = "setuptools.build_meta"
[project]
name = "example_package"
version = "0.0.1"
requires-python = ">=3.8"
[tool.setuptools.packages.find]
where = ["src"]
setup.py
:
from setuptools import setup
from setuptools.command import develop, build_py, install
import subprocess
class CustomDevelop(develop.develop):
def run(self):
super(CustomDevelop, self).run()
print("Execute CustomDevelop ......")
class CustomBuildPy(build_py.build_py):
def run(self):
super(CustomBuildPy, self).run()
print("Execute CustomBuildPy ......")
class CustomInstall(install.install):
def run(self):
super(CustomInstall, self).run()
print("Execute CustomInstall ......")
setup(
cmdclass={
'develop': CustomDevelop,
'build_py': CustomBuildPy,
'install': CustomInstall
}
)
Installation
Normal mode
- Create, activate
venv
, and updatepip
andsetuptools
:python3 -m venv venv/ && source venv/bin/activate && python3 -m pip install --upgrade pip setuptools
- Install in
normal
mode:python3 -m pip install -vv . 2>&1 | grep -E "running|Execute"
- The output message:
running egg_info
running dist_info
running bdist_wheel
running build
running build_py
running egg_info
Execute CustomBuildPy ......
running install
running install_lib
running install_egg_info
running install_scripts
Execute CustomInstall ......
which is expected. CustomBuildPy
and CustomInstall
were executed.
Develop mode
- Create, activate
venv
, and updatepip
andsetuptools
:python3 -m venv venv/ && source venv/bin/activate && python3 -m pip install --upgrade pip setuptools
- Install in
develop
mode:python3 -m pip install -vv -e . 2>&1 | grep -E "running|Execute"
- The output message:
running egg_info
running dist_info
running editable_wheel
running build_py
Execute CustomBuildPy ......
running egg_info
which is not expected by me, because only CustomBuildPy
is run but not CustomDevelop
.
What I really want to do
The reason that I need to execute the costumed command in the installing process in the normal and develop mode is that I have a helloworld.cpp
which needs to be compiled into a executable helloworld
and put into the sys.path
.
cpp/helloworld.cpp
: For example, the content ofhelloworld.cpp
is trivial:
#include <iostream>
int main(int argc, char **argv) {
std::cout << "Hello World!!!\n";
return 0;
}
cpp/CMakeLists.txt
: the associatedCMakeLists.txt
is also trivial:
cmake_minimum_required(VERSION 3.20)
project(HelloWorld)
add_executable(helloworld helloworld.cpp)
The executable helloworld
can be run in the module example_package
like below:
$ cat src/example_package/__init__.py
import subprocess, os, sysconfig, sys
src_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.environ['PATH'] = src_dir + os.pathsep + os.environ['PATH']
subprocess.run("helloworld", env=os.environ)
Lastly, I change the CustomBuildPy
to:
class CustomBuildPy(build_py.build_py):
def run(self):
super(CustomBuildPy, self).run()
print("Execute CustomBuildPy ......")
subprocess.check_call("cmake -S cpp/ -B cpp/cmakebuild && cmake --build cpp/cmakebuild", shell=True)
subprocess.check_call("cp cpp/cmakebuild/helloworld build/lib/.", shell=True)
When installing in normal mode, everything works great. The executable helloworld
appears in venv/lib/python3.8/site-packages
.
But when installing in develop mode, the error emerges:
subprocess.CalledProcessError: Command 'cp -r cpp/build/helloworld build/lib/.' returned non-zero exit status 1.
Because the build
folder is not created in the develop mode in the source folder .
.
What can I do to fix it?