Skip to content
Snippets Groups Projects
Commit 9298e5f6 authored by Christophe Guillon's avatar Christophe Guillon
Browse files

[Setup] Add support for development install

Add support for pip -e development (editable) mode.
Add some environment vars for configuring the cmake build in
development mode:
- AIDGE_BUILD_GEN=<cmake_backend>: for instance Ninja to use
  the ninja backend which better supports incremental build
- AIDGE_BUILD_MODE=[Debug|Release]: define the build mode,
  defaults to Debug

Note that due to behavior changes depending on the
python/setuptools versions, the portable method to ensure
incremental build on C++ files is to use:

export AIDGE_BUILD_GEN=Ninja
pip install --no-build-isolation -v -e .

Refer to the doc string of setup.py for details.
parent 84bbbf7e
No related branches found
No related tags found
No related merge requests found
...@@ -19,6 +19,25 @@ pip install . -v ...@@ -19,6 +19,25 @@ pip install . -v
export AIDGE_INSTALL='<path_to_aidge>/install' export AIDGE_INSTALL='<path_to_aidge>/install'
``` ```
## Development Mode installation
Install in development mode (local changes to python files and .cpp files do not require full installation)
with:
```bash
pip install cmake ninja # install first build dependencies
export AIDGE_BUILD_GEN=Ninja
pip install --no-build-isolation -v -e .
```
After changes in a python file, no action is required, for changes in .cpp/.h file, re-execute:
```bash
pip install --no-build-isolation -v -e .
```
In this mode, the C++ compilation build system is located in the local `build/` directory.
Refer to the doc string in `setup.py`for more details on editable mode.
## Standard C++ Compilation ## Standard C++ Compilation
Create two directories ``build`` and ``ìnstall``. Create two directories ``build`` and ``ìnstall``.
......
#!/usr/bin/env python3 #!/usr/bin/env python3
""" Aidge """ Aidge
This setup file supports both install and develop (editable) mode, i.e.:
- either: pip install -v .
- or editable: pip install [--no-build-isolation] -v -e .
(use --no-build-isolation preferably for modern installation, see [1] below)
In editable mode, there is no need to reinstall after changes in the pythons files.
Also, when changing C++ source files, incremental compilation works and build
directory is located in build/, though one must re-run after C++ changes, either:
- reinstall; pip install [--no-build-isolation] -v -e .
- or cmake: cmake --build build && cmake --install build
- or direct build command: ninja -C build install / make -C build install
Note that in editable mode, one must first install build dependencies as they
will not be automatically installed:
- pip install cmake ninja
[1] on modern setuptools/python versions, isolation mode breaks the incremental
build due to the reinstall of build tools in different locations,
use --no-build_isolation to avoid this.
#TODO To change #TODO To change
POC of the next framework named Aidge POC of the next framework named Aidge
""" """
...@@ -14,7 +34,6 @@ import os ...@@ -14,7 +34,6 @@ import os
if sys.version_info[:2] < (3, 7): if sys.version_info[:2] < (3, 7):
raise RuntimeError("Python version >= 3.7 required.") raise RuntimeError("Python version >= 3.7 required.")
CLASSIFIERS = """\ CLASSIFIERS = """\
Development Status :: 2 - Pre-Alpha Development Status :: 2 - Pre-Alpha
""" """
...@@ -30,12 +49,21 @@ from setuptools import setup, Extension ...@@ -30,12 +49,21 @@ from setuptools import setup, Extension
from setuptools import find_packages from setuptools import find_packages
from setuptools.command.build_ext import build_ext from setuptools.command.build_ext import build_ext
SETUP_DIR = pathlib.Path(__file__).parent
def parse_requirements():
with open(SETUP_DIR / "requirements.txt", "r") as inf:
return [
line
for line in [l.strip() for l in inf.readlines()]
if line
]
def get_project_name() -> str: def get_project_name() -> str:
return open(pathlib.Path().absolute() / "project_name.txt", "r").read() return open(SETUP_DIR / "project_name.txt", "r").read().strip()
def get_project_version() -> str: def get_project_version() -> str:
aidge_root = pathlib.Path().absolute() version = open(SETUP_DIR / "version.txt", "r").read().strip()
version = open(aidge_root / "version.txt", "r").read().strip()
return version return version
...@@ -45,9 +73,19 @@ class CMakeExtension(Extension): ...@@ -45,9 +73,19 @@ class CMakeExtension(Extension):
class CMakeBuild(build_ext): class CMakeBuild(build_ext):
def __init__(self, dist, *args, **kwargs):
super().__init__(dist, *args, **kwargs)
# Detect editable_mode for old versions of setuptools
if not hasattr(self, "editable_mode"):
if hasattr(dist, "commands"):
self.editable_mode = "develop" in dist.commands
else:
self.editable_mode = False
def run(self): def run(self):
# This lists the number of processors available on the machine # This lists the number of processors available on the machine
# The compilation will use half of them # The compilation will use half of them
# Note that for ninja backend this is not necessary
max_jobs = str(ceil(multiprocessing.cpu_count() / 2)) max_jobs = str(ceil(multiprocessing.cpu_count() / 2))
cwd = pathlib.Path().absolute() cwd = pathlib.Path().absolute()
...@@ -60,37 +98,39 @@ class CMakeBuild(build_ext): ...@@ -60,37 +98,39 @@ class CMakeBuild(build_ext):
if not build_lib.exists(): if not build_lib.exists():
build_lib.mkdir(parents=True, exist_ok=True) build_lib.mkdir(parents=True, exist_ok=True)
os.chdir(str(build_temp))
# Impose to use the executable of the python # Impose to use the executable of the python
# used to launch setup.py to setup PythonInterp # used to launch setup.py to setup PythonInterp
param_py = "-DPYTHON_EXECUTABLE=" + sys.executable param_py = "-DPYTHON_EXECUTABLE=" + sys.executable
compile_type = 'Debug' build_gen = os.environ.get("AIDGE_BUILD_GEN", "")
cmake_type_opts = ['-G', build_gen] if build_gen else []
cmake_job_opts = ['-j', max_jobs] if build_gen != "Ninja" else []
compile_type = os.environ.get("AIDGE_BUILD_MODE", "Debug")
install_path = os.path.join(sys.prefix, "lib", "libAidge") if "AIDGE_INSTALL" not in os.environ else os.environ["AIDGE_INSTALL"] install_path = os.path.join(sys.prefix, "lib", "libAidge") if "AIDGE_INSTALL" not in os.environ else os.environ["AIDGE_INSTALL"]
self.spawn(['cmake', str(cwd), param_py, '-DTEST=OFF', f'-DCMAKE_INSTALL_PREFIX:PATH={install_path}', f'-DCMAKE_BUILD_TYPE={compile_type}']) os.chdir(str(build_temp))
self.spawn(['cmake', *cmake_type_opts, str(cwd), param_py, '-DTEST=OFF', f'-DCMAKE_INSTALL_PREFIX:PATH={install_path}', f'-DCMAKE_BUILD_TYPE={compile_type}'])
if not self.dry_run: if not self.dry_run:
self.spawn(['cmake', '--build', '.', '--config', compile_type, '-j', max_jobs]) self.spawn(['cmake', '--build', '.', '--config', compile_type, *cmake_job_opts])
self.spawn(['cmake', '--install', '.', '--config', compile_type]) self.spawn(['cmake', '--install', '.', '--config', compile_type])
os.chdir(str(cwd)) os.chdir(str(cwd))
aidge_package = build_lib / (get_project_name()) package_path_prefix = build_lib if not self.editable_mode else SETUP_DIR
aidge_package = (package_path_prefix / get_project_name()).absolute()
# Get "aidge core" package # Get "aidge core" package
# ext_lib = build_temp # ext_lib = build_temp
print(build_temp.absolute())
# Copy all shared object files from build_temp/lib to aidge_package # Copy all shared object files from build_temp/lib to aidge_package
for root, _, files in os.walk(build_temp.absolute()): for root, _, files in os.walk(build_temp):
for file in files: for file in files:
if (file.endswith('.so') or file.endswith('.pyd')) and (root != str(aidge_package.absolute())): if ((file.endswith('.so') or file.endswith('.pyd')) and
currentFile=os.path.join(root, file) root != str(aidge_package) and
shutil.copy(currentFile, str(aidge_package.absolute())) not root.startswith(str(build_lib))):
currentFile = pathlib.Path(root) / file
shutil.copy(str(currentFile), str(aidge_package))
# Copy version.txt in aidge_package # Copy version.txt in aidge_package
os.chdir(os.path.dirname(__file__)) shutil.copy(str(SETUP_DIR / "version.txt"), str(aidge_package))
shutil.copy("version.txt", str(aidge_package.absolute()))
if __name__ == '__main__': if __name__ == '__main__':
...@@ -105,6 +145,8 @@ if __name__ == '__main__': ...@@ -105,6 +145,8 @@ if __name__ == '__main__':
packages=find_packages(where="."), packages=find_packages(where="."),
include_package_data=True, include_package_data=True,
ext_modules=[CMakeExtension(get_project_name())], ext_modules=[CMakeExtension(get_project_name())],
install_requires=parse_requirements(),
setup_requires=['cmake', 'ninja'],
cmdclass={ cmdclass={
'build_ext': CMakeBuild, 'build_ext': CMakeBuild,
}, },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment