From 63d86684975ce327932e5e213fa5bf01a0c996c9 Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Sat, 10 Apr 2010 21:16:10 +0000 Subject: [PATCH] Removed build dir from ignore, as it now contains build src --- build/README.txt | 1 + build/__init__.py | 0 build/commands.py | 683 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 684 insertions(+) create mode 100644 build/README.txt create mode 100644 build/__init__.py create mode 100644 build/commands.py diff --git a/build/README.txt b/build/README.txt new file mode 100644 index 00000000..006cc581 --- /dev/null +++ b/build/README.txt @@ -0,0 +1 @@ +Source code for the build system belongs in this directory. \ No newline at end of file diff --git a/build/__init__.py b/build/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/build/commands.py b/build/commands.py new file mode 100644 index 00000000..bca459d8 --- /dev/null +++ b/build/commands.py @@ -0,0 +1,683 @@ +import sys, os, ConfigParser, subprocess, shutil + +if sys.platform == 'win32': + import _winreg + +project = 'synergy-plus' +setup_version = 3 +website_url = 'http://code.google.com/p/synergy-plus' + +this_cmd = 'hm' +cmake_cmd = 'cmake' + +make_cmd = 'make' +xcodebuild_cmd = 'xcodebuild' + +source_dir = '..' # Source, relative to build. +cmake_dir = 'cmake' +bin_dir = 'bin' + +sln_filename = '%s.sln' % project +xcodeproj_filename = '%s.xcodeproj' % project +config_filename = '%s.cfg' % this_cmd + +# try_chdir(...) and restore_chdir() will use this +prevdir = '' + +win32_generators = { + '1' : 'Visual Studio 10', + '2' : 'Visual Studio 10 Win64', + '3' : 'Visual Studio 9 2008', + '4' : 'Visual Studio 9 2008 Win64', + '5' : 'Visual Studio 8 2005', + '6' : 'Visual Studio 8 2005 Win64', + '7' : 'Visual Studio 7', + '8' : 'Visual Studio 7 .NET 2003', + '9' : 'Visual Studio 6', + '10' : 'CodeBlocks - MinGW Makefiles', + '11' : 'CodeBlocks - Unix Makefiles', + '12': 'Eclipse CDT4 - MinGW Makefiles', + '13': 'Eclipse CDT4 - NMake Makefiles', + '14': 'Eclipse CDT4 - Unix Makefiles', + '15': 'MinGW Makefiles', + '16': 'NMake Makefiles', + '17': 'Unix Makefiles', + '18': 'Borland Makefiles', + '19': 'MSYS Makefiles', + '20': 'Watcom WMake', +} + +unix_generators = { + '1' : 'Unix Makefiles', + '2' : 'CodeBlocks - Unix Makefiles', + '3' : 'Eclipse CDT4 - Unix Makefiles', + '4' : 'KDevelop3', + '5' : 'KDevelop3 - Unix Makefiles', +} + +darwin_generators = { + '1' : 'Xcode', + '2' : 'Unix Makefiles', + '3' : 'CodeBlocks - Unix Makefiles', + '4' : 'Eclipse CDT4 - Unix Makefiles', + '5' : 'KDevelop3', + '6' : 'KDevelop3 - Unix Makefiles', +} + +def config_filepath(): + return '%s/%s' % (bin_dir, config_filename) + +def sln_filepath(): + return '%s\%s' % (bin_dir, sln_filename) + +def xcodeproj_filepath(): + return '%s/%s' % (bin_dir, xcodeproj_filename) + +def usage(argv): + app = sys.argv[0] + print ('Usage: %s [command]\n' + '\n' + 'Replace [command] with one of:\n' + ' about Show information about this script\n' + ' setup Runs the initial setup for this script\n' + ' configure Runs cmake (generates project files)\n' + ' open Attempts to open the generated project file\n' + ' build Builds using the platform build chain\n' + ' clean Cleans using the platform build chain\n' + ' destroy Destroy all temporary files (bin and build)\n' + ' kill Kills all synergy processes (run as admin)\n' + ' update Updates the source code from repository\n' + ' revision Display the current source code revision\n' + ' package Create a distribution package (e.g. tar.gz)\n' + ' install Installs the program\n' + ' hammer Golden hammer (config, build, package)\n' + ' reformat Reformat .cpp and .h files using AStyle\n' + ' usage Shows the help screen\n' + '\n' + 'Example: %s configure' + ) % (app, app) + +def configure(argv, generator = None): + + err = configure_internal(generator) + + if err == 0: + print ('Configure complete!\n\n' + 'Open project now: %s open\n' + 'Command line build: %s build' + ) % (this_cmd, this_cmd) + return True + else: + return False + +# TODO: handle svn not installed +# TODO: implement for other platforms +def persist_cmake(): + if sys.platform == 'win32': + + version = '2.8.0' + found_cmd = '' + for test_cmd in (cmake_cmd, r'tool\cmake\bin\%s' % cmake_cmd): + print 'Testing for CMake version %s at `%s`...' % (version, test_cmd) + p = subprocess.Popen([test_cmd, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + stdout, stderr = p.communicate() + if p.returncode == 0 and stdout == 'cmake version %s\r\n' % version: + # found one that works, hurrah! + print 'Found valid CMake version' + found_cmd = test_cmd + # HACK: gotta go out so just hacking this for now + if found_cmd == r'tool\cmake\bin\%s' % cmake_cmd: + found_cmd = r'..\tool\cmake\bin\%s' % cmake_cmd + break + + if not found_cmd: + msg = 'CMake 2.8.0 not installed. Auto download now? [Y/n]' + print msg, + + yn = raw_input() + if yn in ['n', 'N']: + print 'Cannot continue without CMake, exiting.' + sys.exit(1) + else: + if not os.path.exists('tool'): + os.mkdir('tool') + os.system(r'svn checkout https://synergy-plus.googlecode.com/svn/tools/win/cmake tool\cmake') + found_cmd = r'tool\cmake\bin\%s' % found_cmd + + return found_cmd + else: + return cmake_cmd + +def configure_internal(generator = None): + + ensure_setup_latest(generator) + _cmake_cmd = persist_cmake() + generator = get_generator() + + if generator != '': + cmake_args = '%s -G "%s"' % (source_dir, generator) + else: + cmake_args = source_dir + + cmake_cmd_string = '%s %s' % (_cmake_cmd, cmake_args) + + print "Configuring with CMake (%s)..." % cmake_cmd_string + + # Run from build dir so we have an out-of-source build. + try_chdir(bin_dir) + err = os.system(cmake_cmd_string) + restore_chdir() + + if err != 0: + print 'CMake encountered error:', err + else: + set_conf_run() + + return err; + +def build(mode): + + ensure_setup_latest() + + if not has_conf_run(): + if configure_internal() != 0: + return False + + generator = get_generator() + + if generator == "Unix Makefiles": + + print 'Building with GNU Make...' + try_chdir(bin_dir) + err = os.system(make_cmd) + restore_chdir() + + if err == 0: + return True + else: + print 'GNU Make failed:', err + return False + + elif generator.startswith('Visual Studio 10') or generator.startswith('Visual Studio 8') or generator.startswith('Visual Studio 9'): + + ret = run_vcbuild(generator, mode) + + if ret == 0: + return True + else: + print 'VCBuild failed:', ret + return False + + elif generator == 'Xcode': + + print 'Building with Xcode...' + try_chdir(bin_dir) + err = os.system(xcodebuild_cmd) + restore_chdir() + + if err == 0: + return True + else: + print 'Xcode failed:', err + return False + + else: + print 'Not supported with generator:',generator + return False + +def clean(mode): + + generator = get_generator() + + if generator == "Unix Makefiles": + + print 'Cleaning with GNU Make...' + try_chdir(bin_dir) + err = os.system(make_cmd + ' clean') + restore_chdir() + + if err == 0: + return True + else: + print 'GNU Make failed: %s' % err + return False + + elif generator.startswith('Visual Studio 10'): + + ret = run_vcbuild(generator, mode, '/target:clean') + + if ret == 0: + return True + else: + print 'VCBuild failed:', ret + return False + + elif generator.startswith('Visual Studio 8') or generator.startswith('Visual Studio 9'): + + ret = run_vcbuild(generator, mode, '/clean') + + if ret == 0: + return True + else: + print 'VCBuild failed:', ret + return False + + elif generator == 'Xcode': + + print 'Cleaning with Xcode...' + try_chdir(bin_dir) + err = os.system(xcodebuild_cmd + ' clean') + restore_chdir() + + if err == 0: + return True + else: + print 'XCode failed:', err + return False + + else: + print 'clean: Not supported on platform:',sys.platform + return False + +def open_project(): + generator = get_generator() + if generator.startswith('Visual Studio'): + open_project_internal(sln_filepath()) + return True + elif generator.startswith('Xcode'): + open_project_internal(xcodeproj_filepath(), 'open') + return True + else: + print 'Not supported with generator:',generator + return False + +def update(): + print "Running Subversion update..." + os.system('svn update') + +def revision(): + # While this doesn't print out the revision specifically, it will do. + os.system('svn info') + +def destroy(argv): + msg = "Are you sure you want to remove the ./bin/ directory? [y/N]" + print msg, + + yn = raw_input() + if yn in ['y', 'Y']: + try: + shutil.rmtree(bin_dir) + except: + print "Warning: Could not remove ./bin/ directory." + +def kill(): + if sys.platform == 'win32': + os.system('taskkill /F /FI "IMAGENAME eq synergy*"') + return True + else: + print 'kill: Error: Command not implemented for current platform' + return False + +def package(type): + + # Package is supported by default. + package_unsupported = False + + if type == None: + package_usage() + elif type == 'src': + if sys.platform in ['linux2', 'darwin']: + package_tgz() + else: + package_unsupported = True + elif type == 'rpm': + if sys.platform == 'linux2': + package_rpm() + else: + package_unsupported = True + elif type == 'deb': + if sys.platform == 'linux2': + package_deb() + else: + package_unsupported = True + elif type == 'win': + if sys.platform == 'win32': + package_win() + else: + package_unsupported = True + elif type == 'mac': + if sys.platform == 'darwin': + package_mac() + else: + package_unsupported = True + else: + print 'Not yet implemented: package %s' % type + + if package_unsupported: + print ('Package type, %s is not ' + 'supported for platform, %s') % (type, sys.platform) + +def package_tgz(): + try_chdir(bin_dir) + os.system('make package_source') + restore_chdir() + +def package_rpm(): + try_chdir(bin_dir) + os.system('cpack -G RPM') + restore_chdir() + +def package_deb(): + try_chdir(bin_dir) + os.system('cpack -G DEB') + restore_chdir() + +def package_win(): + try_chdir(bin_dir) + os.system('cpack -G NSIS') + restore_chdir() + +def package_mac(): + try_chdir(bin_dir) + os.system('cpack -G PackageMaker') + restore_chdir() + +def package_usage(): + print ('Usage: %s package [package-type]\n' + '\n' + 'Replace [package-type] with one of:\n' + ' src .tar.gz source (Posix only)\n' + ' rpm .rpm package (Red Hat)\n' + ' deb .deb paclage (Debian)\n' + ' win .exe installer (Windows)\n' + ' mac .dmg package (Mac OS X)\n' + '\n' + 'Example: %s package src-tgz') % (this_cmd, this_cmd) + +def about(): + print ('Help Me script, from the Synergy+ project.\n' + '%s\n' + '\n' + 'For help, run: %s help') % (website_url, this_cmd) + +# +# Important! +# +# From here on, it's just internal stuff, no need to +# change anything here unless adding new commands, or +# editing the way the script works. +# + + + +def try_chdir(dir): + + # Ensure temp build dir exists. + if not os.path.exists(dir): + os.mkdir(dir) + + global prevdir + prevdir = os.path.abspath(os.curdir) + + # It will exist by this point, so it's safe to chdir. + os.chdir(dir) + +def restore_chdir(): + global prevdir + os.chdir(prevdir) + +def open_project_internal(project_filename, application = ''): + + if not os.path.exists(project_filename): + print 'Project file (%s) not found, run hm conf first.' % project_filename + return False + else: + path = project_filename + if application != '': + path = application + ' ' + path + os.system(path) + return True + +def setup(generator = None): + print "Running setup..." + + # If no generator specified, prompt the user. + if generator == None: + if sys.platform == 'win32': + generator = setup_generator_get(win32_generators) + elif sys.platform in ['linux2', 'sunos5', 'freebsd7']: + generator = setup_generator_get(unix_generators) + elif sys.platform == 'darwin': + generator = setup_generator_get(darwin_generators) + else: + raise Exception('Unsupported platform: ' + sys.platform) + + # Create build dir, since config file resides there. + if not os.path.exists(bin_dir): + os.mkdir(bin_dir) + + if os.path.exists(config_filepath()): + config = ConfigParser.ConfigParser() + config.read(config_filepath()) + else: + config = ConfigParser.ConfigParser() + + if not config.has_section('hm'): + config.add_section('hm') + + if not config.has_section('cmake'): + config.add_section('cmake') + + config.set('hm', 'setup_version', setup_version) + config.set('cmake', 'generator', generator) + + write_config(config) + + cmakecache_filename = '%s/CMakeCache.txt' % bin_dir + if os.path.exists(cmakecache_filename): + print "Removing %s, since generator changed." % cmakecache_filename + os.remove(cmakecache_filename) + + print "\nSetup complete." + +def write_config(config): + configfile = open(config_filepath(), 'wb') + config.write(configfile) + +def get_generator(): + config = ConfigParser.RawConfigParser() + config.read(config_filepath()) + return config.get('cmake', 'generator') + +def has_setup_version(version): + if os.path.exists(config_filepath()): + config = ConfigParser.RawConfigParser() + config.read(config_filepath()) + + try: + return config.getint('hm', 'setup_version') >= version + except: + return False + else: + return False + +def has_conf_run(): + if has_setup_version(2): + config = ConfigParser.RawConfigParser() + config.read(config_filepath()) + try: + return config.getboolean('hm', 'has_conf_run') + except: + return False + else: + return False + +def set_conf_run(): + if has_setup_version(3): + config = ConfigParser.RawConfigParser() + config.read(config_filepath()) + config.set('hm', 'has_conf_run', True) + write_config(config) + else: + raise Exception("User does not have correct setup version.") + +def setup_generator_get(generators): + + generator_options = '' + generators_sorted = sorted(generators.iteritems(), key=lambda t: int(t[0])) + + for id, generator in generators_sorted: + generator_options += '\n ' + id + ': ' + generator + + print ('\nChoose a CMake generator:%s' + ) % generator_options + + return setup_generator_prompt(generators) + +def setup_generator_prompt(generators): + + prompt = 'Enter a number:' + print prompt, + + generator_id = raw_input() + + if generator_id in generators: + print 'Selected generator:', generators[generator_id] + else: + print 'Invalid number, try again.' + setup_generator_prompt(generators) + + return generators[generator_id] + +def get_vcvarsall(generator): + import platform + + # os_bits should be loaded with '32bit' or '64bit' + (os_bits, other) = platform.architecture() + + # visual studio is a 32-bit app, so when we're on 64-bit, we need to check the WoW dungeon + if os_bits == '64bit': + key_name = r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7' + else: + key_name = r'SOFTWARE\Microsoft\VisualStudio\SxS\VC7' + + key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key_name) + if generator.startswith('Visual Studio 8'): + value,type = _winreg.QueryValueEx(key, '8.0') + elif generator.startswith('Visual Studio 9'): + value,type = _winreg.QueryValueEx(key, '9.0') + elif generator.startswith('Visual Studio 10'): + value,type = _winreg.QueryValueEx(key, '10.0') + else: + raise Exception('Cannot determin vcvarsall.bat location for: ' + generator) + + # not sure why, but the value on 64-bit differs slightly to the original + if os_bits == '64bit': + path = value + r'vc\vcvarsall.bat' + else: + path = value + r'vcvarsall.bat' + + if not os.path.exists(path): + raise Exception("'%s' not found." % path) + return path + +def run_vcbuild(generator, mode, args=''): + import platform + + # os_bits should be loaded with '32bit' or '64bit' + (os_bits, other) = platform.architecture() + # Now we choose the parameters bases on OS 32/64 and our target 32/64 + # http://msdn.microsoft.com/en-us/library/x4d2c09s%28VS.80%29.aspx + + # valid options are only: ia64 amd64 x86_amd64 x86_ia64 + # but calling vcvarsall.bat does not garantee that it will work + # ret code from vcvarsall.bat is always 0 so the only way of knowing that I worked is by analysing the text output + # ms bugg: install VS9, FeaturePack, VS9SP1 and you'll obtain a vcvarsall.bat that fails. + if generator.find('Win64') != -1: + # target = 64bit + if os_bits == '32bit': + vcvars_platform = 'x86_amd64' # 32bit OS building 64bit app + else: + vcvars_platform = 'amd64' # 64bit OS building 64bit app + config_platform = 'x64' + else: # target = 32bit + vcvars_platform = 'x86' # 32/64bit OS building 32bit app + config_platform = 'Win32' + if mode == 'release': + config = 'Release' + else: + config = 'Debug' + + if generator.startswith('Visual Studio 10'): + cmd = ('@echo off\n' + 'call "%s" %s \n' + 'msbuild /nologo %s /p:Configuration="%s" /p:Platform="%s" "%s"' + ) % (get_vcvarsall(generator), vcvars_platform, args, config, config_platform, sln_filepath()) + else: + config = config + '|' + config_platform + cmd = ('@echo off\n' + 'call "%s" %s \n' + 'vcbuild /nologo %s "%s" "%s"' + ) % (get_vcvarsall(generator), vcvars_platform, args, sln_filepath(), config) + print cmd + # Generate a batch file, since we can't use environment variables directly. + temp_bat = bin_dir + r'\vcbuild.bat' + file = open(temp_bat, 'w') + file.write(cmd) + file.close() + + return os.system(temp_bat) + +def ensure_setup_latest(generator = None): + if not has_setup_version(setup_version): + setup(generator) + +class HammerBuild: + generator = None + target_dir = None + + def __init__(self, _generator, _target_dir): + self.generator = _generator + self.target_dir = _target_dir + + def run(self): + global bin_dir + bin_dir = self.target_dir + configure(self.generator) + build('debug') + build('release') + +def hammer(): + + hammer_builds = [] + if sys.platform == 'win32': + hammer_builds += [ + HammerBuild('Visual Studio 9 2008', 'bin32'), + HammerBuild('Visual Studio 9 2008 Win64', 'bin64')] + elif sys.platform in ['linux2', 'sunos5', 'freebsd7']: + hammer_builds += [ + HammerBuild('Unix Makefiles', 'bin')] + elif sys.platform == 'darwin': + hammer_builds += [ + HammerBuild('Xcode', 'bin')] + + for hb in hammer_builds: + hb.run() + + package_types = [] + if sys.platform == 'win32': + package_types += ['win'] + elif sys.platform == 'linux2': + package_types += ['src', 'rpm', 'deb'] + elif sys.platform == 'darwin': + package_types += ['mac'] + + for pt in package_types: + package(pt) + +def reformat(): + # TODO: error handling + os.system( + r'tool\astyle\AStyle.exe ' + '--quiet --suffix=none --style=java --indent=force-tab=4 --recursive ' + 'lib/*.cpp lib/*.h cmd/*.cpp cmd/*.h')