develop.py
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:29k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. #!/usr/bin/env python
  2. #
  3. # @file develop.py
  4. # @authors Bryan O'Sullivan, Mark Palange, Aaron Brashears
  5. # @brief Fire and forget script to appropriately configure cmake for SL.
  6. #
  7. # $LicenseInfo:firstyear=2007&license=viewergpl$
  8. # Copyright (c) 2007-2010, Linden Research, Inc.
  9. # Second Life Viewer Source Code
  10. # The source code in this file ("Source Code") is provided by Linden Lab
  11. # to you under the terms of the GNU General Public License, version 2.0
  12. # ("GPL"), unless you have obtained a separate licensing agreement
  13. # ("Other License"), formally executed by you and Linden Lab.  Terms of
  14. # the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. # online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. # There are special exceptions to the terms and conditions of the GPL as
  17. # it is applied to this Source Code. View the full text of the exception
  18. # in the file doc/FLOSS-exception.txt in this software distribution, or
  19. # online at
  20. # http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21. # By copying, modifying or distributing this software, you acknowledge
  22. # that you have read and understood your obligations described above,
  23. # and agree to abide by those obligations.
  24. # ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  25. # WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  26. # COMPLETENESS OR PERFORMANCE.
  27. # $/LicenseInfo$
  28. import errno
  29. import getopt
  30. import os
  31. import random
  32. import re
  33. import shutil
  34. import socket
  35. import sys
  36. import commands
  37. import subprocess
  38. class CommandError(Exception):
  39.     pass
  40. def mkdir(path):
  41.     try:
  42.         os.mkdir(path)
  43.         return path
  44.     except OSError, err:
  45.         if err.errno != errno.EEXIST or not os.path.isdir(path):
  46.             raise
  47. def getcwd():
  48.     cwd = os.getcwd()
  49.     if 'a' <= cwd[0] <= 'z' and cwd[1] == ':':
  50.         # CMake wants DOS drive letters to be in uppercase.  The above
  51.         # condition never asserts on platforms whose full path names
  52.         # always begin with a slash, so we don't need to test whether
  53.         # we are running on Windows.
  54.         cwd = cwd[0].upper() + cwd[1:]
  55.     return cwd
  56. def quote(opts):
  57.     return '"' + '" "'.join([ opt.replace('"', '') for opt in opts ]) + '"'
  58. class PlatformSetup(object):
  59.     generator = None
  60.     build_types = {}
  61.     for t in ('Debug', 'Release', 'RelWithDebInfo'):
  62.         build_types[t.lower()] = t
  63.     build_type = build_types['relwithdebinfo']
  64.     standalone = 'OFF'
  65.     unattended = 'OFF'
  66.     universal = 'OFF'
  67.     project_name = 'SecondLife'
  68.     distcc = True
  69.     cmake_opts = []
  70.     word_size = 32
  71.     def __init__(self):
  72.         self.script_dir = os.path.realpath(
  73.             os.path.dirname(__import__(__name__).__file__))
  74.     def os(self):
  75.         '''Return the name of the OS.'''
  76.         raise NotImplemented('os')
  77.     def arch(self):
  78.         '''Return the CPU architecture.'''
  79.         return None
  80.     def platform(self):
  81.         '''Return a stringified two-tuple of the OS name and CPU
  82.         architecture.'''
  83.         ret = self.os()
  84.         if self.arch():
  85.             ret += '-' + self.arch()
  86.         return ret 
  87.     def build_dirs(self):
  88.         '''Return the top-level directories in which builds occur.
  89.         This can return more than one directory, e.g. if doing a
  90.         32-bit viewer and server build on Linux.'''
  91.         return ['build-' + self.platform()]
  92.     def cmake_commandline(self, src_dir, build_dir, opts, simple):
  93.         '''Return the command line to run cmake with.'''
  94.         args = dict(
  95.             dir=src_dir,
  96.             generator=self.generator,
  97.             opts=quote(opts),
  98.             standalone=self.standalone,
  99.             unattended=self.unattended,
  100.             word_size=self.word_size,
  101.             type=self.build_type.upper(),
  102.             )
  103.         #if simple:
  104.         #    return 'cmake %(opts)s %(dir)r' % args
  105.         return ('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
  106.                 '-DSTANDALONE:BOOL=%(standalone)s '
  107.                 '-DUNATTENDED:BOOL=%(unattended)s '
  108.                 '-DWORD_SIZE:STRING=%(word_size)s '
  109.                 '-G %(generator)r %(opts)s %(dir)r' % args)
  110.     def run_cmake(self, args=[]):
  111.         '''Run cmake.'''
  112.         # do a sanity check to make sure we have a generator
  113.         if not hasattr(self, 'generator'):
  114.             raise "No generator available for '%s'" % (self.__name__,)
  115.         cwd = getcwd()
  116.         created = []
  117.         try:
  118.             for d in self.build_dirs():
  119.                 simple = True
  120.                 if mkdir(d):
  121.                     created.append(d)
  122.                     simple = False
  123.                 try:
  124.                     os.chdir(d)
  125.                     cmd = self.cmake_commandline(cwd, d, args, simple)
  126.                     print 'Running %r in %r' % (cmd, d)
  127.                     self.run(cmd, 'cmake')
  128.                 finally:
  129.                     os.chdir(cwd)
  130.         except:
  131.             # If we created a directory in which to run cmake and
  132.             # something went wrong, the directory probably just
  133.             # contains garbage, so delete it.
  134.             os.chdir(cwd)
  135.             for d in created:
  136.                 print 'Cleaning %r' % d
  137.                 shutil.rmtree(d)
  138.             raise
  139.     def parse_build_opts(self, arguments):
  140.         opts, targets = getopt.getopt(arguments, 'o:', ['option='])
  141.         build_opts = []
  142.         for o, a in opts:
  143.             if o in ('-o', '--option'):
  144.                 build_opts.append(a)
  145.         return build_opts, targets
  146.     def run_build(self, opts, targets):
  147.         '''Build the default targets for this platform.'''
  148.         raise NotImplemented('run_build')
  149.     def cleanup(self):
  150.         '''Delete all build directories.'''
  151.         cleaned = 0
  152.         for d in self.build_dirs():
  153.             if os.path.isdir(d):
  154.                 print 'Cleaning %r' % d
  155.                 shutil.rmtree(d)
  156.                 cleaned += 1
  157.         if not cleaned:
  158.             print 'Nothing to clean up!'
  159.     def is_internal_tree(self):
  160.         '''Indicate whether we are building in an internal source tree.'''
  161.         return os.path.isdir(os.path.join(self.script_dir, 'newsim'))
  162.     def find_in_path(self, name, defval=None, basename=False):
  163.         for ext in self.exe_suffixes:
  164.             name_ext = name + ext
  165.             if os.sep in name_ext:
  166.                 path = os.path.abspath(name_ext)
  167.                 if os.access(path, os.X_OK):
  168.                     return [basename and os.path.basename(path) or path]
  169.             for p in os.getenv('PATH', self.search_path).split(os.pathsep):
  170.                 path = os.path.join(p, name_ext)
  171.                 if os.access(path, os.X_OK):
  172.                     return [basename and os.path.basename(path) or path]
  173.         if defval:
  174.             return [defval]
  175.         return []
  176. class UnixSetup(PlatformSetup):
  177.     '''Generic Unixy build instructions.'''
  178.     search_path = '/usr/bin:/usr/local/bin'
  179.     exe_suffixes = ('',)
  180.     def __init__(self):
  181.         super(UnixSetup, self).__init__()
  182.         self.generator = 'Unix Makefiles'
  183.     def os(self):
  184.         return 'unix'
  185.     def arch(self):
  186.         cpu = os.uname()[-1]
  187.         if cpu.endswith('386'):
  188.             cpu = 'i386'
  189.         elif cpu.endswith('86'):
  190.             cpu = 'i686'
  191.         elif cpu in ('athlon',):
  192.             cpu = 'i686'
  193.         elif cpu == 'Power Macintosh':
  194.             cpu = 'ppc'
  195.         elif cpu == 'x86_64' and self.word_size == 32:
  196.             cpu = 'i686'
  197.         return cpu
  198.     def run(self, command, name=None):
  199.         '''Run a program.  If the program fails, raise an exception.'''
  200.         sys.stdout.flush()
  201.         ret = os.system(command)
  202.         if ret:
  203.             if name is None:
  204.                 name = command.split(None, 1)[0]
  205.             if os.WIFEXITED(ret):
  206.                 st = os.WEXITSTATUS(ret)
  207.                 if st == 127:
  208.                     event = 'was not found'
  209.                 else:
  210.                     event = 'exited with status %d' % st
  211.             elif os.WIFSIGNALED(ret):
  212.                 event = 'was killed by signal %d' % os.WTERMSIG(ret)
  213.             else:
  214.                 event = 'died unexpectedly (!?) with 16-bit status %d' % ret
  215.             raise CommandError('the command %r %s' %
  216.                                (name, event))
  217. class LinuxSetup(UnixSetup):
  218.     def __init__(self):
  219.         super(LinuxSetup, self).__init__()
  220.         try:
  221.             self.debian_sarge = open('/etc/debian_version').read().strip() == '3.1'
  222.         except:
  223.             self.debian_sarge = False
  224.     def os(self):
  225.         return 'linux'
  226.     def build_dirs(self):
  227.         # Only build the server code if we have it.
  228.         platform_build = '%s-%s' % (self.platform(), self.build_type.lower())
  229.         if self.arch() == 'i686' and self.is_internal_tree():
  230.             return ['viewer-' + platform_build, 'server-' + platform_build]
  231.         elif self.arch() == 'x86_64' and self.is_internal_tree():
  232.             # the viewer does not build in 64bit -- kdu5 issues
  233.             # we can either use openjpeg, or overhaul our viewer to handle kdu5 or higher
  234.             # doug knows about kdu issues
  235.             return ['server-' + platform_build]
  236.         else:
  237.             return ['viewer-' + platform_build]
  238.     def cmake_commandline(self, src_dir, build_dir, opts, simple):
  239.         args = dict(
  240.             dir=src_dir,
  241.             generator=self.generator,
  242.             opts=quote(opts),
  243.             standalone=self.standalone,
  244.             unattended=self.unattended,
  245.             type=self.build_type.upper(),
  246.             project_name=self.project_name,
  247.             word_size=self.word_size,
  248.             )
  249.         if not self.is_internal_tree():
  250.             args.update({'cxx':'g++', 'server':'OFF', 'viewer':'ON'})
  251.         else:
  252.             if self.distcc:
  253.                 distcc = self.find_in_path('distcc')
  254.                 baseonly = True
  255.             else:
  256.                 distcc = []
  257.                 baseonly = False
  258.             if 'server' in build_dir:
  259.                 gcc = distcc + self.find_in_path(
  260.                     self.debian_sarge and 'g++-3.3' or 'g++-4.1',
  261.                     'g++', baseonly)
  262.                 args.update({'cxx': ' '.join(gcc), 'server': 'ON',
  263.                              'viewer': 'OFF'})
  264.             else:
  265.                 gcc41 = distcc + self.find_in_path('g++-4.1', 'g++', baseonly)
  266.                 args.update({'cxx': ' '.join(gcc41),
  267.                              'server': 'OFF',
  268.                              'viewer': 'ON'})
  269.         cmd = (('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
  270.                 '-G %(generator)r -DSERVER:BOOL=%(server)s '
  271.                 '-DVIEWER:BOOL=%(viewer)s -DSTANDALONE:BOOL=%(standalone)s '
  272.                 '-DUNATTENDED:BOOL=%(unattended)s '
  273.                 '-DWORD_SIZE:STRING=%(word_size)s '
  274.                 '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
  275.                 '%(opts)s %(dir)r')
  276.                % args)
  277.         if 'CXX' not in os.environ:
  278.             args.update({'cmd':cmd})
  279.             cmd = ('CXX=%(cxx)r %(cmd)s' % args)
  280.         return cmd
  281.     def run_build(self, opts, targets):
  282.         job_count = None
  283.         for i in range(len(opts)):
  284.             if opts[i].startswith('-j'):
  285.                 try:
  286.                     job_count = int(opts[i][2:])
  287.                 except ValueError:
  288.                     try:
  289.                         job_count = int(opts[i+1])
  290.                     except ValueError:
  291.                         job_count = True
  292.         def get_cpu_count():
  293.             count = 0
  294.             for line in open('/proc/cpuinfo'):
  295.                 if re.match(r'processors*:', line):
  296.                     count += 1
  297.             return count
  298.         def localhost():
  299.             count = get_cpu_count()
  300.             return 'localhost/' + str(count), count
  301.         def get_distcc_hosts():
  302.             try:
  303.                 hosts = []
  304.                 name = os.getenv('DISTCC_DIR', '/etc/distcc') + '/hosts'
  305.                 for l in open(name):
  306.                     l = l[l.find('#')+1:].strip()
  307.                     if l: hosts.append(l)
  308.                 return hosts
  309.             except IOError:
  310.                 return (os.getenv('DISTCC_HOSTS', '').split() or
  311.                         [localhost()[0]])
  312.         def count_distcc_hosts():
  313.             cpus = 0
  314.             hosts = 0
  315.             for host in get_distcc_hosts():
  316.                 m = re.match(r'.*/(d+)', host)
  317.                 hosts += 1
  318.                 cpus += m and int(m.group(1)) or 1
  319.             return hosts, cpus
  320.         def mk_distcc_hosts(basename, range, num_cpus):
  321.             '''Generate a list of LL-internal machines to build on.'''
  322.             loc_entry, cpus = localhost()
  323.             hosts = [loc_entry]
  324.             dead = []
  325.             stations = [s for s in xrange(range) if s not in dead]
  326.             random.shuffle(stations)
  327.             hosts += ['%s%d.lindenlab.com/%d,lzo' % (basename, s, num_cpus) for s in stations]
  328.             cpus += 2 * len(stations)
  329.             return ' '.join(hosts), cpus
  330.         if job_count is None:
  331.             hosts, job_count = count_distcc_hosts()
  332.             hostname = socket.gethostname()
  333.             if hosts == 1:
  334.                 if hostname.startswith('station'):
  335.                     hosts, job_count = mk_distcc_hosts('station', 36, 2)
  336.                     os.environ['DISTCC_HOSTS'] = hosts
  337.                 if hostname.startswith('eniac'):
  338.                     hosts, job_count = mk_distcc_hosts('eniac', 71, 2)
  339.                     os.environ['DISTCC_HOSTS'] = hosts
  340.             if hostname.startswith('build'):
  341.                 max_jobs = 6
  342.             else:
  343.                 max_jobs = 12
  344.             if job_count > max_jobs:
  345.                 job_count = max_jobs;
  346.             opts.extend(['-j', str(job_count)])
  347.         if targets:
  348.             targets = ' '.join(targets)
  349.         else:
  350.             targets = 'all'
  351.         for d in self.build_dirs():
  352.             cmd = 'make -C %r %s %s' % (d, ' '.join(opts), targets)
  353.             print 'Running %r' % cmd
  354.             self.run(cmd)
  355.         
  356. class DarwinSetup(UnixSetup):
  357.     def __init__(self):
  358.         super(DarwinSetup, self).__init__()
  359.         self.generator = 'Xcode'
  360.     def os(self):
  361.         return 'darwin'
  362.     def arch(self):
  363.         if self.universal == 'ON':
  364.             return 'universal'
  365.         else:
  366.             return UnixSetup.arch(self)
  367.     def cmake_commandline(self, src_dir, build_dir, opts, simple):
  368.         args = dict(
  369.             dir=src_dir,
  370.             generator=self.generator,
  371.             opts=quote(opts),
  372.             standalone=self.standalone,
  373.             word_size=self.word_size,
  374.             unattended=self.unattended,
  375.             project_name=self.project_name,
  376.             universal=self.universal,
  377.             type=self.build_type.upper(),
  378.             )
  379.         if self.universal == 'ON':
  380.             args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc''
  381.         #if simple:
  382.         #    return 'cmake %(opts)s %(dir)r' % args
  383.         return ('cmake -G %(generator)r '
  384.                 '-DCMAKE_BUILD_TYPE:STRING=%(type)s '
  385.                 '-DSTANDALONE:BOOL=%(standalone)s '
  386.                 '-DUNATTENDED:BOOL=%(unattended)s '
  387.                 '-DWORD_SIZE:STRING=%(word_size)s '
  388.                 '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
  389.                 '%(universal)s '
  390.                 '%(opts)s %(dir)r' % args)
  391.     def run_build(self, opts, targets):
  392.         cwd = getcwd()
  393.         if targets:
  394.             targets = ' '.join(['-target ' + repr(t) for t in targets])
  395.         else:
  396.             targets = ''
  397.         cmd = ('xcodebuild -configuration %s %s %s | grep -v "^[[:space:]]*setenv" ; exit ${PIPESTATUS[0]}' %
  398.                (self.build_type, ' '.join(opts), targets))
  399.         for d in self.build_dirs():
  400.             try:
  401.                 os.chdir(d)
  402.                 print 'Running %r in %r' % (cmd, d)
  403.                 self.run(cmd)
  404.             finally:
  405.                 os.chdir(cwd)
  406. class WindowsSetup(PlatformSetup):
  407.     gens = {
  408.         'vc71' : {
  409.             'gen' : r'Visual Studio 7 .NET 2003',
  410.             'ver' : r'7.1'
  411.             },
  412.         'vc80' : {
  413.             'gen' : r'Visual Studio 8 2005',
  414.             'ver' : r'8.0'
  415.             },
  416.         'vc90' : {
  417.             'gen' : r'Visual Studio 9 2008',
  418.             'ver' : r'9.0'
  419.             }
  420.         }
  421.     gens['vs2003'] = gens['vc71']
  422.     gens['vs2005'] = gens['vc80']
  423.     gens['vs2008'] = gens['vc90']
  424.     search_path = r'C:windows'
  425.     exe_suffixes = ('.exe', '.bat', '.com')
  426.     def __init__(self):
  427.         super(WindowsSetup, self).__init__()
  428.         self._generator = None
  429.         self.incredibuild = False
  430.     def _get_generator(self):
  431.         if self._generator is None:
  432.             for version in 'vc80 vc90 vc71'.split():
  433.                 if self.find_visual_studio(version):
  434.                     self._generator = version
  435.                     print 'Building with ', self.gens[version]['gen']
  436.                     break
  437.             else:
  438.                 print >> sys.stderr, 'Cannot find a Visual Studio installation!'
  439.                 sys.exit(1)
  440.         return self._generator
  441.     def _set_generator(self, gen):
  442.         self._generator = gen
  443.     generator = property(_get_generator, _set_generator)
  444.     def os(self):
  445.         return 'win32'
  446.     def build_dirs(self):
  447.         return ['build-' + self.generator]
  448.     def cmake_commandline(self, src_dir, build_dir, opts, simple):
  449.         args = dict(
  450.             dir=src_dir,
  451.             generator=self.gens[self.generator.lower()]['gen'],
  452.             opts=quote(opts),
  453.             standalone=self.standalone,
  454.             unattended=self.unattended,
  455.             project_name=self.project_name,
  456.             word_size=self.word_size,
  457.             )
  458.         #if simple:
  459.         #    return 'cmake %(opts)s "%(dir)s"' % args
  460.         return ('cmake -G "%(generator)s" '
  461.                 '-DSTANDALONE:BOOL=%(standalone)s '
  462.                 '-DUNATTENDED:BOOL=%(unattended)s '
  463.                 '-DWORD_SIZE:STRING=%(word_size)s '
  464.                 '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
  465.                 '%(opts)s "%(dir)s"' % args)
  466.     def get_HKLM_registry_value(self, key_str, value_str):
  467.         import _winreg
  468.         reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
  469.         key = _winreg.OpenKey(reg, key_str)
  470.         value = _winreg.QueryValueEx(key, value_str)[0]
  471.         print 'Found: %s' % value
  472.         return value
  473.         
  474.     def find_visual_studio(self, gen=None):
  475.         if gen is None:
  476.             gen = self._generator
  477.         gen = gen.lower()
  478.         value_str = (r'EnvironmentDirectory')
  479.         key_str = (r'SOFTWAREMicrosoftVisualStudio%sSetupVS' %
  480.                    self.gens[gen]['ver'])
  481.         print ('Reading VS environment from HKEY_LOCAL_MACHINE%s%s' %
  482.                (key_str, value_str))
  483.         try:
  484.             return self.get_HKLM_registry_value(key_str, value_str)           
  485.         except WindowsError, err:
  486.             key_str = (r'SOFTWAREWow6432NodeMicrosoftVisualStudio%sSetupVS' %
  487.                        self.gens[gen]['ver'])
  488.         try:
  489.             return self.get_HKLM_registry_value(key_str, value_str)
  490.         except:
  491.             print >> sys.stderr, "Didn't find ", self.gens[gen]['gen']
  492.             
  493.         return ''
  494.     def get_build_cmd(self):
  495.         if self.incredibuild:
  496.             config = self.build_type
  497.             if self.gens[self.generator]['ver'] in [ r'8.0', r'9.0' ]:
  498.                 config = '"%s|Win32"' % config
  499.             executable = 'buildconsole'
  500.             cmd = "%(bin)s %(prj)s.sln /build /cfg=%(cfg)s" % {'prj': self.project_name, 'cfg': config, 'bin': executable}
  501.             return (executable, cmd)
  502.         # devenv.com is CLI friendly, devenv.exe... not so much.
  503.         executable = '%sdevenv.com' % (self.find_visual_studio(),)
  504.         cmd = ('"%s" %s.sln /build %s' % 
  505.                 (executable, self.project_name, self.build_type))
  506.         return (executable, cmd)
  507.     def run(self, command, name=None, retry_on=None, retries=1):
  508.         '''Run a program.  If the program fails, raise an exception.'''
  509.         assert name is not None, 'On windows an executable path must be given in name. [DEV-44838]'
  510.         if os.path.isfile(name):
  511.             path = name
  512.         else:
  513.             path = self.find_in_path(name)[0]
  514.         while retries:
  515.             retries = retries - 1
  516.             print "develop.py tries to run:", command
  517.             ret = subprocess.call(command, executable=path)
  518.             print "got ret", ret, "from", command
  519.             if ret == 0:
  520.                 break
  521.             else:
  522.                 error = 'exited with status %d' % ret
  523.                 if retry_on is not None and retry_on == ret:
  524.                     print "Retrying... the command %r %s" % (name, error)
  525.                 else:
  526.                     raise CommandError('the command %r %s' % (name, error))
  527.     def run_cmake(self, args=[]):
  528.         '''Override to add the vstool.exe call after running cmake.'''
  529.         PlatformSetup.run_cmake(self, args)
  530.         if self.unattended == 'OFF':
  531.             self.run_vstool()
  532.     def run_vstool(self):
  533.         for build_dir in self.build_dirs():
  534.             stamp = os.path.join(build_dir, 'vstool.txt')
  535.             try:
  536.                 prev_build = open(stamp).read().strip()
  537.             except IOError:
  538.                 prev_build = ''
  539.             if prev_build == self.build_type:
  540.                 # Only run vstool if the build type has changed.
  541.                 continue
  542.             executable = os.path.join('tools','vstool','VSTool.exe')
  543.             vstool_cmd = (executable +
  544.                           ' --solution ' +
  545.                           os.path.join(build_dir,'SecondLife.sln') +
  546.                           ' --config ' + self.build_type +
  547.                           ' --startup secondlife-bin')
  548.             print 'Running %r in %r' % (vstool_cmd, getcwd())
  549.             self.run(vstool_cmd, name=executable)        
  550.             print >> open(stamp, 'w'), self.build_type
  551.         
  552.     def run_build(self, opts, targets):
  553.         for t in targets:
  554.             assert t.strip(), 'Unexpected empty targets: ' + repr(targets)
  555.         cwd = getcwd()
  556.         executable, build_cmd = self.get_build_cmd()
  557.         for d in self.build_dirs():
  558.             try:
  559.                 os.chdir(d)
  560.                 if targets:
  561.                     for t in targets:
  562.                         cmd = '%s /project %s %s' % (build_cmd, t, ' '.join(opts))
  563.                         print 'Running %r in %r' % (cmd, d)
  564.                         self.run(cmd, name=executable, retry_on=4, retries=3)
  565.                 else:
  566.                     cmd = '%s %s' % (build_cmd, ' '.join(opts))
  567.                     print 'Running %r in %r' % (cmd, d)
  568.                     self.run(cmd, name=executable, retry_on=4, retries=3)
  569.             finally:
  570.                 os.chdir(cwd)
  571.                 
  572. class CygwinSetup(WindowsSetup):
  573.     def __init__(self):
  574.         super(CygwinSetup, self).__init__()
  575.         self.generator = 'vc80'
  576.     def cmake_commandline(self, src_dir, build_dir, opts, simple):
  577.         dos_dir = commands.getoutput("cygpath -w %s" % src_dir)
  578.         args = dict(
  579.             dir=dos_dir,
  580.             generator=self.gens[self.generator.lower()]['gen'],
  581.             opts=quote(opts),
  582.             standalone=self.standalone,
  583.             unattended=self.unattended,
  584.             project_name=self.project_name,
  585.             word_size=self.word_size,
  586.             )
  587.         #if simple:
  588.         #    return 'cmake %(opts)s "%(dir)s"' % args
  589.         return ('cmake -G "%(generator)s" '
  590.                 '-DUNATTENDED:BOOl=%(unattended)s '
  591.                 '-DSTANDALONE:BOOL=%(standalone)s '
  592.                 '-DWORD_SIZE:STRING=%(word_size)s '
  593.                 '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
  594.                 '%(opts)s "%(dir)s"' % args)
  595. setup_platform = {
  596.     'darwin': DarwinSetup,
  597.     'linux2': LinuxSetup,
  598.     'win32' : WindowsSetup,
  599.     'cygwin' : CygwinSetup
  600.     }
  601. usage_msg = '''
  602. Usage:   develop.py [options] [command [command-options]]
  603. Options:
  604.   -h | --help           print this help message
  605.        --standalone     build standalone, without Linden prebuild libraries
  606.        --unattended     build unattended, do not invoke any tools requiring
  607.                         a human response
  608.        --universal      build a universal binary on Mac OS X (unsupported)
  609.   -t | --type=NAME      build type ("Debug", "Release", or "RelWithDebInfo")
  610.   -m32 | -m64           build architecture (32-bit or 64-bit)
  611.   -N | --no-distcc      disable use of distcc
  612.   -G | --generator=NAME generator name
  613.                         Windows: VC71 or VS2003 (default), VC80 (VS2005) or 
  614.                           VC90 (VS2008)
  615.                         Mac OS X: Xcode (default), Unix Makefiles
  616.                         Linux: Unix Makefiles (default), KDevelop3
  617.   -p | --project=NAME   set the root project name. (Doesn't effect makefiles)
  618.                         
  619. Commands:
  620.   build      configure and build default target
  621.   clean      delete all build directories, does not affect sources
  622.   configure  configure project by running cmake (default command if none given)
  623. Command-options for "configure":
  624.   We use cmake variables to change the build configuration.
  625.   -DSERVER:BOOL=OFF        Don't configure simulator/dataserver/etc
  626.   -DVIEWER:BOOL=OFF        Don't configure the viewer
  627.   -DPACKAGE:BOOL=ON        Create "package" target to make installers
  628.   -DLOCALIZESETUP:BOOL=ON  Create one win_setup target per supported language
  629. Examples:
  630.   Set up a viewer-only project for your system:
  631.     develop.py configure -DSERVER:BOOL=OFF
  632.   
  633.   Set up a Visual Studio 2005 project with "package" target:
  634.     develop.py -G vc80 configure -DPACKAGE:BOOL=ON
  635. '''
  636. def main(arguments):
  637.     if os.getenv('DISTCC_DIR') is None:
  638.         distcc_dir = os.path.join(getcwd(), '.distcc')
  639.         if not os.path.exists(distcc_dir):
  640.             os.mkdir(distcc_dir)
  641.         print "setting DISTCC_DIR to %s" % distcc_dir
  642.         os.environ['DISTCC_DIR'] = distcc_dir
  643.     else:
  644.         print "DISTCC_DIR is set to %s" % os.getenv('DISTCC_DIR')
  645.  
  646.     setup = setup_platform[sys.platform]()
  647.     try:
  648.         opts, args = getopt.getopt(
  649.             arguments,
  650.             '?hNt:p:G:m:',
  651.             ['help', 'standalone', 'no-distcc', 'unattended', 'universal', 'type=', 'incredibuild', 'generator=', 'project='])
  652.     except getopt.GetoptError, err:
  653.         print >> sys.stderr, 'Error:', err
  654.         print >> sys.stderr, """
  655. Note: You must pass -D options to cmake after the "configure" command
  656. For example: develop.py configure -DSERVER:BOOL=OFF"""
  657.         print >> sys.stderr, usage_msg.strip()
  658.         sys.exit(1)
  659.     for o, a in opts:
  660.         if o in ('-?', '-h', '--help'):
  661.             print usage_msg.strip()
  662.             sys.exit(0)
  663.         elif o in ('--standalone',):
  664.             setup.standalone = 'ON'
  665.         elif o in ('--unattended',):
  666.             setup.unattended = 'ON'
  667.         elif o in ('--universal',):
  668.             setup.universal = 'ON'
  669.         elif o in ('-m',):
  670.             if a in ('32', '64'):
  671.                 setup.word_size = int(a)
  672.             else:
  673.                 print >> sys.stderr, 'Error: unknown word size', repr(a)
  674.                 print >> sys.stderr, 'Supported word sizes: 32, 64'
  675.                 sys.exit(1)
  676.         elif o in ('-t', '--type'):
  677.             try:
  678.                 setup.build_type = setup.build_types[a.lower()]
  679.             except KeyError:
  680.                 print >> sys.stderr, 'Error: unknown build type', repr(a)
  681.                 print >> sys.stderr, 'Supported build types:'
  682.                 types = setup.build_types.values()
  683.                 types.sort()
  684.                 for t in types:
  685.                     print ' ', t
  686.                 sys.exit(1)
  687.         elif o in ('-G', '--generator'):
  688.             setup.generator = a
  689.         elif o in ('-N', '--no-distcc'):
  690.             setup.distcc = False
  691.         elif o in ('-p', '--project'):
  692.             setup.project_name = a
  693.         elif o in ('--incredibuild'):
  694.             setup.incredibuild = True
  695.         else:
  696.             print >> sys.stderr, 'INTERNAL ERROR: unhandled option', repr(o)
  697.             sys.exit(1)
  698.     if not args:
  699.         setup.run_cmake()
  700.         return
  701.     try:
  702.         cmd = args.pop(0)
  703.         if cmd in ('cmake', 'configure'):
  704.             setup.run_cmake(args)
  705.         elif cmd == 'build':
  706.             for d in setup.build_dirs():
  707.                 if not os.path.exists(d):
  708.                     raise CommandError('run "develop.py cmake" first')
  709.             setup.run_cmake()
  710.             opts, targets = setup.parse_build_opts(args)
  711.             setup.run_build(opts, targets)
  712.         elif cmd == 'clean':
  713.             if args:
  714.                 raise CommandError('clean takes no arguments')
  715.             setup.cleanup()
  716.         else:
  717.             print >> sys.stderr, 'Error: unknown subcommand', repr(cmd)
  718.             print >> sys.stderr, "(run 'develop.py --help' for help)"
  719.             sys.exit(1)
  720.     except getopt.GetoptError, err:
  721.         print >> sys.stderr, 'Error with %r subcommand: %s' % (cmd, err)
  722.         sys.exit(1)
  723. if __name__ == '__main__':
  724.     try:
  725.         main(sys.argv[1:])
  726.     except CommandError, err:
  727.         print >> sys.stderr, 'Error:', err
  728.         sys.exit(1)