]> git.saurik.com Git - wxWidgets.git/blob - build/tools/build-wxwidgets.py
ed00782626aafaa95b2fda33238e1deb8ea61807
[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 verbose = False
31
32
33 def numCPUs():
34 """
35 Detects the number of CPUs on a system.
36 This approach is from detectCPUs here: http://www.artima.com/weblogs/viewpost.jsp?thread=230001
37 """
38 # Linux, Unix and MacOS:
39 if hasattr(os, "sysconf"):
40 if os.sysconf_names.has_key("SC_NPROCESSORS_ONLN"):
41 # Linux & Unix:
42 ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
43 if isinstance(ncpus, int) and ncpus > 0:
44 return ncpus
45 else: # OSX:
46 return int(os.popen2("sysctl -n hw.ncpu")[1].read())
47 # Windows:
48 if os.environ.has_key("NUMBER_OF_PROCESSORS"):
49 ncpus = int(os.environ["NUMBER_OF_PROCESSORS"]);
50 if ncpus > 0:
51 return ncpus
52 return 1 # Default
53
54
55 def exitIfError(code, msg):
56 if code != 0:
57 print msg
58 if exitWithException:
59 raise builder.BuildError, msg
60 else:
61 sys.exit(1)
62
63
64 def getWxRelease():
65 global wxRootDir
66 configureText = open(os.path.join(wxRootDir, "configure.in"), "r").read()
67
68 majorVersion = re.search("wx_major_version_number=(\d+)", configureText).group(1)
69 minorVersion = re.search("wx_minor_version_number=(\d+)", configureText).group(1)
70
71 versionText = "%s.%s" % (majorVersion, minorVersion)
72
73 if int(minorVersion) % 2:
74 releaseVersion = re.search("wx_release_number=(\d+)", configureText).group(1)
75 versionText += ".%s" % (releaseVersion)
76
77 return versionText
78
79
80 def macFixupInstallNames(destdir, prefix, buildDir=None):
81 # When an installdir is used then the install_names embedded in
82 # the dylibs are not correct. Reset the IDs and the dependencies
83 # to use just the prefix.
84 print "**** macFixupInstallNames(%s, %s, %s)" % (destdir, prefix, buildDir)
85 pwd = os.getcwd()
86 os.chdir(destdir+prefix+'/lib')
87 dylibs = glob.glob('*.dylib') # ('*[0-9].[0-9].[0-9].[0-9]*.dylib')
88 for lib in dylibs:
89 cmd = 'install_name_tool -id %s/lib/%s %s/lib/%s' % \
90 (prefix,lib, destdir+prefix,lib)
91 print cmd
92 run(cmd)
93 for dep in dylibs:
94 if buildDir is not None:
95 cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s/lib/%s' % \
96 (buildDir,dep, prefix,dep, destdir+prefix,lib)
97 else:
98 cmd = 'install_name_tool -change %s/lib/%s %s/lib/%s %s/lib/%s' % \
99 (destdir+prefix,dep, prefix,dep, destdir+prefix,lib)
100 print cmd
101 run(cmd)
102 os.chdir(pwd)
103
104
105 def run(cmd):
106 global verbose
107 if verbose:
108 print "Running %s" % cmd
109 return exitIfError(os.system(cmd), "Error running %s" % cmd)
110
111 def main(scriptName, args):
112 global scriptDir
113 global wxRootDir
114 global contribDir
115 global options
116 global configure_opts
117 global wxBuilder
118
119 scriptDir = os.path.dirname(os.path.abspath(scriptName))
120 wxRootDir = os.path.abspath(os.path.join(scriptDir, "..", ".."))
121
122 contribDir = os.path.join("contrib", "src")
123 installDir = None
124
125 VERSION = tuple([int(i) for i in getWxRelease().split('.')[:2]])
126
127 if sys.platform.startswith("win"):
128 contribDir = os.path.join(wxRootDir, "contrib", "build")
129
130 if sys.platform.startswith("win"):
131 toolkit = "msvc"
132 else:
133 toolkit = "autoconf"
134
135 option_dict = {
136 "clean" : (False, "Clean all files from the build directory"),
137 "debug" : (False, "Build the library in debug symbols"),
138 "builddir" : ("", "Directory where the build will be performed for autoconf builds."),
139 "prefix" : ("", "Configured prefix to use for autoconf builds. Defaults to installdir if set."),
140 "j" : (repr(numCPUs()), "Number of jobs to run at one time."),
141 "install" : (False, "Install the toolkit to the installdir directory, or the default dir."),
142 "installdir" : ("", "Directory where built wxWidgets will be installed"),
143 "mac_distdir": (None, "If set on Mac, will create an installer package in the specified dir."),
144 "mac_universal_binary" : (False, "Build Mac version as a universal binary"),
145 "mac_arch" : ("", "Build just the specified architecture on Mac"),
146 "mac_framework" : (False, "Install the Mac build as a framework"),
147 "no_config" : (False, "Turn off configure step on autoconf builds"),
148 "config_only": (False, "Only run the configure step and then exit"),
149 "rebake" : (False, "Regenerate Bakefile and autoconf files"),
150 "unicode" : (False, "Build the library with unicode support"),
151 "wxpython" : (False, "Build the wxWidgets library with all options needed by wxPython"),
152 "cocoa" : (False, "Build the Cooca port (Mac only currently)."),
153 "osx_cocoa" : (False, "Build the new Cocoa port"),
154 "shared" : (False, "Build wx as a dynamic library"),
155 "cairo" : (False, "Build support for wxCairoContext (always true on GTK+)"),
156 "extra_make" : ("", "Extra args to pass on [n]make's command line."),
157 "features" : ("", "A comma-separated list of wxUSE_XYZ defines on Win, or a list of configure flags on unix."),
158 }
159
160 parser = optparse.OptionParser(usage="usage: %prog [options]", version="%prog 1.0")
161
162 for opt in option_dict:
163 default = option_dict[opt][0]
164
165 action = "store"
166 if type(default) == types.BooleanType:
167 action = "store_true"
168 parser.add_option("--" + opt, default=default, action=action, dest=opt, help=option_dict[opt][1])
169
170 options, arguments = parser.parse_args(args=args)
171
172 # compiler / build system specific args
173 buildDir = options.builddir
174 args = []
175 installDir = options.installdir
176 prefixDir = options.prefix
177
178 if toolkit == "autoconf":
179 if not buildDir:
180 buildDir = os.getcwd()
181 configure_opts = []
182 if options.features != "":
183 configure_opts.extend(options.features.split(" "))
184
185 if options.unicode:
186 configure_opts.append("--enable-unicode")
187
188 if options.debug:
189 configure_opts.append("--enable-debug")
190
191 if options.cocoa:
192 configure_opts.append("--with-old_cocoa")
193
194 if options.osx_cocoa:
195 configure_opts.append("--with-osx_cocoa")
196
197 if options.mac_arch:
198 configure_opts.append("--enable-macosx_arch=%s" % options.mac_arch)
199
200 wxpy_configure_opts = [
201 "--with-opengl",
202 "--enable-sound",
203 "--enable-graphics_ctx",
204 "--enable-mediactrl",
205 "--enable-display",
206 "--enable-geometry",
207 "--enable-debug_flag",
208 "--enable-optimise",
209 "--disable-debugreport",
210 "--enable-uiactionsim",
211 ]
212
213 if sys.platform.startswith("darwin"):
214 wxpy_configure_opts.append("--enable-monolithic")
215 else:
216 wxpy_configure_opts.append("--with-sdl")
217 wxpy_configure_opts.append("--with-gnomeprint")
218
219 # Ensure that the Carbon build stays compatible back to 10.4 and
220 # for the Cocoa build allow running on 10.5 and newer. We only add
221 # them to the wxpy options because this is a hard-requirement for
222 # wxPython, but other cases it is optional and is left up to the
223 # developer. TODO: there should be a command line option to set
224 # the SDK...
225 if sys.platform.startswith("darwin"):
226 if not options.osx_cocoa:
227 wxpy_configure_opts.append(
228 "--with-macosx-sdk=/Developer/SDKs/MacOSX10.4u.sdk")
229 else:
230 wxpy_configure_opts.append(
231 "--with-macosx-sdk=/Developer/SDKs/MacOSX10.5.sdk")
232
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 = run("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_universal_binary = True
254 name = "wxOSX"
255 if options.osx_cocoa:
256 name += "Cocoa"
257 else:
258 name += "Carbon"
259 prefixDir = "/Library/Frameworks/%s.framework/Versions/%s" % (name, getWxRelease())
260 # framework builds always need to be monolithic
261 if not "--enable-monolithic" in configure_opts:
262 configure_opts.append("--enable-monolithic")
263
264 if installDir and not prefixDir:
265 prefixDir = installDir
266 if prefixDir:
267 configure_opts.append("--prefix=" + prefixDir)
268
269 if options.mac_universal_binary:
270 configure_opts.append("--enable-universal_binary")
271
272 print "Configure options: " + `configure_opts`
273 wxBuilder = builder.AutoconfBuilder()
274 if not options.no_config and not options.clean:
275 olddir = os.getcwd()
276 if buildDir:
277 os.chdir(buildDir)
278 exitIfError(wxBuilder.configure(dir=wxRootDir, options=configure_opts),
279 "Error running configure")
280 os.chdir(olddir)
281
282 if options.config_only:
283 print "Exiting after configure"
284 return
285
286 elif toolkit in ["msvc", "msvcProject"]:
287 flags = {}
288 buildDir = os.path.abspath(os.path.join(scriptDir, "..", "msw"))
289
290 print "creating wx/msw/setup.h from setup0.h"
291 if options.unicode:
292 flags["wxUSE_UNICODE"] = "1"
293 if VERSION < (2,9):
294 flags["wxUSE_UNICODE_MSLU"] = "1"
295
296 if options.cairo:
297 flags["wxUSE_CAIRO"] = "1"
298
299 if options.wxpython:
300 flags["wxDIALOG_UNIT_COMPATIBILITY "] = "0"
301 flags["wxUSE_DEBUGREPORT"] = "0"
302 flags["wxUSE_DIALUP_MANAGER"] = "0"
303 flags["wxUSE_GRAPHICS_CONTEXT"] = "1"
304 flags["wxUSE_DISPLAY"] = "1"
305 flags["wxUSE_GLCANVAS"] = "1"
306 flags["wxUSE_POSTSCRIPT"] = "1"
307 flags["wxUSE_AFM_FOR_POSTSCRIPT"] = "0"
308 flags["wxUSE_DATEPICKCTRL_GENERIC"] = "1"
309
310 if VERSION < (2,9):
311 flags["wxUSE_DIB_FOR_BITMAP"] = "1"
312
313 if VERSION >= (2,9):
314 flags["wxUSE_UIACTIONSIMULATOR"] = "1"
315
316
317 mswIncludeDir = os.path.join(wxRootDir, "include", "wx", "msw")
318 setup0File = os.path.join(mswIncludeDir, "setup0.h")
319 setupText = open(setup0File, "rb").read()
320
321 for flag in flags:
322 setupText, subsMade = re.subn(flag + "\s+?\d", "%s %s" % (flag, flags[flag]), setupText)
323 if subsMade == 0:
324 print "Flag %s wasn't found in setup0.h!" % flag
325 sys.exit(1)
326
327 setupFile = open(os.path.join(mswIncludeDir, "setup.h"), "wb")
328 setupFile.write(setupText)
329 setupFile.close()
330 args = []
331 if toolkit == "msvc":
332 print "setting build options..."
333 args.append("-f makefile.vc")
334 if options.unicode:
335 args.append("UNICODE=1")
336 if VERSION < (2,9):
337 args.append("MSLU=1")
338
339 if options.wxpython:
340 args.append("OFFICIAL_BUILD=1")
341 args.append("SHARED=1")
342 args.append("MONOLITHIC=0")
343 args.append("USE_OPENGL=1")
344 args.append("USE_GDIPLUS=1")
345
346 if not options.debug:
347 args.append("BUILD=release")
348 else:
349 args.append("BUILD=debug")
350
351 wxBuilder = builder.MSVCBuilder()
352
353 if toolkit == "msvcProject":
354 args = []
355 if options.shared or options.wxpython:
356 args.append("wx_dll.dsw")
357 else:
358 args.append("wx.dsw")
359
360 # TODO:
361 wxBuilder = builder.MSVCProjectBuilder()
362
363 if not wxBuilder:
364 print "Builder not available for your specified platform/compiler."
365 sys.exit(1)
366
367 if options.clean:
368 print "Performing cleanup."
369 wxBuilder.clean()
370
371 if options.wxpython:
372 exitIfError(wxBuilder.clean(os.path.join(contribDir, "gizmos")), "Error building gizmos")
373 exitIfError(wxBuilder.clean(os.path.join(contribDir, "stc")), "Error building stc")
374
375 sys.exit(0)
376
377 if options.extra_make:
378 args.append(options.extra_make)
379 args.append("-j" + options.j)
380 exitIfError(wxBuilder.build(dir=buildDir, options=args), "Error building")
381
382 if options.wxpython and os.path.exists(contribDir):
383 exitIfError(wxBuilder.build(os.path.join(contribDir, "gizmos"), options=args), "Error building gizmos")
384 exitIfError(wxBuilder.build(os.path.join(contribDir, "stc"),options=args), "Error building stc")
385
386 if options.install:
387 extra=None
388 if installDir:
389 extra = ['DESTDIR='+installDir]
390 wxBuilder.install(options=extra)
391
392 if options.wxpython and os.path.exists(contribDir):
393 exitIfError(wxBuilder.install(os.path.join(contribDir, "gizmos"), options=extra), "Error building gizmos")
394 exitIfError(wxBuilder.install(os.path.join(contribDir, "stc"), options=extra), "Error building stc")
395
396 if options.mac_framework:
397
398 def renameLibrary(libname, frameworkname):
399 reallib = libname
400 links = []
401 while os.path.islink(reallib):
402 links.append(reallib)
403 reallib = "lib/" + os.readlink(reallib)
404
405 print "reallib is %s" % reallib
406 run("mv -f %s lib/%s.dylib" % (reallib, frameworkname))
407
408 for link in links:
409 run("ln -s -f %s.dylib %s" % (frameworkname, link))
410
411 frameworkRootDir = prefixDir
412 if installDir:
413 print "installDir = %s" % installDir
414 frameworkRootDir = installDir + prefixDir
415 os.chdir(frameworkRootDir)
416 build_string = ""
417 if options.debug:
418 build_string = "d"
419
420 version = commands.getoutput("bin/wx-config --release")
421 basename = commands.getoutput("bin/wx-config --basename")
422 configname = commands.getoutput("bin/wx-config --selected-config")
423
424 run("ln -s -f bin Resources")
425
426 # we make wx the "actual" library file and link to it from libwhatever.dylib
427 # so that things can link to wx and survive minor version changes
428 renameLibrary("lib/lib%s-%s.dylib" % (basename, version), "wx")
429 run("ln -s -f lib/wx.dylib wx")
430
431 run("ln -s -f include/wx Headers")
432
433 for lib in ["GL", "STC", "Gizmos", "Gizmos_xrc"]:
434 libfile = "lib/lib%s_%s-%s.dylib" % (basename, lib.lower(), version)
435 if os.path.exists(libfile):
436 frameworkDir = "framework/wx%s/%s" % (lib, version)
437 if not os.path.exists(frameworkDir):
438 os.makedirs(frameworkDir)
439 renameLibrary(libfile, "wx" + lib)
440 run("ln -s -f ../../../%s %s/wx%s" % (libfile, frameworkDir, lib))
441
442 for lib in glob.glob("lib/*.dylib"):
443 if not os.path.islink(lib):
444 corelibname = "lib/lib%s-%s.0.dylib" % (basename, version)
445 run("install_name_tool -id %s %s" % (os.path.join(prefixDir, lib), lib))
446 run("install_name_tool -change %s %s %s" % (os.path.join(frameworkRootDir, corelibname), os.path.join(prefixDir, corelibname), lib))
447
448 os.chdir("include")
449
450 header_template = """
451
452 #ifndef __WX_FRAMEWORK_HEADER__
453 #define __WX_FRAMEWORK_HEADER__
454
455 %s
456
457 #endif // __WX_FRAMEWORK_HEADER__
458 """
459 headers = ""
460 header_dir = "wx-%s/wx" % version
461 for include in glob.glob(header_dir + "/*.h"):
462 headers += "wx/" + os.path.basename(include) + "\n"
463
464 framework_header = open("wx.h", "w")
465 framework_header.write(header_template % headers)
466 framework_header.close()
467
468 run("ln -s -f %s wx" % header_dir)
469 run("ln -s -f ../../../lib/wx/include/%s/wx/setup.h wx/setup.h" % configname)
470
471 os.chdir(os.path.join(frameworkRootDir, "..", ".."))
472 run("ln -s -f %s Versions/Current" % getWxRelease())
473 run("ln -s -f Versions/Current/Headers Headers")
474 run("ln -s -f Versions/Current/Resources Resources")
475 run("ln -s -f Versions/Current/wx wx")
476
477 # sanity check to ensure the symlink works
478 run("cd Versions/Current")
479 run("cd ../..")
480
481 # adjust the install_name if needed TODO: skip this for framework builds?
482 if sys.platform.startswith("darwin") and \
483 options.install and \
484 options.installdir and \
485 not options.wxpython: # wxPython's build will do this later if needed
486 if not prefixDir:
487 prefixDir = '/usr/local'
488 macFixupInstallNames(options.installdir, prefixDir)#, buildDir)
489
490 # make a package if a destdir was set.
491 if options.mac_framework and \
492 options.installdir and \
493 options.mac_distdir:
494
495 if os.path.exists(options.mac_distdir):
496 shutil.rmtree(options.mac_distdir)
497
498 packagedir = os.path.join(options.mac_distdir, "packages")
499 os.makedirs(packagedir)
500 basename = os.path.basename(prefixDir.split(".")[0])
501 packageName = basename + "-" + getWxRelease()
502 packageMakerPath = "/Developer/usr/bin/packagemaker "
503 args = []
504 args.append("--root %s" % options.installdir)
505 args.append("--id org.wxwidgets.%s" % basename.lower())
506 args.append("--title %s" % packageName)
507 args.append("--version %s" % getWxRelease())
508 args.append("--out %s" % os.path.join(packagedir, packageName + ".pkg"))
509 cmd = packageMakerPath + ' '.join(args)
510 print "cmd = %s" % cmd
511 run(cmd)
512
513 os.chdir(options.mac_distdir)
514
515 run('hdiutil create -srcfolder %s -volname "%s" -imagekey zlib-level=9 %s.dmg' % (packagedir, packageName, packageName))
516
517 shutil.rmtree(packagedir)
518
519 if __name__ == '__main__':
520 exitWithException = False # use sys.exit instead
521 main(sys.argv[0], sys.argv[1:])
522