Skip to content
Snippets Groups Projects
Commit 733b9b23 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:

pip install --no-build-isolation -v -e .

Refer to the doc string of setup.py for details.
parent 4ac48d01
No related branches found
No related tags found
No related merge requests found
This commit is part of merge request !154. Comments created here will be created in the context of that merge request.
......@@ -19,6 +19,25 @@ pip install . -v
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 # enforce build dependencies (added also ninja here as we request it as build backend)
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
Create two directories ``build`` and ``ìnstall``.
......
#!/usr/bin/env python3
""" 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 python 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
Some envvars are available to configure the cmake build:
- AIDGE_BUILD_MODE=Debug|Release to configure the build type, defaults to Debug.
- AIDGE_BUILD_GEN=<build_backend>, passed as -G<build_backend>, defaults to cmake default.
For instance to use ninja backend on linux, use AIDGE_BUILD_GEN=Ninja.
In this case install ninja first with: pip install 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
POC of the next framework named Aidge
"""
......@@ -14,7 +41,6 @@ import os
if sys.version_info[:2] < (3, 7):
raise RuntimeError("Python version >= 3.7 required.")
CLASSIFIERS = """\
Development Status :: 2 - Pre-Alpha
"""
......@@ -30,12 +56,21 @@ from setuptools import setup, Extension
from setuptools import find_packages
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:
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:
aidge_root = pathlib.Path().absolute()
version = open(aidge_root / "version.txt", "r").read().strip()
version = open(SETUP_DIR / "version.txt", "r").read().strip()
return version
......@@ -45,9 +80,19 @@ class CMakeExtension(Extension):
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):
# This lists the number of processors available on the machine
# The compilation will use half of them
# Note that for ninja backend this is not necessary
max_jobs = str(ceil(multiprocessing.cpu_count() / 2))
cwd = pathlib.Path().absolute()
......@@ -60,37 +105,39 @@ class CMakeBuild(build_ext):
if not build_lib.exists():
build_lib.mkdir(parents=True, exist_ok=True)
os.chdir(str(build_temp))
# Impose to use the executable of the python
# used to launch setup.py to setup PythonInterp
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"]
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:
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])
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
# ext_lib = build_temp
print(build_temp.absolute())
# 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:
if (file.endswith('.so') or file.endswith('.pyd')) and (root != str(aidge_package.absolute())):
currentFile=os.path.join(root, file)
shutil.copy(currentFile, str(aidge_package.absolute()))
if ((file.endswith('.so') or file.endswith('.pyd')) and
root != str(aidge_package) and
not root.startswith(str(build_lib))):
currentFile = pathlib.Path(root) / file
shutil.copy(str(currentFile), str(aidge_package))
# Copy version.txt in aidge_package
os.chdir(os.path.dirname(__file__))
shutil.copy("version.txt", str(aidge_package.absolute()))
shutil.copy(str(SETUP_DIR / "version.txt"), str(aidge_package))
if __name__ == '__main__':
......@@ -105,6 +152,8 @@ if __name__ == '__main__':
packages=find_packages(where="."),
include_package_data=True,
ext_modules=[CMakeExtension(get_project_name())],
install_requires=parse_requirements(),
setup_requires=['cmake'],
cmdclass={
'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