AMBuildScript
author Don <datal30mb@users.sourceforge.net>
Fri Oct 14 11:28:53 2011 -0400 (2011-10-14)
changeset 3411 0a2e40a50757
parent 3388 cbee39527756
child 3457 387b27fb575b
permissions -rw-r--r--
Added native to clientprefs to alter data on a disconnected player (bug 3882, r=pred).
     1 # vim: set ts=2 sw=2 tw=99 noet ft=python:
     2 import os
     3 import sys
     4 from ambuild.command import SymlinkCommand
     5 
     6 class SM:
     7 	def __init__(self):
     8 		self.compiler = Cpp.Compiler()
     9 
    10 		#Build SDK info
    11 		self.possibleSdks = { }
    12 		self.possibleSdks['ep1'] =   {'sdk': 'HL2SDK',          'ext': '1.ep1',   'def': '1',
    13 		                         'name': 'EPISODEONE',     'platform': ['windows', 'linux']}
    14 		self.possibleSdks['ep2'] =   {'sdk': 'HL2SDKOB',        'ext': '2.ep2',   'def': '3',
    15 		                         'name': 'ORANGEBOX',      'platform': ['windows', 'linux']}
    16 		self.possibleSdks['ep2v'] =  {'sdk': 'HL2SDKOBVALVE',   'ext': '2.ep2v',  'def': '6',
    17 		                         'name': 'ORANGEBOXVALVE', 'platform': ['windows', 'linux', 'darwin']}
    18 		self.possibleSdks['l4d'] =   {'sdk': 'HL2SDKL4D',       'ext': '2.l4d',   'def': '7',
    19 		                         'name': 'LEFT4DEAD',      'platform': ['windows', 'linux', 'darwin']}
    20 		self.possibleSdks['l4d2'] =  {'sdk': 'HL2SDKL4D2',      'ext': '2.l4d2',  'def': '8',
    21 		                         'name': 'LEFT4DEAD2',     'platform': ['windows', 'linux', 'darwin']}
    22 		self.possibleSdks['darkm'] = {'sdk': 'HL2SDK-DARKM',    'ext': '2.darkm', 'def': '2',
    23 		                         'name': 'DARKMESSIAH',    'platform': ['windows']}
    24 		self.possibleSdks['swarm'] = {'sdk': 'HL2SDK-SWARM',    'ext': '2.swarm', 'def': '9',
    25 		                         'name': 'ALIENSWARM',     'platform': ['windows']}
    26 		self.possibleSdks['bgt'] =   {'sdk': 'HL2SDK-BGT',      'ext': '2.bgt', 'def': '4',
    27 		                         'name': 'BLOODYGOODTIME', 'platform': ['windows']}
    28 		self.possibleSdks['eye'] =   {'sdk': 'HL2SDK-EYE',      'ext': '2.eye', 'def': '5',
    29 		                         'name': 'EYE', 'platform': ['windows']}
    30 		
    31 		self.sdkInfo = { }
    32 
    33 		if AMBuild.mode == 'config':
    34 			#Detect compilers
    35 			self.compiler.DetectAll(AMBuild)
    36 
    37 			#Detect variables
    38 			envvars = { 'MMSOURCE18':    'mmsource-1.8',
    39 									'HL2SDKOBVALVE': 'hl2sdk-ob-valve',
    40 									'HL2SDKL4D':     'hl2sdk-l4d',
    41 									'HL2SDKL4D2':    'hl2sdk-l4d2',
    42 									'MYSQL5':        'mysql-5.0'
    43 			}
    44 
    45 			if AMBuild.target['platform'] != 'darwin':
    46 				envvars['HL2SDK'] = 'hl2sdk'
    47 				envvars['HL2SDKOB'] = 'hl2sdk-ob'
    48 
    49 			#Dark Messiah is Windows-only
    50 			if AMBuild.target['platform'] == 'windows':
    51 				envvars['HL2SDK-DARKM'] = 'hl2sdk-darkm'
    52 				envvars['HL2SDK-SWARM'] = 'hl2sdk-swarm'
    53 				envvars['HL2SDK-BGT']   = 'hl2sdk-bgt'
    54 				envvars['HL2SDK-EYE']   = 'hl2sdk-eye'
    55 
    56 			# Finds if a dict with `key` set to `value` is present on the dict of dicts `dictionary`
    57 			def findDictByKey(dictionary, key, value):
    58 				for index in dictionary:
    59 					elem = dictionary[index]
    60 					if elem[key] == value:
    61 						return (elem, index)
    62 				return None
    63 
    64 			for i in envvars:
    65 				if i in os.environ:
    66 					path = os.environ[i]
    67 					if not os.path.isdir(path):
    68 						raise Exception('Path for {0} was not found: {1}'.format(i, path))
    69 					elif i.startswith('HL2SDK'):
    70 						(info, sdk) = findDictByKey(self.possibleSdks, 'sdk', i)
    71 						self.sdkInfo[sdk] = info
    72 				else:
    73 					head = os.getcwd()
    74 					oldhead = None
    75 					while head != None and head != oldhead:
    76 						path = os.path.join(head, envvars[i])
    77 						if os.path.isdir(path):
    78 							break
    79 						oldhead = head
    80 						head, tail = os.path.split(head)
    81 					if i.startswith('HL2SDK'):
    82 						(info, sdk) = findDictByKey(self.possibleSdks, 'sdk', i)
    83 						self.sdkInfo[sdk] = info	
    84 					elif head == None or head == oldhead:
    85 						raise Exception('Could not find a valid path for {0}'.format(i))
    86 				AMBuild.cache.CacheVariable(i, path)
    87 
    88 			if len(self.sdkInfo) < 1:
    89 				raise Exception('At least one SDK must be available.')
    90 				
    91 			AMBuild.cache.CacheVariable('sdkInfo', self.sdkInfo)
    92 
    93 			#Set up defines
    94 			cxx = self.compiler.cxx
    95 			if isinstance(cxx, Cpp.CompatGCC):
    96 				if isinstance(cxx, Cpp.GCC):
    97 					self.vendor = 'gcc'
    98 				elif isinstance(cxx, Cpp.Clang):
    99 					self.vendor = 'clang'
   100 				self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
   101 				self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
   102 				self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
   103 				self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
   104 				self.compiler.AddToListVar('CFLAGS', '-pipe')
   105 				self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
   106 				if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang':
   107 					self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
   108 					self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
   109 				self.compiler.AddToListVar('CFLAGS', '-Wall')
   110 				self.compiler.AddToListVar('CFLAGS', '-Werror')
   111 				self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
   112 				self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
   113 				self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
   114 				self.compiler.AddToListVar('CFLAGS', '-msse')
   115 				self.compiler.AddToListVar('CFLAGS', '-m32')
   116 				self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
   117 				self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
   118 				self.compiler.AddToListVar('CXXFLAGS', '-fno-rtti')
   119 				self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
   120 				self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
   121 				self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
   122 				self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
   123 				self.compiler.AddToListVar('CDEFINES', 'GNUC')
   124 				if self.vendor == 'gcc':
   125 					self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
   126 			elif isinstance(cxx, Cpp.MSVC):
   127 				self.vendor = 'msvc'
   128 				if AMBuild.options.debug == '1':
   129 					self.compiler.AddToListVar('CFLAGS', '/MTd')
   130 					self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
   131 				else:
   132 					self.compiler.AddToListVar('CFLAGS', '/MT')
   133 				self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
   134 				self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
   135 				self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
   136 				self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
   137 				self.compiler.AddToListVar('CXXFLAGS', '/GR-')
   138 				self.compiler.AddToListVar('CFLAGS', '/W3')
   139 				self.compiler.AddToListVar('CFLAGS', '/nologo')
   140 				self.compiler.AddToListVar('CFLAGS', '/Zi')
   141 				self.compiler.AddToListVar('CXXFLAGS', '/TP')
   142 				self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
   143 				self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
   144 				self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
   145 				self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
   146 				self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
   147 				self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
   148 				self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
   149 				self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
   150 				self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
   151 				self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
   152 				self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
   153 				self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
   154 				self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
   155 				self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
   156 				self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
   157 
   158 			#Optimization
   159 			if AMBuild.options.opt == '1':
   160 				self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
   161 				if self.vendor == 'gcc' or self.vendor == 'clang':
   162 					self.compiler.AddToListVar('CFLAGS', '-O3')
   163 				elif self.vendor == 'msvc':
   164 					self.compiler.AddToListVar('CFLAGS', '/Ox')
   165 					self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
   166 					self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
   167 
   168 			#Debugging
   169 			if AMBuild.options.debug == '1':
   170 				self.compiler.AddToListVar('CDEFINES', 'DEBUG')
   171 				self.compiler.AddToListVar('CDEFINES', '_DEBUG')
   172 				if self.vendor == 'gcc' or self.vendor == 'clang':
   173 					self.compiler.AddToListVar('CFLAGS', '-g3')
   174 				elif self.vendor == 'msvc':
   175 					self.compiler.AddToListVar('CFLAGS', '/Od')
   176 					self.compiler.AddToListVar('CFLAGS', '/RTC1')
   177 
   178 			#Platform-specifics
   179 			if AMBuild.target['platform'] == 'linux':
   180 				self.compiler.AddToListVar('CDEFINES', '_LINUX')
   181 				if self.vendor == 'gcc':
   182 					self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
   183 				if self.vendor == 'clang':
   184 					self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
   185 			elif AMBuild.target['platform'] == 'darwin':
   186 				self.compiler.AddToListVar('CFLAGS', ['-isysroot',
   187 				                                      '/Developer/SDKs/MacOSX10.5.sdk'])
   188 				self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
   189 				self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
   190 				self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
   191 
   192 				# For OS X dylib versioning
   193 				import re
   194 				productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
   195 				productContents = productFile.read()
   196 				productFile.close()
   197 				m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
   198 				if m == None:
   199 					self.version = '1.0.0'
   200 				else:
   201 					major, minor, release = m.groups()
   202 					self.version = '{0}.{1}.{2}'.format(major, minor, release)
   203 				AMBuild.cache.CacheVariable('version', self.version)
   204 			elif AMBuild.target['platform'] == 'windows':
   205 				self.compiler.AddToListVar('CDEFINES', 'WIN32')
   206 				self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
   207 
   208 			#Finish up
   209 			self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
   210 			self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
   211 			self.compiler.AddToListVar('CINCLUDES',
   212 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   213 			self.compiler.ToConfig(AMBuild, 'compiler')
   214 			AMBuild.cache.CacheVariable('vendor', self.vendor)
   215 			self.targetMap = { }
   216 			AMBuild.cache.CacheVariable('targetMap', self.targetMap)
   217 		else:
   218 			self.sdkInfo = AMBuild.cache['sdkInfo']
   219 			self.compiler.FromConfig(AMBuild, 'compiler')
   220 			self.targetMap = AMBuild.cache['targetMap']
   221 
   222 		if AMBuild.target['platform'] == 'windows':
   223 			self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
   224 			self.compiler.AddToListVar('RCINCLUDES',
   225 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   226 		self.mmsPath = AMBuild.cache['MMSOURCE18']
   227 
   228 	def DefaultCompiler(self):
   229 		return self.compiler.Clone()
   230 
   231 	def JobMatters(self, jobname):
   232 		file = sys._getframe().f_code.co_filename
   233 		if AMBuild.mode == 'config':
   234 			self.targetMap[jobname] = file
   235 			return True
   236 		if len(AMBuild.args) == 0:
   237 			return True
   238 		if not jobname in AMBuild.args:
   239 			return False
   240 
   241 	def DefaultExtCompiler(self, path):
   242 		compiler = self.DefaultCompiler()
   243 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
   244 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
   245 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
   246 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
   247 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
   248 		return compiler
   249 
   250 	def AutoVersion(self, folder, binary):
   251 		if AMBuild.target['platform'] == 'windows':
   252 			env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
   253 			binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
   254 		elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
   255 			binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
   256 			binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
   257 		else:
   258 			return
   259 
   260 	def PreSetupHL2Job(self, job, builder, sdk):
   261 		info = self.sdkInfo[sdk]
   262 		sdkPath = AMBuild.cache[info['sdk']]
   263 		if AMBuild.target['platform'] == 'linux':
   264 			if sdk == 'ep1':
   265 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   266 			else:
   267 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   268 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   269 			if sdk in ['ep2v', 'l4d', 'l4d2']:
   270 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']:
   271 					link = os.path.join(workFolder, i)
   272 					target = os.path.join(staticLibs, i)
   273 					try:
   274 						os.lstat(link)
   275 					except:
   276 						job.AddCommand(SymlinkCommand(link, target))
   277 			else:
   278 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']:
   279 					link = os.path.join(workFolder, i)
   280 					target = os.path.join(staticLibs, i)
   281 					try:
   282 						os.lstat(link)
   283 					except:
   284 						job.AddCommand(SymlinkCommand(link, target))
   285 		elif AMBuild.target['platform'] == 'darwin':
   286 			staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   287 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   288 			for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']:
   289 				link = os.path.join(workFolder, i)
   290 				target = os.path.join(staticLibs, i)
   291 				try:
   292 					os.lstat(link)
   293 				except:
   294 					job.AddCommand(SymlinkCommand(link, target))
   295 		elif AMBuild.target['platform'] == 'windows':
   296 			libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
   297 			if sdk == 'swarm':
   298 				libs.append('interfaces')
   299 			for lib in libs:
   300 				libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
   301 				builder.RebuildIfNewer(libPath)
   302 				builder['POSTLINKFLAGS'].append(libPath)
   303 
   304 	def PostSetupHL2Job(self, job, builder, sdk):
   305 		if AMBuild.target['platform'] in ['linux', 'darwin']:
   306 			builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
   307 
   308 	def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
   309 		compiler = self.DefaultExtCompiler(path)
   310 
   311 		mms = 'core'
   312 		if sdk == 'ep1':
   313 			mms += oldMms
   314 
   315 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
   316 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
   317 
   318 		info = self.possibleSdks
   319 		compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
   320 
   321 		paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
   322 						 ['public', 'tier0'], ['public', 'tier1']]
   323 		if sdk == 'ep1' or sdk == 'darkm':
   324 			paths.append(['public', 'dlls'])
   325 			paths.append(['game_shared'])
   326 		else:
   327 			paths.append(['public', 'game', 'server'])
   328 			paths.append(['public', 'toolframework'])
   329 			paths.append(['game', 'shared'])
   330 			paths.append(['common'])
   331 
   332 		info = self.sdkInfo[sdk]
   333 		sdkPath = AMBuild.cache[info['sdk']]
   334 
   335 		compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
   336 
   337 		if sdk == 'swarm' and AMBuild.target['platform'] == 'windows':
   338 			compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
   339 
   340 		if sdk == 'ep1':
   341 			if AMBuild.target['platform'] == 'linux':
   342 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   343 		else:
   344 			if AMBuild.target['platform'] == 'linux':
   345 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   346 			elif AMBuild.target['platform'] == 'darwin':
   347 				staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   348 
   349 		for i in paths:
   350 			compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
   351 
   352 		if not noLink:
   353 			if AMBuild.target['platform'] == 'linux':
   354 				compiler['POSTLINKFLAGS'][0:0] = ['-lm']
   355 				if sdk in ['ep2v', 'l4d', 'l4d2']:
   356 					compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
   357 					compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
   358 				else:
   359 					compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
   360 					compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
   361 			elif AMBuild.target['platform'] == 'darwin':
   362 				compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
   363 				compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
   364 
   365 		return compiler
   366 
   367 sm = SM()
   368 globals = {
   369 	'SM': sm
   370 }
   371 
   372 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
   373 
   374 FileList = [
   375 		['loader', 'AMBuilder'],
   376 		['core', 'AMBuilder'],
   377 		['core', 'logic', 'AMBuilder'],
   378 		['extensions', 'bintools', 'AMBuilder'],
   379 		['extensions', 'clientprefs', 'AMBuilder'],
   380 		['extensions', 'cstrike', 'AMBuilder'],
   381 		['extensions', 'curl', 'AMBuilder'],
   382 		['extensions', 'geoip', 'AMBuilder'],
   383 		['extensions', 'mysql', 'AMBuilder'],
   384 		['extensions', 'sdktools', 'AMBuilder'],
   385 		['extensions', 'topmenus', 'AMBuilder'],
   386 		['extensions', 'updater', 'AMBuilder'],
   387 		['extensions', 'sqlite', 'AMBuilder'],
   388 		['extensions', 'regex', 'AMBuilder'],
   389 		['extensions', 'tf2', 'AMBuilder'],
   390 		['sourcepawn', 'jit', 'AMBuilder'],
   391 		['sourcepawn', 'compiler', 'AMBuilder'],
   392 		['plugins', 'AMBuilder'],
   393 		['tools', 'buildbot', 'PackageScript']
   394 	]
   395 
   396 for parts in FileList:
   397 	AMBuild.Include(os.path.join(*parts), globals)
   398