forked from Answeror/mlabwrap
/
setup.py
237 lines (199 loc) · 8.73 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
#!/usr/bin/env python
##############################################################################
########################### setup.py for mlabwrap ############################
##############################################################################
## o author: Alexander Schmolck (a.schmolck@gmx.net)
## o created: 2003-08-07 17:15:22+00:40
## o edited: Patrick Snape (patricksnape@gmail.com) 2013-06-25
import os
import sys
import subprocess
import argparse
from setuptools import setup, Extension
import numpy as np
from mlabwrap_utils import isWindows, find_matlab_root
# GLOBAL VARIABLES
VERSION_6_5 = [6.0, 5.0, 0.0, 0.0]
VERSION_7_0 = [7.0, 0.0, 0.0, 0.0]
VERSION_7_3 = [7.0, 3.0, 0.0, 0.0]
VALID_ARCHS = ['GLNX86', 'GLNXI64', 'GLNXA64', 'PCWIN',
'PCWIN64', 'MAC', 'MACI', 'MACI64']
def get_matlab_output(matlab_bin):
"""
Check output doesn't exist in Python < 2.7 so we need to use the old
communicate way. This doesn't poll and assumes that program writes output
and then exits.
"""
command = [matlab_bin, '-r', 'get_version', '-nosplash', '-nodesktop']
# On Windows we can't actually write to stdout apparently so we use the
# logfile trick and just sit and wait until Matlab is finished
# loading the popup command window
if isWindows():
subprocess.call(command + ['-wait', '-logfile', 'out.txt'])
with open('out.txt', 'r+') as f:
return f.read()
else:
if sys.version_info[1] < 7:
return subprocess.Popen(command,
stdout=subprocess.PIPE).communicate()[0]
else:
return subprocess.check_output(command)
def get_matlab_info(matlab_bin):
"""
Run a small Matlab script to determine the Version and Architecture (32/64)
of the given Matlab binary
"""
output = get_matlab_output(matlab_bin)
# Split by new line to separate information
# Should go Header -> Version -> Arch
output = output.split('\n')
# Contains some rubbish for the last but of output, but we ignore this
# by checking if this string contains the correct ARCH and returning that
arch_str = output[-1]
version_str = output[-2]
matlab_arch = None
for arch in VALID_ARCHS:
if arch in arch_str:
matlab_arch = arch
break
version_str = version_str.split(' ')
matlab_version = version_str[0]
# Parse version string into [major,minor,patch,build] list of floats
matlab_version = [float(x) for x in matlab_version.split('.')]
# Slice off brackets
matlab_release = version_str[1][1:-1]
return (matlab_version, matlab_release, matlab_arch)
def msvc_include_dirs():
if not 'INCLUDE' in os.environ:
raise Exception(
'Unable to find Microsoft Visual Studio include directories. '
'This is because the INCLUDE environment variable is not set. '
'In order to install using MSVC you need to run Python from within '
'a Microsft Visual Studio command prompt.')
return os.environ['INCLUDE'].split(os.path.sep)
def msvc_library_dirs():
if not 'LIB' in os.environ:
raise Exception(
'Unable to find Microsoft Visual Studio include directories. '
'This is because the LIB environment variable is not set. '
'In order to install using MSVC you need to run Python from within '
'a Microsft Visual Studio command prompt.')
return os.environ['LIB'].split(os.path.sep)
def get_extension(EXTENSION_NAME, DEFINE_MACROS, MATLAB_LIBRARY_DIRS,
MATLAB_LIBRARIES, CPP_LIBRARIES, MATLAB_INCLUDE_DIRS):
"""
We have to do this due to a bug in the compiler that means that if
the runtime library directories get passed AT ALL to the build command
then the binary fails to build on windows
"""
args = [EXTENSION_NAME, ['mlabwrap/mlabraw.cpp']]
kwargs = {
'define_macros': DEFINE_MACROS,
'library_dirs': MATLAB_LIBRARY_DIRS,
'libraries': MATLAB_LIBRARIES + CPP_LIBRARIES,
'include_dirs': MATLAB_INCLUDE_DIRS + [np.get_include()]
}
if not isWindows():
kwargs['runtime_library_dirs'] = MATLAB_LIBRARY_DIRS
return Extension(*args, **kwargs)
def main(args):
### SETUP BASE VARIABLES
MATLAB_ROOT = args.matlab_root
MATLAB_BIN = os.path.join(MATLAB_ROOT, 'bin')
MATLAB_BINARY = os.path.join(MATLAB_BIN, 'matlab')
# Add .exe if windows
if isWindows():
MATLAB_BINARY = '{0}.exe'.format(MATLAB_BINARY)
# Let's check that we DEFINITELY have a Matlab binary to use
if not os.path.exists(MATLAB_BINARY):
raise Exception(
'Unable to find Matlab binary at {0}'.format(MATLAB_BINARY))
# Now we come against the hardest part of all - finding the Matlab version.
# I can think of 3 valid ways to do this:
# 1. Parse the install directory and use a hard-coded table. However,
# complicated by the fact that there are SP versions and that every OS
# stores the directory in a different manner.
# e.g. 'R2013a' could be parsed in to '2013' and 'a' and this implies V8.1
# (take a look at http://en.wikipedia.org/wiki/MATLAB#Release_history)
# 2. Parse the Help command (matlab -h).
# Doesn't technically run Matlab but is a pain and I can't guarantee
# that all Matlab versions print the EXACT same message.
# e.g. R2013a doesn't print any version information using 'matlab -h'
# 3. Run Matlab itself and query it's 'version' command. Matlab
# documentation tells me that this command exists at least as far back
# as R14. This is the method I've chosen as it also allows me to query
# the 'computer' command which says which architecture Matlab is
# running (32 bit/64 bit). I created a short Matlab script to print
# the appropriate output to stdout
MATLAB_INFO = get_matlab_info(MATLAB_BINARY)
if None in MATLAB_INFO:
raise Exception(
'Unable to correctly parse Matlab information. '
'Found Matlab Version = {0}, Matlab Release = {1}, '
'Matlab Architecture = {2}.'.format(*MATLAB_INFO))
else:
[MATLAB_VERSION, MATLAB_RELEASE, MATLAB_ARCH] = MATLAB_INFO
# Setup include and lib directories for building the extension
MATLAB_INCLUDE_DIRS = [os.path.join(MATLAB_ROOT, 'extern', 'include')]
if isWindows():
EXTENSION_NAME = 'mlabraw'
# Strip off PC from PCWIN##
PLATFORM_DIR = MATLAB_ARCH.lower()[2:]
CPP_LIBRARIES = []
MATLAB_LIBRARIES = ['libeng', 'libmx']
MATLAB_LIBRARY_DIRS = [
os.path.join(MATLAB_ROOT, 'extern', 'lib', PLATFORM_DIR,
'microsoft')]
lib_dirs = msvc_library_dirs()
inc_dirs = msvc_library_dirs()
if lib_dirs:
MATLAB_LIBRARY_DIRS.extend(lib_dirs)
if inc_dirs:
MATLAB_INCLUDE_DIRS.extend(inc_dirs)
else: # Linux/OSX
EXTENSION_NAME = 'mlabrawmodule'
PLATFORM_DIR = MATLAB_ARCH.lower()
CPP_LIBRARIES = ['stdc++']
# Version >= 6.5
if cmp(MATLAB_VERSION, VERSION_6_5) >= 0:
MATLAB_LIBRARIES = ['eng', 'mx', 'mat', 'ut']
else:
MATLAB_LIBRARIES = ['eng', 'mx', 'mat', 'mi', 'ut']
# Version >= 7.0
if cmp(MATLAB_VERSION, VERSION_7_0) >= 0:
MATLAB_LIBRARY_DIRS = [os.path.join(MATLAB_BIN, PLATFORM_DIR)]
else:
MATLAB_LIBRARY_DIRS = [
os.path.join(MATLAB_ROOT, 'extern', 'lib', PLATFORM_DIR)]
# Version dependent defines
DEFINE_MACROS = []
# Version >= 6.5
if cmp(MATLAB_VERSION, VERSION_6_5) >= 0:
DEFINE_MACROS.append(('_V6_5_OR_LATER', 1))
# Version >= 7.3
if cmp(MATLAB_VERSION, VERSION_7_3) >= 0:
DEFINE_MACROS.append(('_V7_3_OR_LATER', 1))
setup(
name="mlabwrap",
version='1.2',
description="A high-level bridge to matlab",
author="Alexander Schmolck",
author_email="A.Schmolck@gmx.net",
url='http://mlabwrap.sourceforge.net',
packages=['mlabwrap', 'mlabwrap_utils'],
ext_package='mlabwrap',
ext_modules=[
get_extension(EXTENSION_NAME, DEFINE_MACROS, MATLAB_LIBRARY_DIRS,
MATLAB_LIBRARIES, CPP_LIBRARIES, MATLAB_INCLUDE_DIRS)
],
use_2to3=True
)
if __name__ == '__main__':
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument('--matlab-root',
help='The full path to the Matlab root '
'e.g. /usr/local/MATLAB/R2013a/',
default=find_matlab_root())
args = parser.parse_known_args()[0]
main(args)