-
Notifications
You must be signed in to change notification settings - Fork 1
/
setup.py
96 lines (81 loc) · 3.67 KB
/
setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python3
"""
Python setuptools config to package the all the components of this repository.
Note conda load_setup_py_data() requires that this script is runnable during the build stage, so we avoid non default
classes such as Pybind11Extension as these packages are unlikely to be installed in the conda base environment.
"""
import os
import sys
import subprocess
from setuptools import setup, find_namespace_packages, Extension
from setuptools.command.build_ext import build_ext
from setuptools.command.install import install
from distutils.command.clean import clean
from distutils.dir_util import copy_tree
from pathlib import Path
class BuildExtensions(build_ext):
"""
Extends the standard extension builder building the pure C++ dependencies before the python extensions, then creates
a handy 'pylib' symlink for the PYTHONPATH.
"""
def run(self):
subprocess.check_call("make build=release", shell=True)
# Overwrite any of the env variables that might be the conda environment that will prepend rpaths we don't want.
os.environ["LDFLAGS"] = "-shared"
os.environ["LDSHARED"] = "-shared"
build_ext.run(self) # call parent
packages = Path("packages")
packages.unlink(missing_ok=True)
packages.symlink_to(self.get_finalized_command("build_py").build_lib)
return
class Install(install):
"""
Extends the standard installer to build the pure C++ dependencies and install the headers, libraries and binaries as
well as the non-platform specific shared files.
"""
def run(self):
subprocess.check_call("make build=release", shell=True)
copy_tree("include", f"{sys.prefix}/include")
copy_tree("lib", f"{sys.prefix}/lib")
copy_tree("bin", f"{sys.prefix}/bin")
copy_tree("share", f"{sys.prefix}/share")
install.run(self) # call parent
return
class Clean(clean):
"""
Extends the standard clean command.
"""
def run(self):
clean.run(self) # call parent, this removes the temp files only
packages_link = Path("packages")
packages_link.unlink(missing_ok=True)
subprocess.check_call(f"rm -rf {self.get_finalized_command('build_py').build_lib}", shell=True)
subprocess.check_call(f"rm -rf {self.get_finalized_command('build').build_scripts}", shell=True)
subprocess.check_call("make build=release clean", shell=True)
return
# C++ python extensions are compiled and packaged using setuptools, not using the Makefile.
COMMON_EXT_ARGS = {
"include_dirs": ["include"],
"library_dirs": ["lib", f"{os.environ.get('CONDA_PREFIX', os.environ.get('PREFIX'))}/lib"], # local build or an installation
"extra_compile_args": ["-fvisibility=hidden", "-std=c++20"], # required for pybind11
"extra_link_args": ["-Wl,-rpath,$ORIGIN/../../../../lib"], # conda-build will also append the env rpath
"language": "c++",
}
# C++ python extensions are compiled and packaged using setuptools, not using the Makefile.
ext_modules = [
Extension(name="acme.skeleton.pyhelloworld",
sources=["src/acme/skeleton/pyhelloworld.cpp"],
libraries=["acme-skeleton-shared"], **COMMON_EXT_ARGS),
]
if __name__ == "__main__":
setup(
name="acme-skeleton",
version="0.0.0", # automatically updated by deploy tool
packages=find_namespace_packages(where="python"),
package_dir={"": "python"},
include_package_data=True,
scripts=[str(f) for f in Path("scripts").glob("**/*") if f.is_file()],
ext_modules=ext_modules,
zip_safe=False,
cmdclass={"build_ext": BuildExtensions, "install": Install, "clean": Clean},
)