-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsetup.py
173 lines (135 loc) · 5.63 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
import setuptools # necessary for install_requires
from distutils.core import Command
from numpy.distutils.core import Extension
from numpy.distutils.command.build_clib import build_clib
from numpy.distutils.command.build_ext import build_ext
from numpy.distutils.command.sdist import sdist
from numpy.distutils.command.build import build
from distutils.command.clean import clean
from Cython.Build import cythonize
from glob import glob
import os
import numpy
import shutil
# base directory of package
package_basedir = os.path.abspath(os.path.dirname(__file__))
def find_version(path, name='version'):
import re
# path shall be a plain ascii text file.
s = open(path, 'rt').read()
version_match = re.search(r"^%s = ['\"]([^'\"]*)['\"]" %name,
s, re.M)
if version_match:
return version_match.group(1)
raise RuntimeError("version not found")
CLASS_VERSION = find_version("classylss/version.py", name='class_version')
def build_CLASS(prefix):
"""
Function to dowwnload CLASS from github and and build the library
"""
# latest class version and download link
args = (package_basedir, package_basedir, CLASS_VERSION, os.path.abspath(prefix))
command = 'sh %s/depends/install_class.sh %s %s %s' %args
ret = os.system(command)
if ret != 0:
raise ValueError("could not build CLASS v%s" %CLASS_VERSION)
class build_external_clib(build_clib):
"""
Custom command to build CLASS first, and then GCL library
"""
def finalize_options(self):
build_clib.finalize_options(self)
# create the CLASS build directory and save the include path
self.class_build_dir = self.build_temp
self.include_dirs.insert(0, os.path.join(self.class_build_dir, 'include'))
def build_libraries(self, libraries):
# build CLASS first
build_CLASS(self.class_build_dir)
# update the link objects with CLASS library
link_objects = ['libclass.a']
link_objects = list(glob(os.path.join(self.class_build_dir, '*', 'libclass.a')))
self.compiler.set_link_objects(link_objects)
self.compiler.library_dirs.insert(0, os.path.join(self.class_build_dir, 'lib'))
# then no longer need to build class.
libraries = [lib for lib in libraries if lib[0] != 'class']
for (library, build_info) in libraries:
# check swig version
if library == "gcl" and swig_needed:
check_swig_version()
# update include dirs
self.include_dirs += build_info.get('include_dirs', [])
build_clib.build_libraries(self, libraries)
class custom_build_ext(build_ext):
"""
Custom extension building to grab include directories
from the ``build_clib`` command
"""
def finalize_options(self):
build_ext.finalize_options(self)
self.include_dirs.append(numpy.get_include())
def run(self):
if self.distribution.has_c_libraries():
self.run_command('build_clib')
build_clib = self.get_finalized_command('build_clib')
self.include_dirs += build_clib.include_dirs
self.library_dirs += build_clib.compiler.library_dirs
# copy data files from temp to classlssy package directory
shutil.rmtree(os.path.join(self.build_lib, 'classylss', 'data'), ignore_errors=True)
shutil.copytree(os.path.join(self.build_temp, 'data'), os.path.join(self.build_lib, 'classylss', 'data'))
build_ext.run(self)
class custom_sdist(sdist):
def run(self):
from six.moves.urllib import request
# download CLASS
tarball_link = "https://github.com/lesgourg/class_public/archive/v%s.tar.gz" %CLASS_VERSION
tarball_local = os.path.join('depends', 'class-v%s.tar.gz' %CLASS_VERSION)
request.urlretrieve(tarball_link, tarball_local)
# run the default
sdist.run(self)
class custom_clean(clean):
def run(self):
# run the built-in clean
clean.run(self)
# remove the CLASS tmp directories
os.system("rm -rf depends/tmp*")
# remove build directory
if os.path.exists('build'):
shutil.rmtree('build')
def libclass_config():
return ('class', {})
def classy_extension_config():
# the configuration for GCL python extension
config = {}
config['name'] = 'classylss.binding'
config['extra_link_args'] = ['-g', '-fPIC']
config['extra_compile_args'] = []
# important or get a symbol not found error, because class is
# compiled with c++?
config['language'] = 'c'
config['libraries'] = ['class', 'gfortran', 'm']
# determine if swig needs to be called
config['sources'] = ['classylss/binding.pyx']
return config
if __name__ == '__main__':
from numpy.distutils.core import setup
setup(name='classylss',
version=find_version("classylss/version.py"),
author='Nick Hand, Yu Feng',
author_email='[email protected]',
description="lightweight Python binding of the CLASS CMB Boltzmann code",
license='GPL3',
url="http://github.com/nickhand/classylss",
install_requires=['numpy', 'cython', 'six'],
extras_require={'tests': ['runtests', 'astropy', 'scipy']},
ext_modules = cythonize([
Extension(**classy_extension_config())
]),
libraries=[libclass_config()],
cmdclass = {
'sdist': custom_sdist,
'build_clib': build_external_clib,
'build_ext': custom_build_ext,
'clean': custom_clean
},
packages=['classylss', 'classylss.tests']
)