File: setup.py

package info (click to toggle)
psychtoolbox-3 3.0.15.20190207.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 101,848 kB
  • sloc: ansic: 174,133; cpp: 11,232; objc: 4,832; sh: 1,874; python: 1,047; php: 384; makefile: 189; java: 113
file content (244 lines) | stat: -rw-r--r-- 11,527 bytes parent folder | download | duplicates (2)
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
# setup.py -- Build-Script for building Psychtoolbox-3 "mex" files as Python extensions.
#
# (c) 2018 Mario Kleiner - Licensed under MIT license.
#

from distutils.core import setup, Extension # Build system.
import os, fnmatch, shutil                  # Directory traversal, file list building.
import platform                             # OS detection.
import sys                                  # cpu arch detection.
import numpy                                # To get include dir on macOS.

def get_sourcefiles(path):
    sources = [];
    pattern1 = '*.c';
    pattern2 = '*.cpp';
    for filename in os.listdir(path):
        if fnmatch.fnmatch(filename, pattern1) or fnmatch.fnmatch(filename, pattern2):
            sources += [os.path.join(path,filename)];

    # Fancy schmanzi, not needed atm. for recursive dir traversal:
    #    for root, dirs, files in os.walk(path):
    #        for filename in files:
    #            sources += [os.path.join(root,filename)];

    return(sources);

def get_basemacros(name, osname):
    return([('PTBMODULE_' + name, None), ('PTBMODULENAME', name)] + base_macros);

def get_baseincludedirs(name, osname):
    return(['PsychSourceGL/Source/Common/' + name] + baseincludes_common + ['PsychSourceGL/Source/' + osname + '/Base'] + ['PsychSourceGL/Source/' + osname + '/' + name]);

def get_basesources(name, osname):
    extrafiles = [];
    if os.access('./PsychSourceGL/Source/' + osname + '/' + name, os.F_OK):
         extrafiles = get_sourcefiles('./PsychSourceGL/Source/' + osname + '/' + name);

    return(basefiles_common + get_sourcefiles('./PsychSourceGL/Source/' + osname + '/Base/') + get_sourcefiles('./PsychSourceGL/Source/Common/' + name) + extrafiles);

# Treating some special cases like Octave seems to be the right thing to do,
# PSYCH_LANGUAGE setting is self-explanatory:
base_macros = [('PTBOCTAVE3MEX', None), ('PSYCH_LANGUAGE', 'PSYCH_PYTHON')];
# Disabled: This would enable Py_LIMITED_API, to allow to build one set of modules for all versions of
# Python >= 3.2. The downside is loss of important functionality [PsychRuntimeEvaluateString()) does not work!].
# Also, we have build failure on at least Ubuntu 18.04 LTS with Python 3.6, so it is a no-go on Linux for now!
#base_macros = [('PTBOCTAVE3MEX', None), ('PSYCH_LANGUAGE', 'PSYCH_PYTHON'), ('Py_LIMITED_API', None)];

# Common infrastructure and the scripting glue module for interfacing with the Python runtime:
basefiles_common = get_sourcefiles('./PsychSourceGL/Source/Common/Base') + ['PsychSourceGL/Source/Common/Base/PythonGlue/PsychScriptingGluePython.c'];
baseincludes_common = [numpy.get_include(), 'PsychSourceGL/Source/Common/Base', 'PsychSourceGL/Source/Common/Screen'];

is_64bits = sys.maxsize > 2**32;

