-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsetup.py
156 lines (140 loc) · 5.98 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
# $File: setup.py $
# $LastChangedDate: $
# $Rev: $
# Copyright (c) 2014, Gao Wang <[email protected]>
# GNU General Public License (http://www.gnu.org/licenses/gpl.html)
from distutils.core import setup, Extension
# from distutils.dep_util import newer
try:
from distutils.command.build_py import build_py_2to3 as build_py
except ImportError:
from distutils.command.build_py import build_py
# monkey-patch for parallel compilation
import multiprocessing, multiprocessing.pool
def compile_parallel(
self,
sources,
output_dir=None,
macros=None,
include_dirs=None,
debug=0,
extra_preargs=None,
extra_postargs=None,
depends=None):
# Copied from distutils.ccompiler.CCompiler
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(
output_dir, macros, include_dirs, sources, depends, extra_postargs)
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
#
def _single_compile(obj):
try:
src, ext = build[obj]
except KeyError:
return
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
# convert to list, imap is evaluated on-demand
list(multiprocessing.pool.ThreadPool(multiprocessing.cpu_count()).imap(_single_compile, objects))
return objects
import distutils.ccompiler
distutils.ccompiler.CCompiler.compile=compile_parallel
import sys, os, subprocess, platform
from glob import glob
from src import NAME, VERSION
if VERSION is None:
VERSION = 'rev{}'.format(subprocess.check_output('cat src/.revision', shell=True).strip())
# use ccache to speed up build
try:
if subprocess.call(['ccache'], stderr = open(os.devnull, "w")):
os.environ['CC'] = 'ccache clang -Qunused-arguments' if platform.system() == 'Darwin' else 'ccache gcc'
except OSError:
pass
SWIG_OPTS = ['-c++', '-python', '-O', '-shadow', '-keyword',
'-w-511', '-w-509', '-outdir', '.']
#SWIG_PYGSL_OPTS = ['-python', '-keyword', '-outdir', '.']
if sys.version_info.major == 2:
PYVERSION = 'py2'
else:
SWIG_OPTS.append('-py3')
# SWIG_PYGSL_OPTS.append('-py3')
PYVERSION = 'py3'
#
def getfn(fn, prefix = "src/umich"):
if type(fn) is list:
return sum([glob(os.path.join(prefix, x)) if "*" in x else [os.path.join(prefix, x)] for x in fn], [])
else:
return glob(os.path.join(prefix, fn)) if "*" in fn else os.path.join(prefix, fn)
#
HEADER = getfn("*.hpp", "src")
CPP = getfn("*.cpp", "src")
WRAPPER_CPP = getfn('cstatgen_{0}.cxx'.format(PYVERSION), "src")
WRAPPER_PY = getfn('cstatgen_{0}.py'.format(PYVERSION), "src")
WRAPPER_I = getfn('cstatgen.i', "src")
# generate wrapper files
try:
try:
ret = subprocess.call(['swig', '-python', '-external-runtime', 'src/third/swigpyrun.h'], shell=False)
except:
SWIG_SUPPORT = False
sys.stderr.write('\033[1;91mSWIG program is not avaiable. Using existing wrapper code, which might be problematic.\033[0m\n')
else:
SWIG_SUPPORT = True
#
if SWIG_SUPPORT and (not os.path.isfile(WRAPPER_PY) or not os.path.isfile(WRAPPER_CPP) or \
os.path.getmtime(WRAPPER_CPP) < max([os.path.getmtime(x) for x in [WRAPPER_I] + HEADER + CPP])):
ret = subprocess.call(['swig'] + SWIG_OPTS + ['-o', WRAPPER_CPP, WRAPPER_I], shell=False)
if ret != 0:
sys.exit('Failed to generate cstatgen C++ extension.')
os.rename('cstatgen.py', WRAPPER_PY)
except OSError as e:
sys.exit('Failed to generate wrapper file: {0}'.format(e))
# Under linux/gcc, lib stdc++ is needed for C++ based extension.
libs = ['stdc++'] if sys.platform == 'linux2' else []
link_args = ["-lm", "-lz", "-lgsl","-lgslcblas"]
#
compile_args_umich = ["-O3", "-shared", "-std=c++11", "-D_FILE_OFFSET_BITS=64", "-D__ZLIB_AVAILABLE__"]#, "-o","umichlib.so","-fPIC"]
# "-static", "-static-libgcc", "-static-libstdc++", "-fPIC"]
UMICH_FILES = getfn(["clusters/*.cpp", "libsrc/*.cpp", "merlin/*.cpp", "regression/*.cpp",
"rvtests/*.cpp", "base/*.cpp", "pdf/*.cpp", "klib/*.c", "general/*.cpp", "vcf/*.cpp"])
os.system("cd src/third/libMvtnorm; make; cd -")
CSTATGEN_MODULE = [
Extension('{}._cstatgen'.format(NAME),
sources = [WRAPPER_CPP] + CPP + UMICH_FILES, # + getfn(LIB_GSL),
extra_compile_args = compile_args_umich,
extra_link_args = link_args,
libraries = libs + ["Mvtnorm"],
library_dirs = ["src/third/libMvtnorm"],
include_dirs = getfn([".", "general", "klib", "vcf", "clusters", "libsrc", "base",
"merlin", "regression", "rvtests", "pdf","eigen"]) + \
["src", "src/third"]
)
]
packages = [NAME]
package_data = {}
ext_modules = CSTATGEN_MODULE
if sys.version_info.major == 2:
compile_args_egglib = ["-O3", "-std=c++11", "-UHAVE_LIBBPP_SEQ", "-UHAVE_LIBBPP_CORE", "-UHAVE_LIBGSLCBLAS"]
# exclude two modules due to lack of gsl and bio++; egglib should have used macro to control for it, though
EGGLIB_FILES = [x for x in getfn("egglib-cpp/*.cpp", prefix = "src/egglib") if not (x.endswith("ABC.cpp") or x.endswith("BppDiversity.cpp"))]
EGGLIB_MODULE = [
Extension('_egglib_binding',
sources = ["src/egglib/egglib_binding.cpp"] + EGGLIB_FILES,
extra_compile_args = compile_args_egglib,
extra_link_args = link_args,
libraries = libs,
library_dirs = [],
include_dirs = getfn(["egglib/egglib-cpp", "egglib"], prefix = "src")
)
]
packages += [NAME + ".egglib"]
package_data[NAME + ".egglib"]=['apps.conf']
ext_modules += EGGLIB_MODULE
setup(name = NAME,
version = VERSION,
description = "Gao Wang's statgen library",
author = "Gao Wang",
package_dir = {NAME:'src'},
cmdclass = {'build_py': build_py},
packages = packages,
package_data = package_data,
ext_modules = ext_modules
)