2
# -*- coding: ascii -*-
3
# Program msys_link_VC_2008_dlls.py
4
# Requires Python 2.4 or later and win32api.
6
"""Link dependency DLLs against the Visual C 2008 run-time using MinGW and MSYS
8
Configured for Pygame 1.8 and Python 2.6 and up.
10
By default the DLLs and export libraries are installed in directory ./lib_VC_2008.
11
msys_build_deps.py must run first to build the static libaries.
13
This program can be run from a Windows cmd.exe or MSYS terminal.
15
The recognized, and optional, environment variables are:
16
SHELL - MSYS shell program path - already defined in the MSYS terminal
17
LDFLAGS - linker options - prepended to flags set by the program
18
LIBRARY_PATH - library directory paths - appended to those used by this
21
To get a list of command line options run
23
python build_deps.py --help
25
This program has been tested against the following libraries:
27
SDL 1.2 (.13) revision 4114 from SVN
29
SDL_mixer 1.2 (.8) revision 3942 from SVN
31
smpeg revision 370 from SVN
41
The build environment used:
50
Builds have been performed on Windows 98 and XP.
53
For pre-2007 computers: MSYS bug "[ 1170716 ] executing a shell scripts
54
gives a memory leak" (http://sourceforge.net/tracker/
55
index.php?func=detail&aid=1170716&group_id=2435&atid=102435)
57
It may not be possible to use the --all option to build all Pygame
58
dependencies in one session. Instead the job may need to be split into two
59
or more sessions, with a reboot of the operatingsystem between each. Use
60
the --help-args option to list the libraries in the their proper build
66
from optparse import OptionParser, Option, OptionValueError
73
DEFAULT_DEST_DIR_NAME = 'lib_VC_2008'
75
def print_(*args, **kwds):
76
msys.msys_print(*args, **kwds)
78
def merge_strings(*args, **kwds):
79
"""Returns non empty string joined by sep
81
The default separator is an empty string.
84
sep = kwds.get('sep', '')
85
return sep.join([s for s in args if s])
87
class BuildError(StandardError):
88
"""Raised for missing source paths and failed script runs"""
91
class Dependency(object):
92
"""Builds a library"""
94
def __init__(self, name, dlls, shell_script):
97
self.shell_script = shell_script
99
def build(self, msys):
100
return_code = msys.run_shell_script(self.shell_script)
102
raise BuildError("The build for %s failed with code %d" %
103
(self.name, return_code))
105
class Preparation(object):
106
"""Perform necessary build environment preperations"""
108
def __init__(self, name, shell_script):
113
self.shell_script = shell_script
115
def build(self, msys):
116
return_code = msys.run_shell_script(self.shell_script)
118
raise BuildError("Preparation '%s' failed with code %d" %
119
(self.name, return_code))
121
def build(dependencies, msys):
122
"""Execute that shell scripts for all dependencies"""
124
for dep in dependencies:
127
def check_directory_path(option, opt, value):
128
# Remove those double quotes that Windows won't.
129
if re.match(r'([A-Za-z]:){0,1}[^"<>:|?*]+$', value) is None:
130
raise OptionValueError("option %s: invalid path" % value)
133
class MyOption(Option):
134
TYPES = Option.TYPES + ("dir",)
135
TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
136
TYPE_CHECKER["dir"] = check_directory_path
139
"""Process the command line and return the options"""
141
usage = ("usage: %prog [options] --all\n"
142
" %prog [options] [args]\n"
144
"Build the Pygame dependencies. The args, if given, are\n"
145
"libraries to include or exclude.\n"
147
"At startup this program may prompt for missing information.\n"
148
"Be aware of this before redirecting output or leaving the\n"
149
"program unattended. Once the 'Starting build' message appears\n"
150
"no more user input is required. The build process will"
151
"abort on the first error, as library build order is important.\n"
153
"See --include and --help-args.\n"
155
"For more details see the program's document string\n")
157
parser = OptionParser(usage, option_class=MyOption)
158
parser.add_option('-a', '--all', action='store_true', dest='build_all',
159
help="Include all libraries in the build")
160
parser.set_defaults(build_all=False)
161
parser.add_option('--console', action='store_true', dest='console',
162
help="Link with the console subsystem:"
163
" defaults to Win32 GUI")
164
parser.set_defaults(console=False)
165
parser.add_option('--no-strip', action='store_false', dest='strip',
166
help="Do not strip the library")
167
parser.set_defaults(strip=True)
168
parser.add_option('-e', '--exclude', action='store_true', dest='exclude',
169
help="Exclude the specified libraries")
170
parser.set_defaults(exclude=False)
171
parser.add_option('-d', '--destination-dir', type='dir',
172
dest='destination_dir',
173
help="Where the DLLs and export libraries will go",
175
parser.set_defaults(destination_dir=DEFAULT_DEST_DIR_NAME)
176
parser.add_option('-m', '--msys-root', action='store', type='dir',
177
dest='msys_directory',
178
help="MSYS directory path, which may include"
179
" the 1.x subdirectory")
180
parser.add_option('--help-args', action='store_true', dest='arg_help',
181
help="Show a list of recognised libraries,"
182
" in build order, and exit")
183
parser.set_defaults(arg_help=False)
184
return parser.parse_args()
186
def set_environment_variables(msys, options):
187
"""Set the environment variables used by the scripts"""
189
environ = msys.environ
190
msys_root = msys.msys_root
191
destination_dir = os.path.abspath(options.destination_dir)
192
environ['BDWD'] = msys.windows_to_msys(destination_dir)
193
environ['BDBIN'] = '/usr/local/bin'
194
environ['BDLIB'] = '/usr/local/lib'
195
subsystem = '-mwindows'
197
subsystem = '-mconsole'
200
strip = '-Wl,--strip-all'
201
environ['LDFLAGS'] = merge_strings(environ.get('LDFLAGS', ''),
205
library_path = os.path.join(msys_root, 'local', 'lib')
206
msvcr90_path = os.path.join(destination_dir, 'msvcr90')
207
environ['DBMSVCR90'] = msys.windows_to_msys(msvcr90_path)
208
# For dependency libraries and msvcrt hiding.
209
environ['LIBRARY_PATH'] = merge_strings(msvcr90_path,
210
environ.get('LIBRARY_PATH', ''),
213
class ChooseError(StandardError):
214
"""Failer to select dependencies"""
217
def choose_dependencies(dependencies, options, args):
218
"""Return the dependencies to actually build"""
220
if options.build_all:
222
raise ChooseError("No library names are accepted"
223
" for the --all option.")
230
names = [d.name for d in dependencies]
231
args = [a.upper() for a in args]
234
msg = ["%s is an unknown library; valid choices are:" % a]
236
raise ChooseError('\n'.join(msg))
238
return [d for d in dependencies if d.name not in args]
239
return [d for d in dependencies if d.name in args]
243
def summary(dependencies, msys, start_time, chosen_deps, options):
244
"""Display a summary report of new, existing and missing DLLs"""
248
print_("\n\n=== Summary ===")
249
if start_time is not None:
250
print_(" Elapse time:",
251
datetime.timedelta(seconds=time.time()-start_time))
252
bin_dir = options.destination_dir
253
for d in dependencies:
257
dll_path = os.path.join(bin_dir, dll)
259
mod_time = os.path.getmtime(dll_path)
263
if mod_time >= start_time:
264
msg = "Installed new DLL %s" % dll_path
266
msg = "-- (old DLL %s)" % dll_path
267
print_(" %-10s: %s" % (name, msg))
269
def main(dependencies, msvcr90_preparation, msys_preparation):
270
"""Build the dependencies according to the command line options."""
272
options, args = command_line()
274
print_("These are the Pygame library dependencies:")
275
for dep in dependencies:
276
print_(" ", dep.name)
279
chosen_deps = choose_dependencies(dependencies, options, args)
280
except ChooseError, e:
283
print_("Destination directory:", options.destination_dir)
286
print_("No libraries specified.")
287
elif options.build_all:
288
print_("All libraries excluded")
289
chosen_deps.insert(0, msvcr90_preparation)
290
chosen_deps.insert(0, msys_preparation)
292
msys_directory = options.msys_directory
293
except AttributeError:
294
msys_directory = None
296
m = msys.Msys(msys_directory)
297
except msys.MsysException, e:
302
set_environment_variables(m, options)
303
print_("\n=== Starting build ===")
304
start_time = time.time() # For file timestamp checks.
306
build(chosen_deps, m)
307
except BuildError, e:
308
print_("Build aborted:", e)
310
# A successful build!
312
summary(dependencies, m, start_time, chosen_deps, options)
317
# Build specific code
320
# This list includes the MSYS shell scripts to build each library. Each script
321
# runs in an environment where MINGW_ROOT_DIRECTORY is defined and the MinGW
322
# bin directory is in PATH. DBWD, is the working directory. A script will cd to
323
# it before doing anything else. BDBIN is the location of the dependency DLLs.
324
# BDLIB is the location of the dependency libraries. LDFLAGS are linker flags.
326
# The list order corresponds to build order. It is critical.
328
Dependency('SDL', ['SDL.dll'], """
333
pexports "$BDBIN/SDL.dll" >SDL.def
334
gcc -shared $LDFLAGS -o SDL.dll -def SDL.def "$BDLIB/libSDL.a" -lwinmm -ldxguid
335
dlltool -D SDL.dll -d SDL.def -l libSDL.dll.a
337
strip --strip-all SDL.dll
339
Dependency('Z', ['zlib1.dll'], """
344
pexports "$BDBIN/zlib1.dll" >z.def
345
gcc -shared $LDFLAGS -o zlib1.dll -def z.def "$BDLIB/libz.a"
346
dlltool -D zlib1.dll -d z.def -l libz.dll.a
348
strip --strip-all zlib1.dll
350
Dependency('FREETYPE', ['libfreetype-6.dll'], """
355
pexports "$BDBIN/libfreetype-6.dll" >freetype.def
356
gcc -shared $LDFLAGS -L. -o libfreetype-6.dll -def freetype.def \
357
"$BDLIB/libfreetype.a" -lz
358
dlltool -D libfreetype-6.dll -d freetype.def -l libfreetype.dll.a
359
ranlib libfreetype.dll.a
360
strip --strip-all libfreetype-6.dll
362
Dependency('FONT', ['SDL_ttf.dll'], """
367
pexports "$BDBIN/SDL_ttf.dll" >SDL_ttf.def
368
gcc -shared $LDFLAGS -L. "-L$BDLIB" -o SDL_ttf.dll -def SDL_ttf.def \
369
"$BDLIB/libSDL_ttf.a" -lSDL -lfreetype
370
dlltool -D SDL_ttf.dll -d SDL_ttf.def -l libSDL_ttf.dll.a
371
ranlib libSDL_ttf.dll.a
372
strip --strip-all SDL_ttf.dll
374
Dependency('PNG', ['libpng12-0.dll'], """
379
pexports "$BDBIN/libpng12-0.dll" >png.def
380
gcc -shared $LDFLAGS -L. -o libpng12-0.dll -def png.def "$BDLIB/libpng.a" -lz
381
dlltool -D libpng12-0.dll -d png.def -l libpng.dll.a
383
strip --strip-all libpng12-0.dll
385
Dependency('JPEG', ['jpeg.dll'], """
390
pexports "$BDBIN/jpeg.dll" >jpeg.def
391
gcc -shared $LDFLAGS -o jpeg.dll -def jpeg.def "$BDLIB/libjpeg.a"
392
dlltool -D jpeg.dll -d jpeg.def -l libjpeg.dll.a
394
strip --strip-all jpeg.dll
396
Dependency('TIFF', ['libtiff.dll'], """
401
pexports "$BDBIN/libtiff.dll" >tiff.def
402
gcc -shared $LDFLAGS -L. -o libtiff.dll -def tiff.def \
403
"$BDLIB/libtiff.a" -ljpeg -lz
404
dlltool -D libtiff.dll -d tiff.def -l libtiff.dll.a
406
strip --strip-all libtiff.dll
408
Dependency('IMAGE', ['SDL_image.dll'], """
413
pexports "$BDBIN/SDL_image.dll" >SDL_image.def
414
gcc -shared $LDFLAGS -L. -o SDL_image.dll -def SDL_image.def \
415
"$BDLIB/libSDL_image.a" -lSDL -ljpeg -lpng -ltiff
416
dlltool -D SDL_image.dll -d SDL_image.def -l libSDL_image.dll.a
417
ranlib libSDL_image.dll.a
418
strip --strip-all SDL_image.dll
420
Dependency('SMPEG', ['smpeg.dll'], """
425
pexports "$BDBIN/smpeg.dll" >smpeg.def
426
g++ -shared $LDFLAGS -L. -o smpeg.dll -def smpeg.def \
427
"$BDLIB/libsmpeg.a" -lSDL
428
dlltool -D smpeg.dll -d smpeg.def -l libsmpeg.dll.a
429
ranlib libsmpeg.dll.a
430
strip --strip-all smpeg.dll
432
Dependency('OGG', ['libogg-0.dll'], """
437
pexports "$BDBIN/libogg-0.dll" >ogg.def
438
gcc -shared $LDFLAGS -o libogg-0.dll -def ogg.def "$BDLIB/libogg.a"
439
dlltool -D libogg-0.dll -d ogg.def -l libogg.dll.a
441
strip --strip-all libogg-0.dll
443
Dependency('VORBIS', ['libvorbis-0.dll', 'libvorbisfile-3.dll'], """
448
pexports "$BDBIN/libvorbis-0.dll" >vorbis.def
449
gcc -shared $LDFLAGS -L. -o libvorbis-0.dll -def vorbis.def \
450
"$BDLIB/libvorbis.a" -logg
451
dlltool -D libvorbis-0.dll -d vorbis.def -l libvorbis.dll.a
452
ranlib libvorbis.dll.a
453
strip --strip-all libvorbis-0.dll
455
pexports "$BDBIN/libvorbisfile-3.dll" >vorbisfile.def
456
gcc -shared $LDFLAGS -L. -o libvorbisfile-3.dll -def vorbisfile.def \
457
"$BDLIB/libvorbisfile.a" -lvorbis -logg
458
dlltool -D libvorbisfile-3.dll -d vorbisfile.def -l libvorbisfile.dll.a
459
ranlib libvorbisfile.dll.a
460
strip --strip-all libvorbisfile-3.dll
462
Dependency('MIXER', ['SDL_mixer.dll'], """
467
pexports "$BDBIN/SDL_mixer.dll" >SDL_mixer.def
468
gcc -shared $LDFLAGS -L. -L/usr/local/lib -o SDL_mixer.dll -def SDL_mixer.def \
469
"$BDLIB/libSDL_mixer.a" -lSDL -lsmpeg -lvorbisfile -lFLAC -lWs2_32 -lwinmm
470
dlltool -D SDL_mixer.dll -d SDL_mixer.def -l libSDL_mixer.dll.a
471
ranlib libSDL_mixer.dll.a
472
strip --strip-all SDL_mixer.dll
474
Dependency('PORTMIDI', ['portmidi.dll'], """
479
pexports "$BDBIN/portmidi.dll" >portmidi.def
480
gcc -shared $LDFLAGS -L. -L/usr/local/lib -o portmidi.dll -def portmidi.def \
481
"$BDLIB/libportmidi.a" -lwinmm
482
dlltool -D portmidi.dll -d portmidi.def -l portmidi.dll.a
483
ranlib libSDL_mixer.dll.a
484
strip --strip-all portmidi.dll
486
] # End dependencies = [.
489
msys_prep = Preparation('/usr/local', """
491
# Ensure destination directories exists.
493
mkdir -p "$DBMSVCR90"
496
msvcr90_prep = Preparation('msvcr90.dll linkage', r"""
501
# msvcr90.dll support
503
if [ ! -f "$DBMSVCR90/libmoldnamed.dll.a" ]; then
504
OBJS='isascii.o iscsym.o iscsymf.o toascii.o
505
strcasecmp.o strncasecmp.o wcscmpi.o'
506
if [ ! -d /tmp/build_deps ]; then mkdir /tmp/build_deps; fi
509
# These definitions were generated with pexports on msvcr90.dll.
510
# The C++ stuff at the beginning was removed. _onexit and atexit made
512
cat > msvcr90.def << 'THE_END'
540
_IsExceptionObjectToBeDestroyed
548
__BuildCatchObjectHelper
550
__CxxCallUnwindDelDtor
552
__CxxCallUnwindStdDelDtor
553
__CxxCallUnwindVecDtor
560
__CxxQueryExceptionSize
561
__CxxRegisterExceptionObject
562
__CxxUnregisterExceptionObject
563
__DestructExceptionObject
574
___lc_collate_cp_func
579
___unguarded_readlc_active_add_func
583
__clean_type_info_names_internal
684
__unguarded_readlc_active DATA
692
_abnormal_termination
715
_aligned_offset_malloc
716
_aligned_offset_realloc
717
_aligned_offset_recalloc
814
_except_handler4_common
905
_get_invalid_parameter_handler
909
_get_printf_count_output
910
_get_purecall_handler
965
_invalid_parameter_noinfo
1293
_seh_longjmp_unwind4
1302
_set_invalid_parameter_handler
1303
_set_malloc_crt_max_wait
1305
_set_printf_count_output
1306
_set_purecall_handler
1895
# Provide the gmtime stub required by PNG.
1896
cat > gmtime.c << 'THE_END'
1897
/* Stub function for gmtime.
1898
* This is an inline function in Visual C 2008 so is missing from msvcr90.dll
1902
struct tm* _gmtime32(const time_t *timer);
1904
struct tm* gmtime(const time_t *timer)
1906
return _gmtime32(timer);
1910
# Provide the _ftime stub required by numpy.random.mtrand.
1911
cat > _ftime.c << 'THE_END'
1912
/* Stub function for _ftime.
1913
* This is an inline function in Visual C 2008 so is missing from msvcr90.dll
1915
#include <sys/types.h>
1916
#include <sys/timeb.h>
1918
void _ftime32(struct _timeb *timeptr);
1920
void _ftime(struct _timeb *timeptr)
1926
# Provide the time stub required by Numeric.RNG.
1927
cat > time.c << 'THE_END'
1928
/* Stub function for time.
1929
* This is an inline function in Visual C 2008 so is missing from msvcr90.dll
1933
time_t _time32(time_t *timer);
1935
time_t time(time_t *timer)
1937
return _time32(timer);
1941
gcc -c -O2 gmtime.c _ftime.c time.c
1942
dlltool -d msvcr90.def -D msvcr90.dll -l libmsvcr90.dll.a
1943
ar rc libmsvcr90.dll.a gmtime.o _ftime.o time.o
1944
ranlib libmsvcr90.dll.a
1945
cp -f libmsvcr90.dll.a "$DBMSVCR90"
1946
mv -f libmsvcr90.dll.a "$DBMSVCR90/libmsvcrt.dll.a"
1948
dlltool -d msvcr90.def -D msvcr90d.dll -l libmsvcr90d.dll.a
1949
ar rc libmsvcr90d.dll.a gmtime.o
1950
ranlib libmsvcr90d.dll.a
1951
cp -f libmsvcr90d.dll.a "$DBMSVCR90"
1952
mv -f libmsvcr90d.dll.a "$DBMSVCR90/libmsvcrtd.dll.a"
1954
# These definitions are taken from mingw-runtime-3.12 .
1955
# The file was generated with the following command:
1957
# gcc -DRUNTIME=msvcrt -D__FILENAME__=moldname-msvcrt.def
1958
# -D__MSVCRT__ -C -E -P -xc-header moldname.def.in >moldname-msvcrt.def
1959
# It then had fstat deleted to match with msvcr90.dll.
1960
cat > moldname-msvcrt.def << 'THE_END'
1990
; Alias fpreset is set in CRT_fp10,c and CRT_fp8.c.
2050
; export tzname for both. See <time.h>
2070
; non-ANSI functions declared in math.h
2088
# Provide the fstat stub required by TIFF.
2089
cat > fstat.c << 'THE_END'
2090
/* Stub function for fstat.
2091
* This is an inlined functions in Visual C 2008 so is missing from msvcr90.dll
2093
#include <sys/stat.h>
2095
int _fstat32(int fd, struct stat *buffer);
2097
int fstat(int fd, struct stat *buffer)
2099
return _fstat32(fd, buffer);
2103
mkdir -p "$DBMSVCR90"
2105
ar x /mingw/lib/libmoldname90.a $OBJS
2106
dlltool --as as -k -U \
2107
--dllname msvcr90.dll \
2108
--def moldname-msvcrt.def \
2109
--output-lib libmoldname.dll.a
2110
ar rc libmoldname.dll.a $OBJS fstat.o
2111
ranlib libmoldname.dll.a
2112
mv -f libmoldname.dll.a "$DBMSVCR90"
2114
ar x /mingw/lib/libmoldname90d.a $OBJS
2115
dlltool --as as -k -U \
2116
--dllname msvcr90.dll \
2117
--def moldname-msvcrt.def \
2118
--output-lib libmoldnamed.dll.a
2119
ar rc libmoldnamed.dll.a $OBJS fstat.o
2120
ranlib libmoldnamed.dll.a
2121
mv -f libmoldnamed.dll.a "$DBMSVCR90"
2124
rmdir /tmp/build_deps
2128
if __name__ == '__main__':
2129
sys.exit(main(dependencies, msvcr90_prep, msys_prep))