Various build tweaks and updates for wxPython 2.9.1.1
[wxWidgets.git] / build / tools / build-wxwidgets.py
1 #!/usr/bin/env python
2
3 ###################################
4 # Author: Kevin Ollivier
5 # Licence: wxWindows licence
6 ###################################
7
8 import os
9 import re
10 import sys
11 import builder
12 import commands
13 import glob
14 import optparse
15 import platform
16 import shutil
17 import types
18
19 # builder object
20 wxBuilder = None
21
22 # other globals
23 scriptDir = None
24 wxRootDir = None
25 contribDir = None
26 options = None
27 configure_opts = None
28 exitWithException = True
29
30
31 def exitIfError(code, msg):
32 if code != 0:
33 print msg
34 if exitWithException:
35 raise builder.BuildError, msg
36 else:
37 sys.exit(1)
38
39
40 def getWxRelease():
41 global wxRootDir
42 configureText = open(os.path.join(wxRootDir, "configure.in"), "r").read()
43
44 majorVersion = re.search("wx_major_version_number=(\d+)", configureText).group(1)
45 minorVersion = re.search("wx_minor_version_number=(\d+)", configureText).group(1)
46
47 return "%s.%s" % (majorVersion, minorVersion)
48
49
50
51 def doMacLipoBuild(arch, buildDir, installDir,
52 cxxcompiler="g++-4.0", cccompiler="gcc-4.0", target="10.4", flags=""):
53 archInstallDir = installDir + "/" + arch
54 old_env = dict(CXX = os.environ.get('CXX'),
55 CC = os.environ.get('CC'),
56 MACOSX_DEPLOYMENT_TARGET = os.environ.get('MACOSX_DEPLOYMENT_TARGET'),
57 )
58
59 os.environ["CXX"] = "%s -arch %s %s" % (cxxcompiler, arch, flags)
60 os.environ["CC"] = "%s -arch %s %s" % (cccompiler, arch, flags)
61 os.environ["MACOSX_DEPLOYMENT_TARGET"] = target
62 archArgs = ["DESTDIR=" + archInstallDir]
63 buildRoot = "bld-" + arch
64 if buildDir:
65 buildRoot = buildDir + "/" + buildRoot
66
67 if not os.path.exists(buildRoot):
68 os.makedirs(buildRoot)
69
70 olddir = os.getcwd()
71 os.chdir(buildRoot)
72
73 if not options.no_config:
74 exitIfError(wxBuilder.configure(dir=wxRootDir, options=configure_opts), "Error running configure for "+arch)
75 exitIfError(wxBuilder.build(options=archArgs), "Error building for "+arch)
76 exitIfError(wxBuilder.install(options=["DESTDIR=" + archInstallDir]), "Error Installing for "+arch)
77
78 if options.wxpython and os.path.exists(os.path.join(wxRootDir, contribDir)):
79 exitIfError(wxBuilder.build(dir=os.path.join(contribDir, "gizmos"), options=archArgs),
80 "Error building gizmos for "+arch)
81 exitIfError(wxBuilder.install(os.path.join(contribDir, "gizmos"), options=["DESTDIR=" + archInstallDir]),
82 "Error Installing gizmos for "+arch)
83
84 exitIfError(wxBuilder.build(dir=os.path.join(contribDir, "stc"),options=archArgs),
85 "Error building stc for "+arch)
86 exitIfError(wxBuilder.install(os.path.join(contribDir, "stc"),options=["DESTDIR=" + archInstallDir]),
87 "Error installing stc for "+arch)
88
89 os.chdir(olddir)
90 for key, val in old_env.items():
91 if val:
92 os.environ[key] = val
93 else:
94 del os.environ[key]
95
96
97 def macFixupInstallNames(destdir, prefix, buildDir=None):
98 # When an installdir is used then the install_names embedded in
99 # the dylibs are not correct. Reset the IDs and the dependencies
100 # to use just the prefix.
101 print "**** macFixupInstallNames(%s, %s, %s)" % (destdir, prefix, buildDir)
102 pwd = os.getcwd()
103 os.chdir(destdir+prefix+'/lib')
104 dylibs = glob.glob('*.dylib') # ('*[0-9].[0-9].[0-9].[0-9]*.dylib')
105 for lib in dylibs:
106 cmd = 'install_name_tool -id %s/lib/%s %s/lib/%s' % \
107 (prefix,lib, destdir+prefix,lib)
108 print cmd
109 os.system(cmd)
110 for dep in dylibs:
111 if buildDir is not None:
112 cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s/lib/%s' % \
113 (buildDir,dep, prefix,dep, destdir+prefix,lib)
114 else:
115 cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s/lib/%s' % \
116 (destdir+prefix,dep, prefix,dep, destdir+prefix,lib)
117 print cmd
118 os.system(cmd)
119 os.chdir(pwd)
120
121
122
123 def main(scriptName, args):
124 global scriptDir
125 global wxRootDir
126 global contribDir
127 global options
128 global configure_opts
129 global wxBuilder
130
131 scriptDir = os.path.dirname(os.path.abspath(scriptName))
132 wxRootDir = os.path.abspath(os.path.join(scriptDir, "..", ".."))
133
134 contribDir = os.path.join("contrib", "src")
135 installDir = None
136
137 VERSION = tuple([int(i) for i in getWxRelease().split('.')])
138
139 if sys.platform.startswith("win"):
140 contribDir = os.path.join(wxRootDir, "contrib", "build")
141
142 if sys.platform.startswith("win"):
143 toolkit = "msvc"
144 else:
145 toolkit = "autoconf"
146
147 option_dict = {
148 "clean" : (False, "Clean all files from the build directory"),
149 "debug" : (False, "Build the library in debug symbols"),
150 "builddir" : ("", "Directory where the build will be performed for autoconf builds."),
151 "prefix" : ("", "Configured prefix to use for autoconf builds. Defaults to installdir if set."),
152 "install" : (False, "Install the toolkit to the installdir directory, or the default dir."),
153 "installdir" : ("", "Directory where built wxWidgets will be installed"),
154 "mac_universal_binary" : (False, "Build Mac version as a universal binary"),
155 "mac_arch" : ("", "Build just the specified architecture on Mac"),
156 "mac_lipo" : (False, "EXPERIMENTAL: Create a universal binary by merging a PPC and Intel build together."),
157 "mac_framework" : (False, "Install the Mac build as a framework"),
158 "no_config" : (False, "Turn off configure step on autoconf builds"),
159 "config_only": (False, "Only run the configure step and then exit"),
160 "rebake" : (False, "Regenerate Bakefile and autoconf files"),
161 "unicode" : (False, "Build the library with unicode support"),
162 "wxpython" : (False, "Build the wxWidgets library with all options needed by wxPython"),
163 "cocoa" : (False, "Build the Cooca port (Mac only currently)."),
164 "osx_cocoa" : (False, "Build the new Cocoa port"),
165 "shared" : (False, "Build wx as a dynamic library"),
166 "cairo" : (False, "Build support for wxCairoContext (always true on GTK+)"),
167 "extra_make" : ("", "Extra args to pass on [n]make's command line."),
168 "features" : ("", "A comma-separated list of wxUSE_XYZ defines on Win, or a list of configure flags on unix."),
169 }
170
171 parser = optparse.OptionParser(usage="usage: %prog [options]", version="%prog 1.0")
172
173 for opt in option_dict:
174 default = option_dict[opt][0]
175
176 action = "store"
177 if type(default) == types.BooleanType:
178 action = "store_true"
179 parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1])
180
181 options, arguments = parser.parse_args(args=args)
182
183 # compiler / build system specific args
184 buildDir = options.builddir
185 args = None
186 installDir = options.installdir
187 prefixDir = options.prefix
188
189 if toolkit == "autoconf":
190 if not buildDir:
191 buildDir = os.getcwd()
192 configure_opts = []
193 if options.features != "":
194 configure_opts.extend(options.features.split(" "))
195
196 if options.unicode:
197 configure_opts.append("--enable-unicode")
198
199 if options.debug:
200 configure_opts.append("--enable-debug")
201
202 if options.mac_universal_binary:
203 configure_opts.append("--enable-universal_binary")
204 configure_opts.append("--without-macosx-sdk") # don't let configure default it
205
206 if options.cocoa:
207 configure_opts.append("--with-old_cocoa")
208
209 if options.osx_cocoa:
210 configure_opts.append("--with-osx_cocoa")
211
212 if options.mac_arch:
213 configure_opts.append("--enable-macosx_arch=%s" % options.mac_arch)
214
215 wxpy_configure_opts = [
216 "--with-opengl",
217 "--enable-sound",
218 "--enable-graphics_ctx",
219 "--enable-mediactrl",
220 "--enable-display",
221 "--enable-geometry",
222 "--enable-debug_flag",
223 "--enable-optimise",
224 "--disable-debugreport",
225 "--enable-uiactionsim",
226 ]
227
228 if sys.platform.startswith("darwin"):
229 wxpy_configure_opts.append("--enable-monolithic")
230 else:
231 wxpy_configure_opts.append("--with-sdl")
232 wxpy_configure_opts.append("--with-gnomeprint")
233
234 if not options.mac_framework:
235 if installDir and not prefixDir:
236 prefixDir = installDir
237 if prefixDir:
238 configure_opts.append("--prefix=" + prefixDir)
239
240 if options.wxpython:
241 configure_opts.extend(wxpy_configure_opts)
242 if options.debug:
243 # wxPython likes adding these debug options too
244 configure_opts.append("--enable-debug_gdb")
245 configure_opts.append("--disable-optimise")
246
247 if options.rebake:
248 retval = os.system("make -f autogen.mk")
249 exitIfError(retval, "Error running autogen.mk")
250
251 if options.mac_framework:
252 # Framework build is always a universal binary
253 options.mac_lipo = True
254 name = "wx"
255 if options.osx_cocoa:
256 name += "OSXCocoa"
257 installDir = "/Library/Frameworks/%s.framework/Versions/%s" % (name, getWxRelease())
258 configure_opts.append("--prefix=" + installDir)
259 # framework builds always need to be monolithic
260 if not "--enable-monolithic" in configure_opts:
261 configure_opts.append("--enable-monolithic")
262
263 print "Configure options: " + `configure_opts`
264 wxBuilder = builder.AutoconfBuilder()
265 if not options.no_config and not options.clean and not options.mac_lipo:
266 olddir = os.getcwd()
267 if buildDir:
268 os.chdir(buildDir)
269 exitIfError(wxBuilder.configure(dir=wxRootDir, options=configure_opts),
270 "Error running configure")
271 os.chdir(olddir)
272
273 if options.config_only:
274 print "Exiting after configure"
275 return
276
277 elif toolkit in ["msvc", "msvcProject"]:
278 flags = {}
279 buildDir = os.path.abspath(os.path.join(scriptDir, "..", "msw"))
280
281 print "creating wx/msw/setup.h from setup0.h"
282 if options.unicode:
283 flags["wxUSE_UNICODE"] = "1"
284 if VERSION < (2,9):
285 flags["wxUSE_UNICODE_MSLU"] = "1"
286
287 if options.cairo:
288 flags["wxUSE_CAIRO"] = "1"
289
290 if options.wxpython:
291 flags["wxDIALOG_UNIT_COMPATIBILITY "] = "0"
292 flags["wxUSE_DEBUGREPORT"] = "0"
293 flags["wxUSE_DIALUP_MANAGER"] = "0"
294 flags["wxUSE_GRAPHICS_CONTEXT"] = "1"
295 flags["wxUSE_DISPLAY"] = "1"
296 flags["wxUSE_GLCANVAS"] = "1"
297 flags["wxUSE_POSTSCRIPT"] = "1"
298 flags["wxUSE_AFM_FOR_POSTSCRIPT"] = "0"
299 flags["wxUSE_DATEPICKCTRL_GENERIC"] = "1"
300
301 if VERSION < (2,9):
302 flags["wxUSE_DIB_FOR_BITMAP"] = "1"
303
304 if VERSION >= (2,9):
305 flags["wxUSE_UIACTIONSIMULATOR"] = "1"
306
307
308 mswIncludeDir = os.path.join(wxRootDir, "include", "wx", "msw")
309 setup0File = os.path.join(mswIncludeDir, "setup0.h")
310 setupText = open(setup0File, "rb").read()
311
312 for flag in flags:
313 setupText, subsMade = re.subn(flag + "\s+?\d", "%s %s" % (flag, flags[flag]), setupText)
314 if subsMade == 0:
315 print "Flag %s wasn't found in setup0.h!" % flag
316 sys.exit(1)
317
318 setupFile = open(os.path.join(mswIncludeDir, "setup.h"), "wb")
319 setupFile.write(setupText)
320 setupFile.close()
321 args = []
322 if toolkit == "msvc":
323 print "setting build options..."
324 args.append("-f makefile.vc")
325 if options.unicode:
326 args.append("UNICODE=1")
327 if VERSION < (2,9):
328 args.append("MSLU=1")
329
330 if options.wxpython:
331 args.append("OFFICIAL_BUILD=1")
332 args.append("SHARED=1")
333 args.append("MONOLITHIC=0")
334 args.append("USE_OPENGL=1")
335 args.append("USE_GDIPLUS=1")
336
337 if not options.debug:
338 args.append("BUILD=release")
339 else:
340 args.append("BUILD=debug")
341
342 wxBuilder = builder.MSVCBuilder()
343
344 if toolkit == "msvcProject":
345 args = []
346 if options.shared or options.wxpython:
347 args.append("wx_dll.dsw")
348 else:
349 args.append("wx.dsw")
350
351 # TODO:
352 wxBuilder = builder.MSVCProjectBuilder()
353
354 if not wxBuilder:
355 print "Builder not available for your specified platform/compiler."
356 sys.exit(1)
357
358 if options.clean:
359 print "Performing cleanup."
360 wxBuilder.clean()
361
362 if options.wxpython:
363 exitIfError(wxBuilder.clean(os.path.join(contribDir, "gizmos")), "Error building gizmos")
364 exitIfError(wxBuilder.clean(os.path.join(contribDir, "stc")), "Error building stc")
365
366 sys.exit(0)
367
368 isLipo = False
369 if options.mac_lipo:
370 if options.mac_universal_binary:
371 print "WARNING: Cannot specify both mac_lipo and mac_universal_binary, as they conflict."
372 print " Using mac_universal_binary..."
373 else:
374 isLipo = True
375 # TODO: Add 64-bit when we're building OS X Cocoa
376
377 # 2.8, use gcc 3.3 on PPC for 10.3 support, but only when building ...
378 macVersion = platform.mac_ver()[0]
379 isLeopard = macVersion.find("10.5") != -1
380
381 if not isLeopard and os.path.exists(os.path.join(wxRootDir, contribDir)):
382 # Building wx 2.8 so make the ppc build compatible with Panther
383 doMacLipoBuild("ppc", buildDir, installDir, cxxcompiler="g++-3.3", cccompiler="gcc-3.3",
384 target="10.3", flags="-DMAC_OS_X_VERSION_MAX_ALLOWED=1040")
385 else:
386 doMacLipoBuild("ppc", buildDir, installDir)
387
388 doMacLipoBuild("i386", buildDir, installDir)
389
390 # Use lipo to merge together all binaries in the install dirs, and it
391 # also copies all other files and links it finds to the new destination.
392 result = os.system("python %s/distrib/scripts/mac/lipo-dir.py %s %s %s" %
393 (wxRootDir, installDir+"/ppc", installDir+"/i386", installDir))
394
395 # tweak the wx-config script
396 fname = os.path.abspath(installDir + '/bin/wx-config')
397 data = open(fname).read()
398 data = data.replace('ppc/', '')
399 data = data.replace('i386/', '')
400 open(fname, 'w').write(data)
401
402 shutil.rmtree(installDir + "/ppc")
403 shutil.rmtree(installDir + "/i386")
404
405
406
407 if not isLipo:
408 if options.extra_make:
409 args.append(options.extra_make)
410 exitIfError(wxBuilder.build(dir=buildDir, options=args), "Error building")
411
412 if options.wxpython and os.path.exists(contribDir):
413 exitIfError(wxBuilder.build(os.path.join(contribDir, "gizmos"), options=args), "Error building gizmos")
414 exitIfError(wxBuilder.build(os.path.join(contribDir, "stc"),options=args), "Error building stc")
415
416 if options.install:
417 extra=None
418 if installDir:
419 extra = ['DESTDIR='+installDir]
420 wxBuilder.install(options=extra)
421
422 if options.wxpython and os.path.exists(contribDir):
423 exitIfError(wxBuilder.install(os.path.join(contribDir, "gizmos"), options=extra), "Error building gizmos")
424 exitIfError(wxBuilder.install(os.path.join(contribDir, "stc"), options=extra), "Error building stc")
425
426 if options.mac_framework:
427
428 def renameLibrary(libname, frameworkname):
429 reallib = libname
430 links = []
431 while os.path.islink(reallib):
432 links.append(reallib)
433 reallib = "lib/" + os.readlink(reallib)
434
435 print "reallib is %s" % reallib
436 os.system("mv -f %s lib/%s.dylib" % (reallib, frameworkname))
437
438 for link in links:
439 os.system("ln -s -f %s.dylib %s" % (frameworkname, link))
440
441 os.chdir(installDir)
442 build_string = ""
443 if options.debug:
444 build_string = "d"
445 version = commands.getoutput("bin/wx-config --release")
446 basename = commands.getoutput("bin/wx-config --basename")
447 configname = commands.getoutput("bin/wx-config --selected-config")
448
449 os.system("ln -s -f bin Resources")
450
451 # we make wx the "actual" library file and link to it from libwhatever.dylib
452 # so that things can link to wx and survive minor version changes
453 renameLibrary("lib/lib%s-%s.dylib" % (basename, version), "wx")
454 os.system("ln -s -f lib/wx.dylib wx")
455
456 os.system("ln -s -f include/wx Headers")
457
458 for lib in ["GL", "STC", "Gizmos", "Gizmos_xrc"]:
459 libfile = "lib/lib%s_%s-%s.dylib" % (basename, lib.lower(), version)
460 if os.path.exists(libfile):
461 frameworkDir = "framework/wx%s/%s" % (lib, version)
462 if not os.path.exists(frameworkDir):
463 os.makedirs(frameworkDir)
464 renameLibrary(libfile, "wx" + lib)
465 os.system("ln -s -f ../../../%s %s/wx%s" % (libfile, frameworkDir, lib))
466
467 for lib in glob.glob("lib/*.dylib"):
468 if not os.path.islink(lib):
469 corelibname = "lib/lib%s-%s.0.dylib" % (basename, version)
470 os.system("install_name_tool -id %s %s" % (os.path.join(installDir, lib), lib))
471 os.system("install_name_tool -change %s %s %s" % (os.path.join(installDir, "i386", corelibname), os.path.join(installDir, corelibname), lib))
472
473 os.chdir("include")
474
475 header_template = """
476
477 #ifndef __WX_FRAMEWORK_HEADER__
478 #define __WX_FRAMEWORK_HEADER__
479
480 %s
481
482 #endif // __WX_FRAMEWORK_HEADER__
483 """
484 headers = ""
485 header_dir = "wx-%s/wx" % version
486 for include in glob.glob(header_dir + "/*.h"):
487 headers += "wx/" + os.path.basename(include) + "\n"
488
489 framework_header = open("wx.h", "w")
490 framework_header.write(header_template % headers)
491 framework_header.close()
492
493 os.system("ln -s -f %s wx" % header_dir)
494 os.system("ln -s -f ../../../lib/wx/include/%s/wx/setup.h wx/setup.h" % configname)
495
496 os.chdir(os.path.join(installDir, "..", ".."))
497 os.system("ln -s -f %s Versions/Current" % os.path.basename(installDir))
498 os.system("ln -s -f Versions/Current/Headers Headers")
499 os.system("ln -s -f Versions/Current/Resources Resources")
500 os.system("ln -s -f Versions/Current/wx wx")
501
502
503 # adjust the install_name if needed TODO: skip this for framework builds?
504 if sys.platform.startswith("darwin") and \
505 options.install and \
506 options.installdir and \
507 not options.wxpython: # wxPython's build will do this later if needed
508 prefix = options.prefix
509 if not prefix:
510 prefix = '/usr/local'
511 macFixupInstallNames(options.installdir, prefix)#, buildDir)
512
513
514
515 if __name__ == '__main__':
516 exitWithException = False # use sys.exit instead
517 main(sys.argv[0], sys.argv[1:])
518