1import contextlib
2import os
3import re
4import sys
5import platform
6import subprocess
7import glob
8
9from codecs import open  # To use a consistent encoding
10from setuptools import setup, Extension
11from setuptools.command.build_ext import build_ext
12from distutils.version import LooseVersion
13import distutils.log
14
15# Get the current directory path.
16dart_root = os.path.abspath(os.path.dirname(__file__))
17dartpy_root = os.path.join(dart_root, 'python')
18
19with open(os.path.join(dart_root, 'README.md'), encoding='utf-8') as f:
20    long_description = f.read()
21description = 'Python API of Dynamic Animation and Robotics Toolkit.'
22
23distutils.log.set_verbosity(distutils.log.DEBUG)  # Set DEBUG level
24
25
26class CMakeExtension(Extension):
27    def __init__(self, name, sourcedir='', sources=[]):
28        Extension.__init__(self, name, sources=sources)
29        self.sourcedir = os.path.abspath(sourcedir)
30
31
32class CMakeBuild(build_ext):
33    """ Wrapper class that builds the extension using CMake. """
34
35    def run(self):
36        """ Build using CMake from the specified build directory. """
37        try:
38            out = subprocess.check_output(['cmake', '--version'])
39        except OSError:
40            raise RuntimeError(
41                "CMake must be installed to build the following extensions: " +
42                ", ".join(e.name for e in self.extensions))
43
44        if platform.system() == "Windows":
45            cmake_version = LooseVersion(
46                re.search(r'version\s*([\d.]+)', out.decode()).group(1))
47            if cmake_version < '3.8.0':
48                raise RuntimeError("CMake >= 3.8.0 is required on Windows")
49
50        distutils.log.set_verbosity(distutils.log.DEBUG)  # Set DEBUG level
51
52        for ext in self.extensions:
53            self.build_extension(ext)
54
55    def build_extension(self, ext):
56        cmake_args = [
57            '-DDART_BUILD_DARTPY=ON', '-DPYTHON_EXECUTABLE=' + sys.executable
58        ]
59
60        cfg = 'Debug' if self.debug else 'Release'
61        build_args = ['--config', cfg]
62
63        if platform.system() == "Windows":
64            if sys.maxsize > 2**32:
65                cmake_args += ['-A', 'x64']
66            build_args += ['--', '/m']
67        else:
68            cmake_args += ['-DCMAKE_BUILD_TYPE=' + cfg]
69            build_args += ['--', '-j4']
70
71        env = os.environ.copy()
72        env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(
73            env.get('CXXFLAGS', ''), self.distribution.get_version())
74        if not os.path.exists(self.build_temp):
75            os.makedirs(self.build_temp)
76        subprocess.check_call(['cmake', ext.sourcedir] + cmake_args,
77                              cwd=self.build_temp,
78                              env=env)
79        subprocess.check_call(['cmake', '--build', '.', '--target', 'dartpy'] +
80                              build_args,
81                              cwd=self.build_temp)
82        subprocess.check_call(['cmake', '--build', '.', '--target', 'install'],
83                              cwd=self.build_temp)
84
85
86sources = ['CMakeLists.txt']
87sources.extend(glob.glob('cmake/**/*', recursive=True))
88sources.extend(glob.glob('dart/**/*', recursive=True))
89sources.extend(glob.glob('python/**/*', recursive=True))
90sources.extend(glob.glob('doxygen/**/*', recursive=True))
91
92# Set up the python package wrapping this extension.
93setup(
94    name='dartpy',
95    version='0.0.1-10',
96    description=description,
97    long_description=long_description,
98    long_description_content_type='text/markdown',
99    ext_modules=[CMakeExtension('dartpy', sources=sources)],
100    url='https://github.com/dartsim/dart',
101    author='Jeongseok Lee',
102    author_email='jslee02@gmail.com',
103    license='BSD 2-Clause',
104    keywords='dartsim robotics',
105    classifiers=[
106        'Development Status :: 2 - Pre-Alpha',
107        'Framework :: Robot Framework',
108        'Intended Audience :: Science/Research',
109        'License :: OSI Approved :: BSD License',
110        'Topic :: Scientific/Engineering',
111    ],
112    cmdclass=dict(build_ext=CMakeBuild),
113)
114