1import sys
2import os
3
4if sys.version.find('MSC') == -1:
5    windows = False
6else:
7    windows = True
8
9if windows:
10    try:
11        from setuptools import setup, Extension
12    except ImportError:
13        from distutils.core import setup, Extension
14else:
15    from distutils.core import setup, Extension
16
17from distutils.command.clean import clean
18from distutils.command.build_ext import build_ext
19from distutils.command.install_data import install_data
20
21def writeln(s):
22    sys.stdout.write('%s\n' % s)
23    sys.stdout.flush()
24
25# Utility function to read the contents of the README file.
26def read(fname):
27    return open(os.path.join(os.path.dirname(__file__), fname)).read()
28
29# Fail gracefully for old versions of Python.
30
31if sys.version[:3] < '2.6':
32    writeln("GMPY2 requires Python 2.6 or later.")
33    writeln("Please use GMPY 1.x for earlier versions of Python.")
34    sys.exit()
35
36# Run python setup.py build_ext --help for build options
37
38# Notes regarding coverage testing.
39#
40# The --gcov command line option configures GCC to collect code coverage data
41# for testing purposes. The raw collected data can be converted to .gcov files
42# with the command "gcov build/temp.linux-x86_64-3.4/src/gmpy2.gcno". To create
43# a tidy HTML summary, use "gcovr -s -r . --html -o coverage.html". When tests
44# are completed, delete the .gcov and coverage.html files.
45#
46# The following commands show the use of lcov to analyze the coverage data.
47#
48#   py34 setup.py clean
49#   py34 setup.py install --gcov --force
50#   py34 test/runtests.py
51#   lcov --capture --directory build/temp.linux-x86_64-3.4/src/gmpy2.gcno --output-file build/coverage.info
52#   genhtml build/coverage.info --output-directory build/out
53#   firefox build/out/index.html
54#
55# Remember to remove the *.gcov file and the out sub-directory.
56
57
58# Improved clean command.
59
60class gmpy_clean(clean):
61
62    def run(self):
63        self.all = True
64        clean.run(self)
65
66build_options = [
67    ('mpir', None, 'Build using mpir; deprecated'),
68    ('msys2', None, 'Build in msys2 environment'),
69    ('gcov', None, 'configure GCC to collect code coverage data for testing purposes'),
70    ('fast', None, 'depend on MPFR and MPC internal implementations details'),
71    ('vector', None, 'include the vector_XXX() functions; they are unstable and under active development'),
72    ('shared', None, 'Build using shared libraries'),
73    ('static', None, 'Build using static libraries'),
74]
75
76# Define a custom build class that parses to the defined macros to alter the
77# build setup.
78
79class gmpy_build_ext(build_ext):
80    default_opts = build_ext.user_options
81    user_options = list(build_options)
82    user_options.extend(default_opts)
83
84    def initialize_options(self):
85        build_ext.initialize_options(self)
86        self.mpir = False
87        self.msys2 = False
88        self.gcov = False
89        self.fast = False
90        self.vector = False
91        self.static = None
92        self.shared = None
93
94    def doit(self):
95        # Find the directory specfied for non-standard library location.
96
97        defines = []
98
99        if self.static is None and self.shared is None:
100            self.shared = True
101
102        if self.gcov:
103            self.extensions[0].libraries.append('gcov')
104            self.extensions[0].extra_compile_args.extend(['-O0', '--coverage'])
105            self.extensions[0].extra_link_args.append('--coverage')
106
107        if self.vector:
108            defines.append(('VECTOR', 1))
109
110        if self.fast:
111            defines.append(('FAST', 1))
112
113        if self.msys2:
114            defines.append(('MSYS2', 1))
115
116        if self.mpir:
117            defines.append(('MPIR', 1))
118
119        if self.shared:
120            defines.append(('SHARED', 1))
121
122        if self.static:
123            defines.append(('STATIC', 1))
124
125        if self.mpir:
126            self.extensions[0].libraries.extend(['mpir', 'mpfr', 'mpc'])
127        else:
128            self.extensions[0].libraries.extend(['gmp', 'mpfr', 'mpc'])
129
130        # Add MSVC specific options.
131        if windows and not self.msys2:
132            self.extensions[0].extra_link_args.append('/MANIFEST')
133            defines.append(("MPIR", 1))
134            if not self.static:
135                defines.append(("MSC_USE_DLL", None))
136
137        self.extensions[0].define_macros.extend(defines)
138
139
140    def finalize_options(self):
141        build_ext.finalize_options(self)
142        gmpy_build_ext.doit(self)
143
144# custom install data in order that data_files
145# get installed together with the .so
146
147class gmpy_install_data(install_data):
148    def finalize_options(self):
149        install_data.finalize_options(self)
150        install = self.distribution.get_command_obj('install')
151        self.install_dir = install.install_purelib
152
153# prepare the extension for building
154
155my_commands = {'clean' : gmpy_clean, 'build_ext' : gmpy_build_ext, 'install_data' : gmpy_install_data}
156
157gmpy2_ext = Extension('gmpy2',
158                      sources=[os.path.join('src', 'gmpy2.c')],
159                      include_dirs=['./src'])
160
161setup(name = "gmpy2",
162      version = "2.1.0b4",
163      author = "Case Van Horsen",
164      author_email = "casevh@gmail.com",
165      license = "LGPL-3.0+",
166      url = "https://github.com/aleaxit/gmpy",
167      description = "gmpy2 interface to GMP, MPFR, and MPC for Python 2.7 and 3.4+",
168      long_description = read('README'),
169      data_files = [('', ['src/gmpy2.pxd']), ('gmpy2', ['src/gmpy2.h'])],
170      classifiers = [
171        'Development Status :: 4 - Beta',
172        'Intended Audience :: Developers',
173        'Intended Audience :: Science/Research',
174        'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)',
175        'Natural Language :: English',
176        'Operating System :: MacOS :: MacOS X',
177        'Operating System :: Microsoft :: Windows',
178        'Operating System :: POSIX',
179        'Programming Language :: C',
180        'Programming Language :: Python :: 2',
181        'Programming Language :: Python :: 2.7',
182        'Programming Language :: Python :: 3',
183        'Programming Language :: Python :: 3.4',
184        'Programming Language :: Python :: 3.5',
185        'Programming Language :: Python :: 3.6',
186        'Programming Language :: Python :: 3.7',
187        'Programming Language :: Python :: 3.8',
188        'Programming Language :: Python :: Implementation :: CPython',
189        'Topic :: Scientific/Engineering :: Mathematics',
190        'Topic :: Software Development :: Libraries :: Python Modules',
191      ],
192      keywords = "gmp mpir mpfr mpc multiple-precision arbitrary-precision precision bignum",
193      cmdclass = my_commands,
194      ext_modules = [gmpy2_ext]
195)
196