-
Notifications
You must be signed in to change notification settings - Fork 1
/
setupext.py
388 lines (321 loc) · 12.3 KB
/
setupext.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
# -*- coding: iso-8859-1 -*-
"""
Some helper functions for building the C extensions
you may need to edit basedir to point to the default location of your
required libs, eg, png, z, freetype
DARWIN
I have installed all of the backends on OSX.
Tk: If you want to install TkAgg, I recommend the "batteries included"
binary build of Tcl/Tk at
http://www.apple.com/downloads/macosx/unix_open_source/tcltkaqua.html
GTK: I installed GTK from src as described at
http://www.macgimp.org/index.php?topic=gtk. There are several
packages, but all configure/make/make install w/o problem. In
addition to the packages listed there, You will also need libpng,
libjpeg, and libtiff if you want output to these formats from GTK.
WIN32 - MINGW
If you are sufficiently masochistic that you want to build this
yourself, download the win32_static dir from
http://matplotlib.sourceforge.net/win32_static.tar.gz and
see the README file in that dir
> python setup.py build --compiler=mingw32 bdist_wininst > build23.out
NOTE, if you are building on python24 on win32, see
http://mail.python.org/pipermail/python-list/2004-December/254826.html
WIN32 - VISUAL STUDIO 7.1 (2003)
This build is similar to the mingw. Download the visual studio static
dependencies from
http://matplotlib.sourceforge.net/win32_static_vs.tar.gz and
see the README in that dir
> python setup.py build --compiler=msvc bdist_wininst
"""
import os
import re
import subprocess
basedir = {
'win32' : ['win32_static',],
'linux2' : ['/usr/local', '/usr'],
'linux' : ['/usr/local', '/usr',],
'cygwin' : ['/usr/local', '/usr',],
'darwin' : ['/sw/lib/freetype2', '/sw/lib/freetype219', '/usr/local',
'/usr', '/sw', '/usr/X11R6'],
'freebsd4' : ['/usr/local', '/usr'],
'freebsd5' : ['/usr/local', '/usr'],
'freebsd6' : ['/usr/local', '/usr'],
'sunos5' : [os.getenv('MPLIB_BASE') or '/usr/local',],
'gnukfreebsd5' : ['/usr/local', '/usr'],
'gnukfreebsd6' : ['/usr/local', '/usr'],
'aix5' : ['/usr/local'],
}
import sys, os, stat
if sys.platform != 'win32':
import commands
from textwrap import fill
from distutils.core import Extension
import glob
import ConfigParser
import cStringIO
BUILT_PNG = False
BUILT_FT2FONT = False
# for nonstandard installation/build with --prefix variable
numpy_inc_dirs = []
# matplotlib build options, which can be altered using setup.cfg
options = {'display_status': True,
'verbose': False,
'backend': None}
# Based on the contents of setup.cfg, determine the build options
if os.path.exists("setup.cfg"):
config = ConfigParser.SafeConfigParser()
config.read("setup.cfg")
try: options['display_status'] = not config.getboolean("status", "suppress")
except: pass
try: options['verbose'] = not config.getboolean("status", "verbose")
except: pass
try: options['backend'] = config.get("rc_options", "backend")
except: pass
if options['display_status']:
def print_line(char='='):
print char * 76
def print_status(package, status):
initial_indent = "%22s: " % package
indent = ' ' * 24
print fill(str(status), width=76,
initial_indent=initial_indent,
subsequent_indent=indent)
def print_message(message):
indent = ' ' * 24 + "* "
print fill(str(message), width=76,
initial_indent=indent,
subsequent_indent=indent)
def print_raw(section):
print section
else:
def print_line(*args, **kwargs):
pass
print_status = print_message = print_raw = print_line
def run_child_process(cmd):
p = subprocess.Popen(cmd, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
close_fds=True)
return p.stdin, p.stdout
class CleanUpFile:
"""CleanUpFile deletes the specified filename when self is destroyed."""
def __init__(self, name):
self.name = name
def __del__(self):
os.remove(self.name)
def temp_copy(_from, _to):
"""temp_copy copies a named file into a named temporary file.
The temporary will be deleted when the setupext module is destructed.
"""
# Copy the file data from _from to _to
s = open(_from).read()
open(_to,"w+").write(s)
# Suppress object rebuild by preserving time stamps.
stats = os.stat(_from)
os.utime(_to, (stats.st_atime, stats.st_mtime))
# Make an object to eliminate the temporary file at exit time.
globals()["_cleanup_"+_to] = CleanUpFile(_to)
def get_win32_compiler():
# Used to determine mingw32 or msvc
# This is pretty bad logic, someone know a better way?
for v in sys.argv:
if 'mingw32' in v:
return 'mingw32'
return 'msvc'
win32_compiler = get_win32_compiler()
if sys.platform == 'win32' and win32_compiler == 'msvc':
std_libs = []
else:
std_libs = ['stdc++', 'm']
def has_pkgconfig():
if has_pkgconfig.cache is not None:
return has_pkgconfig.cache
if sys.platform == 'win32':
has_pkgconfig.cache = False
else:
#print 'environ', os.environ['PKG_CONFIG_PATH']
status, output = commands.getstatusoutput("pkg-config --help")
has_pkgconfig.cache = (status == 0)
return has_pkgconfig.cache
has_pkgconfig.cache = None
def get_pkgconfig(module,
packages,
flags="--libs --cflags",
pkg_config_exec='pkg-config',
report_error=False):
"""Loosely based on an article in the Python Cookbook:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502261"""
if not has_pkgconfig():
return False
_flags = {'-I': 'include_dirs',
'-L': 'library_dirs',
'-l': 'libraries',
'-D': 'define_macros',
'-U': 'undef_macros'}
cmd = "%s %s %s" % (pkg_config_exec, flags, packages)
status, output = commands.getstatusoutput(cmd)
if status == 0:
for token in output.split():
attr = _flags.get(token[:2], None)
if attr is not None:
if token[:2] == '-D':
value = tuple(token[2:].split('='))
if len(value) == 1:
value = (value[0], None)
else:
value = token[2:]
set = getattr(module, attr)
if value not in set:
set.append(value)
else:
if token not in module.extra_link_args:
module.extra_link_args.append(token)
return True
if report_error:
print_status("pkg-config", "looking for %s" % packages)
print_message(output)
return False
def get_pkgconfig_version(package):
default = "found, but unknown version (no pkg-config)"
if not has_pkgconfig():
return default
status, output = commands.getstatusoutput(
"pkg-config %s --modversion" % (package))
if status == 0:
return output
return default
def try_pkgconfig(module, package, fallback):
if not get_pkgconfig(module, package):
module.libraries.append(fallback)
def find_include_file(include_dirs, filename):
for d in include_dirs:
if os.path.exists(os.path.join(d, filename)):
return True
return False
def check_for_freetype():
module = Extension('test', [])
add_base_flags(module)
if not get_pkgconfig(module, 'freetype2'):
basedirs = module.include_dirs[:] # copy the list to avoid inf loop!
for d in basedirs:
module.include_dirs.append(os.path.join(d, 'freetype2'))
print_status("freetype2", get_pkgconfig_version('freetype2'))
if not find_include_file(module.include_dirs, 'ft2build.h'):
print_message(
"WARNING: Could not find 'freetype2' headers in any of %s." %
", ".join(["'%s'" % x for x in module.include_dirs]))
return True
def check_for_libpng():
module = Extension("test", [])
get_pkgconfig(module, 'libpng')
add_base_flags(module)
print_status("libpng", get_pkgconfig_version('libpng'))
if not find_include_file(module.include_dirs, 'png.h'):
print_message(
"Could not find 'libpng' headers in any of %s" %
", ".join(["'%s'" % x for x in module.include_dirs]))
return True
def add_base_flags(module):
incdirs = filter(os.path.exists,
[os.path.join(p, 'include') for p in basedir[sys.platform] ])
libdirs = filter(os.path.exists,
[os.path.join(p, 'lib') for p in basedir[sys.platform] ]+
[os.path.join(p, 'lib64') for p in basedir[sys.platform] ] )
module.include_dirs.extend(incdirs)
module.include_dirs.append('.')
module.library_dirs.extend(libdirs)
def getoutput(s):
'get the output of a system command'
ret = os.popen(s).read().strip()
return ret
def check_for_numpy():
try:
import numpy
except ImportError:
print_status("numpy", "no")
print_message("You must install numpy 1.1 or later to build matplotlib.")
return False
nn = numpy.__version__.split('.')
if not (int(nn[0]) >= 1 and int(nn[1]) >= 1):
print_message(
'numpy 1.1 or later is required; you have %s' % numpy.__version__)
return False
module = Extension('test', [])
add_numpy_flags(module)
add_base_flags(module)
print_status("numpy", numpy.__version__)
if not find_include_file(module.include_dirs, os.path.join("numpy", "arrayobject.h")):
print_message("Could not find the headers for numpy. You may need to install the development package.")
return False
return True
def add_numpy_flags(module):
"Add the modules flags to build extensions which use numpy"
import numpy
module.include_dirs.append(numpy.get_include())
def add_png_flags(module):
try_pkgconfig(module, 'libpng', 'png')
add_base_flags(module)
add_numpy_flags(module)
module.libraries.append('z')
module.include_dirs.extend(['.'])
module.libraries.extend(std_libs)
def add_ft2font_flags(module):
'Add the module flags to ft2font extension'
add_numpy_flags(module)
if not get_pkgconfig(module, 'freetype2'):
module.libraries.extend(['freetype', 'z'])
add_base_flags(module)
basedirs = module.include_dirs[:] # copy the list to avoid inf loop!
for d in basedirs:
module.include_dirs.append(os.path.join(d, 'freetype2'))
p = os.path.join(d, 'lib/freetype2/include')
if os.path.exists(p): module.include_dirs.append(p)
p = os.path.join(d, 'lib/freetype2/include/freetype2')
if os.path.exists(p): module.include_dirs.append(p)
basedirs = module.library_dirs[:] # copy the list to avoid inf loop!
for d in basedirs:
p = os.path.join(d, 'freetype2/lib')
if os.path.exists(p): module.library_dirs.append(p)
else:
add_base_flags(module)
module.libraries.append('z')
# put this last for library link order
module.libraries.extend(std_libs)
def check_for_macosx():
gotit = False
import sys
if sys.platform=='darwin':
gotit = True
if gotit:
print_status("Mac OS X native", "yes")
else:
print_status("Mac OS X native", "no")
return gotit
def build_ft2font(ext_modules, packages):
global BUILT_FT2FONT
if BUILT_FT2FONT: return # only build it if you you haven't already
deps = ['src/ft2font.cpp', 'src/mplutils.cpp']
deps.extend(glob.glob('CXX/*.cxx'))
deps.extend(glob.glob('CXX/*.c'))
module = Extension('mathtex.ft2font', deps,
define_macros=[('PY_ARRAYAUNIQUE_SYMBOL', 'MPL_ARRAY_API')])
add_ft2font_flags(module)
ext_modules.append(module)
BUILT_FT2FONT = True
def build_png(ext_modules, packages):
global BUILT_PNG
if BUILT_PNG: return # only build it if you you haven't already
deps = ['src/_png.cpp', 'src/mplutils.cpp']
deps.extend(glob.glob('CXX/*.cxx'))
deps.extend(glob.glob('CXX/*.c'))
module = Extension(
'mathtex._png',
deps,
include_dirs=numpy_inc_dirs,
define_macros=[('PY_ARRAY_UNIQUE_SYMBOL', 'MPL_ARRAY_API')]
)
add_png_flags(module)
ext_modules.append(module)
BUILT_PNG = True