# OS detection and file selection for the different OS specific backends:
print('Platform reported as: %s\n' % platform.system());
if platform.system() == 'Linux':
    # Linux specific backend code:
    print('Building for Linux...\n');
    osname = 'Linux';
    # All libraries to link to all modules:
    base_libs = ['c', 'rt', 'dl'];
    # No "no reproducible builds" warning:
    base_compile_args = ['-Wno-date-time'];
    # Extra OS specific libs for PsychPortAudio:
    audio_libdirs = [];
    audio_extralinkargs = [];
    audio_libs = ['portaudio', 'asound'];
    audio_objects = [];

    # Static linking for audio_objects aka libportaudio.a no longer used as of v3.0.15:
    #if is_64bits == True:
    #    audio_objects = ['PsychSourceGL/Cohorts/PortAudio/libportaudio64Linux.a'];
    #else:
    #    audio_objects = ['PsychSourceGL/Cohorts/PortAudio/libportaudio32Linux.a'];

    # libusb includes:
    usb_includes = ['/usr/include/libusb-1.0'];

    # Extra OS specific libs for PsychHID:
    psychhid_includes = usb_includes;
    psychhid_libdirs = [];
    psychhid_libs = ['dl', 'usb-1.0', 'X11', 'Xi', 'util'];
    psychhid_extra_objects = [];

    # Extra files needed, e.g., libraries:
    extra_files = {};

if platform.system() == 'Windows':
    print('Building for Windows...\n');
    osname = 'Windows';
    base_libs = ['kernel32', 'user32', 'advapi32', 'winmm'];
    base_compile_args = [];

    # Extra OS specific libs for PsychPortAudio:
    audio_libdirs = ['PsychSourceGL/Cohorts/PortAudio'];
    audio_extralinkargs = []; # No runtime delay loading atm. No benefit with current packaging method: ['/DELAYLOAD:portaudio_x64.dll'];
    audio_libs = ['delayimp', 'portaudio_x64'];
    audio_objects = [];

    # libusb includes:
    usb_includes = ['PsychSourceGL/Cohorts/libusb1-win32/include/libusb-1.0']

    # Extra OS specific libs for PsychHID:
    psychhid_includes = usb_includes;
    psychhid_libdirs = ['PsychSourceGL/Cohorts/libusb1-win32/MS64/dll'];
    psychhid_libs = ['dinput8', 'libusb-1.0', 'setupapi'];  
    psychhid_extra_objects = [];

    # Extra files needed, e.g., libraries.
    # The 64-Bit portaudio dll for PsychPortAudio and libusb1 dll for PsychHID:
    extra_files = {'psychtoolbox' : ['portaudio_x64.dll', 'libusb-1.0.dll']};

    # These extra files must be in the PsychPython folder that defines our
    # 'psychtoolbox' package. Copy them temporarily from their actual locations
    # in Psychtoolbox to that folder:
    shutil.copy('Psychtoolbox/PsychSound/portaudio_x64.dll', 'PsychPython/');
    shutil.copy('Psychtoolbox/PsychContributed/libusb-1.0.dll', 'PsychPython/');

if platform.system() == 'Darwin':
    print('Building for macOS...\n');
    osname = 'OSX';
    # These should go to extra_link_args in Extension() below, but apparently distutils
    # always appends the extra_link_args at the end of the linker command line, which is
    # wrong for -framework's, as they must be stated *before* the .o object files which
    # want to use functions from them. A solution to this problem doesn't exist in distutils
    # almost two decades after the debut of Mac OSX, because hey, take your time!
    #
    # The hack is to set the LDFLAGS environment variable to what we need, as LDFLAGS
    # apparently gets prepended to the linker invocation arguments, so -framework statements
    # precede the .o'bjects they should apply to and the linker is happy again.
    #
    # Downside is that now we have to pass the union of *all* -framework switches ever
    # used for *any* extension module, as os.environ can't be changed during the build
    # sequencing for a distribution package.
    #
    # Is this awful? Absolutely! And i thought the Octave/Matlab build process on macOS
    # sucked big time, but apparently somebody in Pythonland shouted "Hold my beer!" :(
    # Hopefully some new info about this issue will prove me wrong, and there is a sane
    # and elegant solution, but this is the best i could find after hours of Googling and
    # trying.
    #
    # The following would be the full list of frameworks, but apparently including -framework Carbon
    # is enough. Maybe a catch-all including all other frameworks?
    #
    # -framework Carbon -framework CoreServices -framework CoreFoundation -framework CoreAudio -framework AudioToolbox -framework AudioUnit
    # -framework ApplicationServices -framework OpenGL -framework CoreVideo -framework IOKit -framework SystemConfiguration
    # -framework CoreText -framework Cocoa
    #
    os.environ['LDFLAGS'] = '-framework Carbon -framework CoreAudio'
    base_libs = [];

    # No "no reproducible builds" warning:
    base_compile_args = ['-Wno-date-time', '-mmacosx-version-min=10.11'];

    # Extra OS specific libs for PsychPortAudio:
    audio_libdirs = [];
    audio_extralinkargs = [];
    audio_libs = [];
    # Include our statically linked on-steroids version of PortAudio:
    audio_objects = ['PsychSourceGL/Cohorts/PortAudio/libportaudio_osx_64.a'];

    # Include Apples open-source HID Utilities for all things USB-HID device handling:
    psychhid_includes = ['PsychSourceGL/Cohorts/HID_Utilities_64Bit/', 'PsychSourceGL/Cohorts/HID_Utilities_64Bit/IOHIDManager'];
    psychhid_libdirs = [];
    psychhid_libs = [];
    # Extra objects for PsychHID - statically linked HID utilities:
    psychhid_extra_objects = ['PsychSourceGL/Cohorts/HID_Utilities_64Bit/build/Release/libHID_Utilities64.a'];

    # Extra files needed, e.g., libraries:
    extra_files = {};

