Skip to content

Commit b50da45

Browse files
author
Carlos Hernandez
committed
add devtools
1 parent 21457c9 commit b50da45

23 files changed

+886
-776
lines changed

.travis.yml

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
language: python
1+
language: c
2+
sudo: false
23

3-
before_install:
4-
- sudo apt-get update
5-
- wget http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
6-
- bash miniconda.sh -b -p $HOME/miniconda
7-
- export PATH="$HOME/miniconda/bin:$PATH"
8-
- hash -r
9-
- conda config --set always_yes yes --set changeps1 no
10-
- conda update -q conda
11-
- conda install numpy scipy pandas scikit-learn nose
12-
- conda install -c omnia mdtraj msmbuilder nose-timer
4+
env:
5+
matrix:
6+
- CONDA_PY=3.4
7+
- CONDA_PY=3.5
8+
9+
branches:
10+
only:
11+
- master
1312

1413
install:
15-
- python setup.py install
14+
- source devtools/travis-ci/install_miniconda.sh
15+
- conda config --add channels omnia
16+
- conda install -yq python-coveralls
1617

1718
script:
18-
- nosetests -v --with-timer
19+
- conda build --quiet devtools/conda-recipe
1920

20-
after_success:
21-
- echo 'after_success'
21+
# after_success:
22+
# - cp $HOME/miniconda3/conda-bld/test-tmp_dir/.coverage .
23+
# - coveralls

LICENSE

Lines changed: 17 additions & 669 deletions
Large diffs are not rendered by default.

MANIFEST.in

Lines changed: 0 additions & 2 deletions
This file was deleted.

