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