# GetSecs module: Clock queries.
name = 'GetSecs';
GetSecs = Extension(name,
                    extra_compile_args = base_compile_args,
                    define_macros = get_basemacros(name, osname),
                    include_dirs = get_baseincludedirs(name, osname),
                    sources = get_basesources(name, osname),
                    libraries = base_libs,
                   )

# WaitSecs module: Timed waits.
name = 'WaitSecs';
WaitSecs = Extension(name,
                     extra_compile_args = base_compile_args,
                     define_macros = get_basemacros(name, osname),
                     include_dirs = get_baseincludedirs(name, osname),
                     sources = get_basesources(name, osname),
                     libraries = base_libs
                    )

# PsychPortAudio module: High precision, high reliability, multi-channel, multi-card audio i/o.
name = 'PsychPortAudio';
PsychPortAudio = Extension(name,
                           extra_compile_args = base_compile_args,
                           define_macros = get_basemacros(name, osname),
                           include_dirs = get_baseincludedirs(name, osname),
                           sources = get_basesources(name, osname),
                           library_dirs = audio_libdirs,
                           libraries = base_libs + audio_libs,
                           extra_link_args = audio_extralinkargs,
                           extra_objects = audio_objects
                          )

# PsychHID module: Note the extra include_dirs and libraries:
name = 'PsychHID';
PsychHID = Extension(name,
                     extra_compile_args = base_compile_args,
                     define_macros = get_basemacros(name, osname),
                     include_dirs = get_baseincludedirs(name, osname) + psychhid_includes,
                     sources = get_basesources(name, osname),
                     library_dirs = psychhid_libdirs,
                     libraries = base_libs + psychhid_libs,
                     extra_objects = psychhid_extra_objects
                    )

# IOPort module:
name = 'IOPort';
IOPort = Extension(name,
                   extra_compile_args = base_compile_args,
                   define_macros = get_basemacros(name, osname),
                   include_dirs = get_baseincludedirs(name, osname),
                   sources = get_basesources(name, osname),
                   libraries = base_libs
                  )

setup (name = 'psychtoolbox',
       version = '3.0.15',
       description = 'Pieces of Psychtoolbox-3 ported to CPython.',
       author = 'Mario Kleiner',
       author_email = 'mario.kleiner.de@gmail.com',
       url = 'http://psychtoolbox.org',
       packages = ['psychtoolbox'],
       package_dir = {'psychtoolbox' : 'PsychPython'},
       package_data = extra_files,
       ext_package= 'psychtoolbox',
       ext_modules = [WaitSecs, GetSecs, IOPort, PsychHID, PsychPortAudio]
      )

if platform.system() == 'Windows':
    # Get rid of the now no longer needed copies of dll's inside PsychPython,
    # now that setup() has already copied them into the distribution.
    os.remove('PsychPython/portaudio_x64.dll');
    os.remove('PsychPython/libusb-1.0.dll');