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