forked from viscid-hub/Viscid
-
Notifications
You must be signed in to change notification settings - Fork 1
/
setup.py
executable file
·413 lines (362 loc) · 13.7 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
#!/usr/bin/env python
# Notes: cython is auto-detected, so if it's not found, then the cython
# extensions are built / cleaned if the .c files are found, else, the
# extension is ignored gracefully
from __future__ import print_function
import io
import os
import re
import sys
from glob import glob
from subprocess import Popen, CalledProcessError, PIPE
from distutils.command.clean import clean
from distutils.command.install_lib import install_lib
from distutils.version import LooseVersion
from distutils import log
# from distutils.core import setup
# from distutils.extension import Extension
from distutils import sysconfig
import json
import shutil
import numpy as np
from numpy.distutils.core import setup
import numpy.distutils.fcompiler
from numpy.distutils.extension import Extension as Extension
npExtension = Extension
INSTALL_MANIFEST = '.install_manifest.json'
RECORD_FNAME = '.temp_install_list.txt'
try:
from Cython.Build import cythonize
has_cython = True
except ImportError:
has_cython = False
if sys.version_info >= (3, 0):
PY3K = True
else:
PY3K = False
try:
FileNotFoundError
except NameError:
class FileNotFoundError(Exception):
pass
# listing the sources
cmdclass = {}
pkgs = ['viscid',
'viscid.calculator',
'viscid.cython',
'viscid.compat',
'viscid.compat.futures',
'viscid.plot',
'viscid.readers'
]
scripts = glob(os.path.join('scripts', '*'))
# list of extension objects
ext_mods = []
# cy_defs is [["path.to.module1", ["path/to/src1", "path/to/src2"], dict()],
# ["path.to.module2", ["path/to/src1", "path/to/src2"], dict()]]
# note that sources should be without extension, .pyx will be
# appended if building with cython, and .c will be appended
# if using pre-generated c files
# dict are kwargs that go into the Extension() constructor
cy_ccflags = ["-Wno-unused-function"]
cy_ldflags = []
cy_defs = []
cy_defs.append(["viscid.cython.cycalc",
["viscid/cython/cycalc"],
dict()
])
cy_defs.append(["viscid.cython.integrate",
["viscid/cython/integrate"],
dict()
])
cy_defs.append(["viscid.cython.streamline",
["viscid/cython/streamline"],
dict()
])
cy_defs.append(["viscid.cython.null_tools",
["viscid/cython/null_tools"],
dict()
])
cy_defs.append(["viscid.cython.cyfield",
["viscid/cython/cyfield"],
dict()
])
cy_defs.append(["viscid.cython.cyamr",
["viscid/cython/cyamr"],
dict()
])
fort_fcflags = []
fort_ldflags = []
fort_defs = []
fort_defs.append(["viscid.readers._fortfile",
["viscid/readers/_fortfile.F90"],
dict(define_macros=[("FSEEKABLE", 1), ("HAVE_STREAM", 1)])
])
fort_defs.append(["viscid.readers._jrrle",
["viscid/readers/_jrrle.f90"],
dict(define_macros=[("FSEEKABLE", 1), ("HAVE_STREAM", 1)])
])
############################################################################
# below this line shouldn't need to be changed except for version and stuff
# FIXME: these should be distutils commands, but they're not
try:
i = sys.argv.index("dev")
sys.argv[i] = "build_ext"
sys.argv.insert(i + 1, "-i")
sys.argv.insert(i + 1, "--with-cython")
if not has_cython:
raise RuntimeError("dev builds imply you have cython, try just using "
"'build_ext -i --with-cython' for the most general "
"build (use cython if you have it)")
except ValueError:
pass
try:
i = sys.argv.index("devclean")
sys.argv[i] = "clean"
sys.argv.insert(i + 1, "-a")
sys.argv.insert(i + 1, "--with-cython")
if not has_cython:
raise RuntimeError("devclean imply you have cython, try just using "
"'clean -a --with-cython' for the most general case "
"(clean .c files if you have cython)")
except ValueError:
pass
try:
sys.argv.remove("--with-cython")
use_cython = True
except ValueError:
use_cython = False
# prepare a cute hack to get an `uninstall`
desired_record_fname = ''
if 'install' in sys.argv:
try:
i = sys.argv.index('--record')
sys.argv.pop(i)
desired_record_fname = sys.argv[i]
sys.argv.pop(i)
except ValueError:
pass
except IndexError:
print("error: --record must be followed by a filename")
sys.exit(4)
sys.argv += ['--record', RECORD_FNAME]
# check for multicore build
_nprocs = 1
for i, arg in enumerate(sys.argv):
if arg.startswith("-j"):
try:
if arg.endswith("-j"):
# get number from the next arg
_nprocs = int(sys.argv.pop(i + 1))
else:
_nprocs = int(arg[2:])
sys.argv.pop(i)
break
except IndexError:
raise RuntimeError("Syntax for multiple process build is "
"-jN or -j N")
sys.exit(2)
except ValueError:
raise RuntimeError("Number of build procs must be an integer")
sys.exit(3)
# decide which extension to add to cython sources (pyx or c)
cy_ext = ".c" # or ".cpp"?
if has_cython and use_cython:
cy_ext = ".pyx"
# add extension to cython sources
for i, d in enumerate(cy_defs):
for j, src in enumerate(d[1]):
fname = cy_defs[i][1][j] + cy_ext
if os.path.isfile(fname):
cy_defs[i][1][j] = fname
else:
log.warn("{0} not found. Skipping extension: "
"{1}".format(fname, cy_defs[i][0]))
print("To use this extension, please install cython",
file=sys.stderr)
cy_defs[i] = None
break
def clean_pyc_files(dry_run=False):
"""remove all .pyc / .pyo files"""
cwd = os.getcwd()
if cwd.endswith("Viscid"):
for root, _, files in os.walk(cwd, topdown=False):
for name in files:
if name.endswith('.pyc') or name.endswith('.pyo'):
if os.path.isfile(os.path.join(root, name)):
print('removing: %s' % os.path.join(root, name))
if not dry_run:
os.remove(os.path.join(root, name))
else:
print("Not in Viscid directory, not cleaning pyc/pyo files")
def clean_other_so_files(valid_so_list, dry_run=False):
"""remove all .pyc / .pyo files"""
cwd = os.getcwd()
if cwd.endswith("Viscid"):
for root, _, files in os.walk(cwd, topdown=False):
for name in files:
name = os.path.join(root, name)
if name.endswith('.so') and name not in valid_so_list:
if os.path.isfile(name):
print('removing other: %s' % name)
if not dry_run:
os.remove(name)
else:
print("Not in Viscid directory, not cleaning pyc/pyo files")
# get clean to remove inplace files
class Clean(clean):
def run(self):
# distutils uses old-style classes???
#super(Clean, self).run()
clean.run(self)
clean_pyc_files(self.dry_run)
# clean inplace so files that are not in ext_modules
# this will clean old object files if cython modules move
so_file_list = []
for ext in self.distribution.ext_modules:
fn = os.path.join(*ext.name.split('.')) + ".so"
so_file_list.append(os.path.abspath(fn))
clean_other_so_files(so_file_list, self.dry_run)
if self.all:
# remove inplace extensions
for ext in self.distribution.ext_modules:
fn = os.path.join(*ext.name.split('.'))
files = [fn + ".so", fn + ".pyd"]
for fn in files:
if os.path.isfile(fn):
log.info("removing '{0}'".format(fn))
os.unlink(fn)
# remove c files if has_cython
if has_cython and use_cython:
for f in ext.sources:
if f[-4:] == ".pyx":
for rm_ext in ['.c', '.cpp']:
fn = f[:-4] + rm_ext
if os.path.isfile(fn):
log.info("removing '{0}'".format(fn))
os.unlink(fn)
cmdclass["clean"] = Clean
# this is a super hack for a single py2k compatability layer for the futures
# module. It raises an exception using an old syntax that won't byte-compile
# on install in py3k. So, to quiet the syntax error, which looks serious even
# though it's in code that's never imported in py3k, let's just not
# byte-compile that one module
if PY3K:
class InstallLib(install_lib):
def byte_compile(self, files):
files = [f for f in files if not f.endswith("compat/futures/_base.py")]
install_lib.byte_compile(self, files)
cmdclass["install_lib"] = InstallLib
# make cython extension instances
for d in cy_defs:
if d is None:
continue
src_lst = d[1]
_ext = Extension(d[0], src_lst, extra_compile_args=cy_ccflags,
extra_link_args=cy_ldflags, **d[2])
ext_mods += [_ext]
if has_cython and use_cython:
ext_mods = cythonize(ext_mods, nthreads=_nprocs)
# make fortran extension instances
try:
fc = numpy.distutils.fcompiler.new_fcompiler(dry_run=True)
except ValueError:
fc = None
if fc is None:
# warn the user at the very end so they're more likely to see the warning
pass
else:
for d in fort_defs:
if d is None:
continue
src_lst = d[1]
ext_mods += [npExtension(d[0], src_lst, extra_compile_args=fort_fcflags,
extra_link_args=fort_ldflags, **d[2])]
# hack for OSX pythons that are compiled with gcc symlinked to llvm-gcc
if sys.platform == "darwin" and "-arch" in sysconfig.get_config_var("CFLAGS"):
cc = sysconfig.get_config_var("CC")
try:
cc_version = Popen([cc, "--version"], stdout=PIPE,
stderr=PIPE).communicate()[0]
if PY3K:
cc_version = cc_version.decode()
if "MacPorts" in cc_version:
cc = "llvm-gcc"
cc = Popen(["which", cc], stdout=PIPE).communicate()[0]
if PY3K:
cc = cc.decode()
cc = cc.strip()
os.environ["CC"] = cc
print("switching compiler to", cc)
except (CalledProcessError, OSError):
print("I think there's a problem with your compiler ( CC =", cc,
"), but I'll continue anyway...")
def get_viscid_version(init_py):
with io.open(init_py, 'r', encoding="utf-8") as f:
version = None
quoted_str = r"((?<![\\])(?:'''|\"\"\"|\"|'))((?:.(?!(?<![\\])\1))*.?)\1"
ver_re = r"__version__\s*=\s*" + quoted_str
for line in f:
m = re.search(ver_re, line)
if m:
return m.groups()[1]
try:
setup(name='viscid',
version=get_viscid_version("viscid/__init__.py"),
description='Visualization in python',
author='Kris Maynard',
author_email='[email protected]',
packages=pkgs,
cmdclass=cmdclass,
include_dirs=[np.get_include()],
ext_modules=ext_mods,
scripts=scripts,
data_files=[('viscid/plot/images', glob("viscid/plot/images/*.jpg")),
('viscid/plot/styles', glob('viscid/plot/styles/*.mplstyle')),
('viscid/sample', glob("sample/*"))]
)
# if installed, store list of installed files in a json file - this
# manifest is used to implement an uninstall
if os.path.isfile(RECORD_FNAME):
try:
with open(INSTALL_MANIFEST, 'r') as fin:
inst_manifest = json.load(fin)
except (IOError, FileNotFoundError):
inst_manifest = dict()
with open(RECORD_FNAME) as fin:
file_list = [line.strip() for line in fin]
for fname in file_list:
if "__main__.py" in fname:
pkg_instdir = os.path.dirname(fname)
break
inst_manifest[sys.executable] = dict(pkg_instdir=pkg_instdir,
file_list=file_list)
with open(INSTALL_MANIFEST, 'w') as fout:
json.dump(inst_manifest, fout, indent=2, sort_keys=True)
if desired_record_fname:
shutil.copy(RECORD_FNAME, desired_record_fname)
os.remove(RECORD_FNAME)
except SystemExit as e:
if os.uname()[0] == 'Darwin':
print('\n'
'NOTE: OS X has an issue you may be running into.\n'
' If the compile is complaining that it can\'t find\n'
' -lgcc_s.10.5, then run the following:\n'
' \n'
' $ sudo su root -c "mkdir -p /usr/local/lib && ln -s '
'/usr/lib/libSystem.B.dylib /usr/local/lib/libgcc_s.10.5.dylib"'
' \n', file=sys.stderr)
raise
# warn the user at the end if the fortran code was not built
if fc is None:
print("\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"WARNING: No fortran compiler found. Modules that depend on Fortran \n"
" code will not work (eg, the jrrle reader), but this may \n"
" or may not be a problem for you since most of Viscid \n"
" does not depend on Fortran.\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"\n", file=sys.stderr)
##
## EOF
##