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