1# Requires Python 2.4 or better and win32api.
2
3"""Config on Msys mingw
4
5This version expects the Pygame 1.9.0 dependencies as built by
6msys_build_deps.py
7"""
8
9import dll
10from setup_win_common import get_definitions
11import msys
12import os, sys, string
13import logging
14from glob import glob
15from distutils.sysconfig import get_python_inc
16
17configcommand = os.environ.get('SDL_CONFIG', 'sdl-config',)
18configcommand = configcommand + ' --version --cflags --libs'
19localbase = os.environ.get('LOCALBASE', '')
20
21#these get prefixes with '/usr/local' and /mingw or the $LOCALBASE
22origincdirs = ['/include', '/include/SDL', '/include/SDL11',
23               '/include/libpng12', ]
24origlibdirs = ['/lib']
25
26
27class ConfigError(Exception):
28    pass
29
30def path_join(a, *p):
31    return os.path.join(a, *p).replace(os.sep, '/')
32path_split = os.path.split
33
34def print_(*args, **kwds):
35    return msys.msys_print(*args, **kwds)
36
37class DependencyProg:
38    needs_dll = True
39    def __init__(self, name, envname, exename, minver, msys, defaultlibs=None):
40        if defaultlibs is None:
41            defaultlibs = [dll.name_to_root(name)]
42        self.name = name
43        try:
44            command = os.environ[envname]
45        except KeyError:
46            command = exename
47        else:
48            drv, pth = os.path.splitdrive(command)
49            if drv:
50                command = '/' + drv[0] + pth
51        self.lib_dir = ''
52        self.inc_dir = ''
53        self.libs = []
54        self.cflags = ''
55        try:
56            config = msys.run_shell_command([command, '--version', '--cflags', '--libs'])
57            ver, flags = config.split('\n', 1)
58            self.ver = ver.strip()
59            flags = flags.split()
60            if minver and self.ver < minver:
61                err= 'WARNING: requires %s version %s (%s found)' % (self.name, self.ver, minver)
62                raise ValueError(err)
63            self.found = 1
64            self.cflags = ''
65            for f in flags:
66                if f[:2] in ('-I', '-L'):
67                    self.cflags += f[:2] + msys.msys_to_windows(f[2:]) + ' '
68                elif f[:2] in ('-l', '-D'):
69                    self.cflags += f + ' '
70                elif f[:3] == '-Wl':
71                    self.cflags += '-Xlinker ' + f + ' '
72        except ValueError:
73            print_('WARNING: "%s" failed!' % command)
74            self.found = 0
75            self.ver = '0'
76            self.libs = defaultlibs
77
78    def configure(self, incdirs, libdir):
79        if self.found:
80            print_(self.name + '        '[len(self.name):] + ': found ' + self.ver)
81            self.found = 1
82        else:
83            print_(self.name + '        '[len(self.name):] + ': not found')
84
85class Dependency:
86    needs_dll = True
87    def __init__(self, name, checkhead, checklib, libs=None):
88        if libs is None:
89            libs = [dll.name_to_root(name)]
90        self.name = name
91        self.inc_dir = None
92        self.lib_dir = None
93        self.libs = libs
94        self.found = 0
95        self.checklib = checklib
96        self.checkhead = checkhead
97        self.cflags = ''
98
99    def configure(self, incdirs, libdirs):
100        self.find_inc_dir(incdirs)
101        self.find_lib_dir(libdirs)
102
103        if self.lib_dir and self.inc_dir:
104            print_(self.name + '        '[len(self.name):] + ': found')
105            self.found = 1
106        else:
107            print_(self.name + '        '[len(self.name):] + ': not found')
108
109    def find_inc_dir(self, incdirs):
110        incname = self.checkhead
111        for dir in incdirs:
112            path = path_join(dir, incname)
113            if os.path.isfile(path):
114                self.inc_dir = dir
115                return
116
117    def find_lib_dir(self, libdirs):
118        libname = self.checklib
119        for dir in libdirs:
120            path = path_join(dir, libname)
121            if any(map(os.path.isfile, glob(path+'*'))):
122                self.lib_dir = dir
123                return
124
125
126class DependencyPython:
127    needs_dll = False
128    def __init__(self, name, module, header):
129        self.name = name
130        self.lib_dir = ''
131        self.inc_dir = ''
132        self.libs = []
133        self.cflags = ''
134        self.found = 0
135        self.ver = '0'
136        self.module = module
137        self.header = header
138
139    def configure(self, incdirs, libdirs):
140        self.found = 1
141        if self.module:
142            try:
143                self.ver = __import__(self.module).__version__
144            except ImportError:
145                self.found = 0
146        if self.found and self.header:
147            fullpath = path_join(get_python_inc(0), self.header)
148            if not os.path.isfile(fullpath):
149                self.found = 0
150            else:
151                self.inc_dir = os.path.split(fullpath)[0]
152        if self.found:
153            print_(self.name + '        '[len(self.name):] + ': found', self.ver)
154        else:
155            print_(self.name + '        '[len(self.name):] + ': not found')
156
157class DependencyDLL:
158    needs_dll = False
159    def __init__(self, name, libs=None):
160        if libs is None:
161            libs = dll.libraries(name)
162        self.name = 'COPYLIB_' + dll.name_to_root(name)
163        self.inc_dir = None
164        self.lib_dir = '_'
165        self.libs = libs
166        self.found = 1  # Alway found to make its COPYLIB work
167        self.cflags = ''
168        self.lib_name = name
169        self.file_name_test = dll.tester(name)
170
171    def configure(self, incdirs, libdirs, start=None):
172        omit = []
173        if start is not None:
174            if self.set_path(start):
175                return
176            omit.append(start)
177            p, f = path_split(start)
178            if f == 'lib' and self.set_path(path_join(p, 'bin')):
179                return
180            omit.append(start)
181        # Search other directories
182        for dir in libdirs:
183            if dir not in omit:
184                if self.set_path(dir):
185                    return
186                p, f = path_split(dir)
187                if f == 'lib' and self.set_path(path_join(p, 'bin')):  # cond. and
188                    return
189
190    def set_path(self, wdir):
191        test = self.file_name_test
192        try:
193            files = os.listdir(wdir)
194        except OSError:
195            pass
196        else:
197            for f in files:
198                if test(f) and os.path.isfile(path_join(wdir, f)):
199                    # Found
200                    self.lib_dir = path_join(wdir, f)
201                    return True
202        # Not found
203        return False
204
205class DependencyWin:
206    needs_dll = False
207    def __init__(self, name, cflags):
208        self.name = name
209        self.inc_dir = None
210        self.lib_dir = None
211        self.libs = []
212        self.found = 1
213        self.cflags = cflags
214
215    def configure(self, incdirs, libdirs):
216        pass
217
218
219def main():
220    m = msys.Msys(require_mingw=False)
221    print_('\nHunting dependencies...')
222    DEPS = [
223        DependencyProg('SDL', 'SDL_CONFIG', 'sdl-config', '1.2.13', m),
224        Dependency('FONT', 'SDL_ttf.h', 'libSDL_ttf.dll.a'),
225        Dependency('IMAGE', 'SDL_image.h', 'libSDL_image.dll.a'),
226        Dependency('MIXER', 'SDL_mixer.h', 'libSDL_mixer.dll.a'),
227        Dependency('PNG', 'png.h', 'libpng.dll.a'),
228        Dependency('JPEG', 'jpeglib.h', 'libjpeg.dll.a'),
229        Dependency('PORTMIDI', 'portmidi.h', 'libportmidi.dll.a'),
230        Dependency('PORTTIME', 'portmidi.h', 'libportmidi.dll.a'),
231        DependencyDLL('TIFF'),
232        DependencyDLL('VORBISFILE'),
233        DependencyDLL('VORBIS'),
234        DependencyDLL('OGG'),
235        DependencyDLL('FREETYPE'),
236        DependencyDLL('Z'),
237    ]
238
239    if not DEPS[0].found:
240        print_('Unable to run "sdl-config". Please make sure a development version of SDL is installed.')
241        sys.exit(1)
242
243    if localbase:
244        incdirs = [localbase+d for d in origincdirs]
245        libdirs = [localbase+d for d in origlibdirs]
246    else:
247        incdirs = []
248        libdirs = []
249    incdirs += [m.msys_to_windows("/usr/local"+d) for d in origincdirs]
250    libdirs += [m.msys_to_windows("/usr/local"+d) for d in origlibdirs]
251    if m.mingw_root is not None:
252        incdirs += [m.msys_to_windows("/mingw"+d) for d in origincdirs]
253        libdirs += [m.msys_to_windows("/mingw"+d) for d in origlibdirs]
254    for arg in string.split(DEPS[0].cflags):
255        if arg[:2] == '-I':
256            incdirs.append(arg[2:])
257        elif arg[:2] == '-L':
258            libdirs.append(arg[2:])
259    dll_deps = []
260    for d in DEPS:
261        d.configure(incdirs, libdirs)
262        if d.needs_dll:
263            dll_dep = DependencyDLL(d.name)
264            dll_dep.configure(incdirs, libdirs, d.lib_dir)
265            dll_deps.append(dll_dep)
266
267    DEPS += dll_deps
268    for d in get_definitions():
269        DEPS.append(DependencyWin(d.name, d.value))
270    for d in DEPS:
271        if isinstance(d, DependencyDLL):
272            if d.lib_dir == '':
273                print_("DLL for %-12s: not found" % d.lib_name)
274            else:
275                print_("DLL for %-12s: %s" % (d.lib_name, d.lib_dir))
276
277    for d in DEPS[1:]:
278        if not d.found:
279            if "-auto" not in sys.argv:
280                logging.warning(
281                    "Some pygame dependencies were not found. "
282                    "Pygame can still compile and install, but games that "
283                    "depend on those missing dependencies will not run. "
284                    "Use -auto to continue building without all dependencies. "
285                )
286                raise SystemExit("Missing dependencies")
287            break
288
289    return DEPS
290
291if __name__ == '__main__':
292    print_("""This is the configuration subscript for MSYS.
293Please run "config.py" for full configuration.""")
294
295