basesetup.py

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
from __future__ import print_function, absolute_import
2+
import os
3+
import sys
4+
import imp
5+
import json
6+
import shutil
7+
import subprocess
8+
import tempfile
9+
from distutils.dep_util import newer_group
10+
from distutils.core import Extension
11+
from distutils.errors import DistutilsExecError, DistutilsSetupError
12+
from distutils.ccompiler import new_compiler
13+
from distutils.sysconfig import customize_compiler, get_config_vars
14+
from distutils.command.build_ext import build_ext as _build_ext
15+
16+
17+
def check_dependencies(dependencies):
18+
def module_exists(dep):
19+
try:
20+
imp.find_module(dep)
21+
return True
22+
except ImportError:
23+
return False
24+
25+
for dep in dependencies:
26+
if len(dep) == 1:
27+
import_name, pkg_name = dep[0], dep[0]
28+
elif len(dep) == 2:
29+
import_name, pkg_name = dep
30+
else:
31+
raise ValueError(dep)
32+
33+
if not module_exists(import_name):
34+
lines = [
35+
'-' * 50,
36+
'Warning: This package requires %r. Try' % import_name,
37+
'',
38+
' $ conda install %s' % pkg_name,
39+
'',
40+
'or:',
41+
'',
42+
' $ pip install %s' % pkg_name,
43+
'-' * 50,
44+
]
45+
print(os.linesep.join(lines), file=sys.stderr)
46+
47+
48+
class CompilerDetection(object):
49+
# Necessary for OSX. See https://github.com/mdtraj/mdtraj/issues/576
50+
# The problem is that distutils.sysconfig.customize_compiler()
51+
# is necessary to properly invoke the correct compiler for this class
52+
# (otherwise the CC env variable isn't respected). Unfortunately,
53+
# distutils.sysconfig.customize_compiler() DIES on OSX unless some
54+
# appropriate initialization routines have been called. This line
55+
# has a side effect of calling those initialzation routes, and is therefor
56+
# necessary for OSX, even though we don't use the result.
57+
_DONT_REMOVE_ME = get_config_vars()
58+
59+
def __init__(self, disable_openmp):
60+
cc = new_compiler()
61+
customize_compiler(cc)
62+
63+
self.msvc = cc.compiler_type == 'msvc'
64+
self._print_compiler_version(cc)
65+
66+
if disable_openmp:
67+
self.openmp_enabled = False
68+
else:
69+
self.openmp_enabled, openmp_needs_gomp = self._detect_openmp()
70+
self.sse3_enabled = self._detect_sse3() if not self.msvc else True
71+
self.sse41_enabled = self._detect_sse41() if not self.msvc else True
72+
73+
self.compiler_args_sse2 = (['-msse2'] if not self.msvc else
74+
['/arch:SSE2'])
75+
self.compiler_args_sse3 = ['-mssse3'] if (self.sse3_enabled and
76+
not self.msvc) else []
77+
78+
self.compiler_args_sse41, self.define_macros_sse41 = [], []
79+
if self.sse41_enabled:
80+
self.define_macros_sse41 = [('__SSE4__', 1), ('__SSE4_1__', 1)]
81+
if not self.msvc:
82+
self.compiler_args_sse41 = ['-msse4']
83+
84+
if self.openmp_enabled:
85+
self.compiler_libraries_openmp = []
86+
87+
if self.msvc:
88+
self.compiler_args_openmp = ['/openmp']
89+
else:
90+
self.compiler_args_openmp = ['-fopenmp']
91+
if openmp_needs_gomp:
92+
self.compiler_libraries_openmp = ['gomp']
93+
else:
94+
self.compiler_libraries_openmp = []
95+
self.compiler_args_openmp = []
96+
97+
if self.msvc:
98+
self.compiler_args_opt = ['/O2']
99+
else:
100+
self.compiler_args_opt = ['-O3', '-funroll-loops']
101+
print()
102+
103+
def _print_compiler_version(self, cc):
104+
print("C compiler:")
105+
try:
106+
if self.msvc:
107+
if not cc.initialized:
108+
cc.initialize()
109+
cc.spawn([cc.cc])
110+
else:
111+
cc.spawn([cc.compiler[0]] + ['-v'])
112+
except DistutilsExecError:
113+
pass
114+
115+
def hasfunction(self, funcname, include=None, libraries=None,
116+
extra_postargs=None):
117+
# running in a separate subshell lets us prevent unwanted stdout/stderr
118+
part1 = '''
119+
from __future__ import print_function
120+
import os
121+
import json
122+
from distutils.ccompiler import new_compiler
123+
from distutils.sysconfig import customize_compiler, get_config_vars
124+
125+
FUNCNAME = json.loads('%(funcname)s')
126+
INCLUDE = json.loads('%(include)s')
127+
LIBRARIES = json.loads('%(libraries)s')
128+
EXTRA_POSTARGS = json.loads('%(extra_postargs)s')
129+
''' % {
130+
'funcname': json.dumps(funcname),
131+
'include': json.dumps(include),
132+
'libraries': json.dumps(libraries or []),
133+
'extra_postargs': json.dumps(extra_postargs)}
134+
135+
part2 = '''
136+
get_config_vars() # DON'T REMOVE ME
137+
cc = new_compiler()
138+
customize_compiler(cc)
139+
for library in LIBRARIES:
140+
cc.add_library(library)
141+
142+
status = 0
143+
try:
144+
with open('func.c', 'w') as f:
145+
if INCLUDE is not None:
146+
f.write('#include %s\\n' % INCLUDE)
147+
f.write('int main(void) {\\n')
148+
f.write(' %s;\\n' % FUNCNAME)
149+
f.write('}\\n')
150+
objects = cc.compile(['func.c'], output_dir='.',
151+
extra_postargs=EXTRA_POSTARGS)
152+
cc.link_executable(objects, 'a.out')
153+
except Exception as e:
154+
status = 1
155+
exit(status)
156+
'''
157+
tmpdir = tempfile.mkdtemp(prefix='hasfunction-')
158+
try:
159+
curdir = os.path.abspath(os.curdir)
160+
os.chdir(tmpdir)
161+
with open('script.py', 'w') as f:
162+
f.write(part1 + part2)
163+
proc = subprocess.Popen(
164+
[sys.executable, 'script.py'],
165+
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
166+
proc.communicate()
167+
status = proc.wait()
168+
finally:
169+
os.chdir(curdir)
170+
shutil.rmtree(tmpdir)
171+
172+
return status == 0
173+
174+
def _print_support_start(self, feature):
175+
print('Attempting to autodetect {0:6} support...'.format(
176+
feature), end=' ')
177+
178+
def _print_support_end(self, feature, status):
179+
if status is True:
180+
print('Compiler supports {0}'.format(feature))
181+
else:
182+
print('Did not detect {0} support'.format(feature))
183+
184+
def _detect_openmp(self):
185+
self._print_support_start('OpenMP')
186+
hasopenmp = self.hasfunction('omp_get_num_threads()', extra_postargs=[
187+
'-fopenmp', '/openmp'])
188+
needs_gomp = hasopenmp
189+
if not hasopenmp:
190+
hasopenmp = self.hasfunction(
191+
'omp_get_num_threads()', libraries=['gomp'])
192+
needs_gomp = hasopenmp
193+
self._print_support_end('OpenMP', hasopenmp)
194+
return hasopenmp, needs_gomp
195+
196+
def _detect_sse3(self):
197+
"Does this compiler support SSE3 intrinsics?"
198+
self._print_support_start('SSE3')
199+
result = self.hasfunction('__m128 v; _mm_hadd_ps(v,v)',
200+
include='<pmmintrin.h>',
201+
extra_postargs=['-msse3'])
202+
self._print_support_end('SSE3', result)
203+
return result
204+
205+
def _detect_sse41(self):
206+
"Does this compiler support SSE4.1 intrinsics?"
207+
self._print_support_start('SSE4.1')
208+
result = self.hasfunction('__m128 v; _mm_round_ps(v,0x00)',
209+
include='<smmintrin.h>',
210+
extra_postargs=['-msse4'])
211+
self._print_support_end('SSE4.1', result)
212+
return result
213+
214+
215+
def git_version():
216+
# Return the git revision as a string
217+
# copied from numpy setup.py
218+
def _minimal_ext_cmd(cmd):
219+
# construct minimal environment
220+
env = {}
221+
for k in ['SYSTEMROOT', 'PATH']:
222+
v = os.environ.get(k)
223+
if v is not None:
224+
env[k] = v
225+
# LANGUAGE is used on win32
226+
env['LANGUAGE'] = 'C'
227+
env['LANG'] = 'C'
228+
env['LC_ALL'] = 'C'
229+
out = subprocess.Popen(
230+
cmd, stdout=subprocess.PIPE, env=env).communicate()[0]
231+
return out
232+
233+
try:
234+
out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD'])
235+
GIT_REVISION = out.strip().decode('ascii')
236+
except OSError:
237+
GIT_REVISION = 'Unknown'
238+
239+
return GIT_REVISION
240+
241+
242+
def write_version_py(version, isreleased, filename):
243+
cnt = """
244+
# This file is generated in setup.py at build time.
245+
version = '{version}'
246+
short_version = '{short_version}'
247+
full_version = '{full_version}'
248+
git_revision = '{git_revision}'
249+
release = {release}
250+
"""
251+
# git_revision
252+
if os.path.exists('.git'):
253+
git_revision = git_version()
254+
else:
255+
git_revision = 'Unknown'
256+
257+
# short_version, full_version
258+
if isreleased:
259+
full_version = version
260+
short_version = version
261+
else:
262+
full_version = ("{version}+{git_revision}"
263+
.format(version=version, git_revision=git_revision))
264+
short_version = version
265+
266+
with open(filename, 'w') as f:
267+
f.write(cnt.format(version=version,
268+
short_version=short_version,
269+
full_version=full_version,
270+
git_revision=git_revision,
271+
release=isreleased))
272+
273+
274+
class StaticLibrary(Extension):
275+
276+
def __init__(self, *args, **kwargs):
277+
self.export_include = kwargs.pop('export_include', [])
278+
Extension.__init__(self, *args, **kwargs)
279+
280+
281+
class build_ext(_build_ext):
282+
283+
def build_extension(self, ext):
284+
if isinstance(ext, StaticLibrary):
285+
self.build_static_extension(ext)
286+
else:
287+
_build_ext.build_extension(self, ext)
288+
289+
def build_static_extension(self, ext):
290+
from distutils import log
291+
292+
sources = ext.sources
293+
if sources is None or not isinstance(sources, (list, tuple)):
294+
raise DistutilsSetupError(
295+
("in 'ext_modules' option (extension '%s'), " +
296+
"'sources' must be present and must be " +
297+
"a list of source filenames") % ext.name)
298+
sources = list(sources)
299+
300+
ext_path = self.get_ext_fullpath(ext.name)
301+
depends = sources + ext.depends
302+
if not (self.force or newer_group(depends, ext_path, 'newer')):
303+
log.debug("skipping '%s' extension (up-to-date)", ext.name)
304+
return
305+
else:
306+
log.info("building '%s' extension", ext.name)
307+
308+
extra_args = ext.extra_compile_args or []
309+
macros = ext.define_macros[:]
310+
for undef in ext.undef_macros:
311+
macros.append((undef,))
312+
objects = self.compiler.compile(sources,
313+
output_dir=self.build_temp,
314+
macros=macros,
315+
include_dirs=ext.include_dirs,
316+
debug=self.debug,
317+
extra_postargs=extra_args,
318+
depends=ext.depends)
319+
self._built_objects = objects[:]
320+
if ext.extra_objects:
321+
objects.extend(ext.extra_objects)
322+
extra_args = ext.extra_link_args or []
323+
324+
language = ext.language or self.compiler.detect_language(sources)
325+
326+
libname = os.path.splitext(os.path.basename(ext_path))[0]
327+
output_dir = os.path.dirname(ext_path)
328+
if (self.compiler.static_lib_format.startswith('lib') and
329+
libname.startswith('lib')):
330+
libname = libname[3:]
331+
332+
if not os.path.exists(output_dir):
333+
# necessary for windows
334+
os.makedirs(output_dir)
335+
336+
self.compiler.create_static_lib(objects,
337+
output_libname=libname,
338+
output_dir=output_dir,
339+
target_lang=language)
340+
341+
for item in ext.export_include:
342+
shutil.copy(item, output_dir)

0 commit comments

Comments
 (0)