AMBuildScript
author Tony <aangione@gmail.com>
Sun May 27 01:51:06 2012 +0100 (2012-05-27)
changeset 3510 c72cfe0c6a57
parent 3503 08b1578a8363
child 3515 c14c14e06cc1
permissions -rw-r--r--
Adding missing SetMenuNoVoteButton native declaration (bug 4522, r=asherkin).
     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 						if head != None and head != oldhead:
    83 							(info, sdk) = findDictByKey(self.possibleSdks, 'sdk', i)
    84 							self.sdkInfo[sdk] = info
    85 					elif head == None or head == oldhead:
    86 						raise Exception('Could not find a valid path for {0}'.format(i))
    87 				AMBuild.cache.CacheVariable(i, path)
    88 
    89 			if len(self.sdkInfo) < 1:
    90 				raise Exception('At least one SDK must be available.')
    91 				
    92 			AMBuild.cache.CacheVariable('sdkInfo', self.sdkInfo)
    93 
    94 			#Set up defines
    95 			cxx = self.compiler.cxx
    96 			if isinstance(cxx, Cpp.CompatGCC):
    97 				if isinstance(cxx, Cpp.GCC):
    98 					self.vendor = 'gcc'
    99 				elif isinstance(cxx, Cpp.Clang):
   100 					self.vendor = 'clang'
   101 				self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
   102 				self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
   103 				self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
   104 				self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
   105 				self.compiler.AddToListVar('CFLAGS', '-pipe')
   106 				self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
   107 				if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang':
   108 					self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
   109 					self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
   110 				self.compiler.AddToListVar('CFLAGS', '-Wall')
   111 				self.compiler.AddToListVar('CFLAGS', '-Werror')
   112 				self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
   113 				self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
   114 				self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
   115 				self.compiler.AddToListVar('CFLAGS', '-msse')
   116 				self.compiler.AddToListVar('CFLAGS', '-m32')
   117 				self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
   118 				self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
   119 				self.compiler.AddToListVar('CXXFLAGS', '-fno-rtti')
   120 				self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
   121 				self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
   122 				self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
   123 				if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \
   124 						(self.vendor == 'clang' and cxx.majorVersion >= 3):
   125 					self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor')
   126 				self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
   127 				self.compiler.AddToListVar('CDEFINES', 'GNUC')
   128 				if self.vendor == 'gcc':
   129 					self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
   130 			elif isinstance(cxx, Cpp.MSVC):
   131 				self.vendor = 'msvc'
   132 				if AMBuild.options.debug == '1':
   133 					self.compiler.AddToListVar('CFLAGS', '/MTd')
   134 					self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
   135 				else:
   136 					self.compiler.AddToListVar('CFLAGS', '/MT')
   137 				self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
   138 				self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
   139 				self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
   140 				self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
   141 				self.compiler.AddToListVar('CXXFLAGS', '/GR-')
   142 				self.compiler.AddToListVar('CFLAGS', '/W3')
   143 				self.compiler.AddToListVar('CFLAGS', '/nologo')
   144 				self.compiler.AddToListVar('CFLAGS', '/Zi')
   145 				self.compiler.AddToListVar('CXXFLAGS', '/TP')
   146 				self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
   147 				self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
   148 				self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
   149 				self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
   150 				self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
   151 				self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
   152 				self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
   153 				self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
   154 				self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
   155 				self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
   156 				self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
   157 				self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
   158 				self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
   159 				self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
   160 				self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
   161 
   162 			#Optimization
   163 			if AMBuild.options.opt == '1':
   164 				self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
   165 				if self.vendor == 'gcc' or self.vendor == 'clang':
   166 					self.compiler.AddToListVar('CFLAGS', '-O3')
   167 				elif self.vendor == 'msvc':
   168 					self.compiler.AddToListVar('CFLAGS', '/Ox')
   169 					self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
   170 					self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
   171 
   172 			#Debugging
   173 			if AMBuild.options.debug == '1':
   174 				self.compiler.AddToListVar('CDEFINES', 'DEBUG')
   175 				self.compiler.AddToListVar('CDEFINES', '_DEBUG')
   176 				if self.vendor == 'gcc' or self.vendor == 'clang':
   177 					self.compiler.AddToListVar('CFLAGS', '-g3')
   178 				elif self.vendor == 'msvc':
   179 					self.compiler.AddToListVar('CFLAGS', '/Od')
   180 					self.compiler.AddToListVar('CFLAGS', '/RTC1')
   181 
   182 			#Platform-specifics
   183 			if AMBuild.target['platform'] == 'linux':
   184 				self.compiler.AddToListVar('CDEFINES', '_LINUX')
   185 				if self.vendor == 'gcc':
   186 					self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
   187 				if self.vendor == 'clang':
   188 					self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
   189 			elif AMBuild.target['platform'] == 'darwin':
   190 				self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
   191 				self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
   192 				self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
   193 
   194 				# For OS X dylib versioning
   195 				import re
   196 				productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
   197 				productContents = productFile.read()
   198 				productFile.close()
   199 				m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
   200 				if m == None:
   201 					self.version = '1.0.0'
   202 				else:
   203 					major, minor, release = m.groups()
   204 					self.version = '{0}.{1}.{2}'.format(major, minor, release)
   205 				AMBuild.cache.CacheVariable('version', self.version)
   206 			elif AMBuild.target['platform'] == 'windows':
   207 				self.compiler.AddToListVar('CDEFINES', 'WIN32')
   208 				self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
   209 
   210 			#Finish up
   211 			self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
   212 			self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
   213 			self.compiler.AddToListVar('CINCLUDES',
   214 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   215 			self.compiler.ToConfig(AMBuild, 'compiler')
   216 			AMBuild.cache.CacheVariable('vendor', self.vendor)
   217 			self.targetMap = { }
   218 			AMBuild.cache.CacheVariable('targetMap', self.targetMap)
   219 		else:
   220 			self.sdkInfo = AMBuild.cache['sdkInfo']
   221 			self.compiler.FromConfig(AMBuild, 'compiler')
   222 			self.targetMap = AMBuild.cache['targetMap']
   223 
   224 		if AMBuild.target['platform'] == 'windows':
   225 			self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
   226 			self.compiler.AddToListVar('RCINCLUDES',
   227 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   228 		self.mmsPath = AMBuild.cache['MMSOURCE18']
   229 
   230 	def DefaultCompiler(self):
   231 		return self.compiler.Clone()
   232 
   233 	def JobMatters(self, jobname):
   234 		file = sys._getframe().f_code.co_filename
   235 		if AMBuild.mode == 'config':
   236 			self.targetMap[jobname] = file
   237 			return True
   238 		if len(AMBuild.args) == 0:
   239 			return True
   240 		if not jobname in AMBuild.args:
   241 			return False
   242 
   243 	def DefaultExtCompiler(self, path):
   244 		compiler = self.DefaultCompiler()
   245 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
   246 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
   247 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
   248 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
   249 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
   250 		return compiler
   251 
   252 	def AutoVersion(self, folder, binary):
   253 		if AMBuild.target['platform'] == 'windows':
   254 			env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
   255 			binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
   256 		elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
   257 			binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
   258 			binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
   259 		else:
   260 			return
   261 
   262 	def PreSetupHL2Job(self, job, builder, sdk):
   263 		info = self.sdkInfo[sdk]
   264 		sdkPath = AMBuild.cache[info['sdk']]
   265 		if AMBuild.target['platform'] == 'linux':
   266 			if sdk == 'ep1':
   267 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   268 			else:
   269 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   270 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   271 			if sdk in ['ep2v', 'l4d', 'l4d2']:
   272 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']:
   273 					link = os.path.join(workFolder, i)
   274 					target = os.path.join(staticLibs, i)
   275 					try:
   276 						os.lstat(link)
   277 					except:
   278 						job.AddCommand(SymlinkCommand(link, target))
   279 			else:
   280 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']:
   281 					link = os.path.join(workFolder, i)
   282 					target = os.path.join(staticLibs, i)
   283 					try:
   284 						os.lstat(link)
   285 					except:
   286 						job.AddCommand(SymlinkCommand(link, target))
   287 		elif AMBuild.target['platform'] == 'darwin':
   288 			staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   289 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   290 			for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']:
   291 				link = os.path.join(workFolder, i)
   292 				target = os.path.join(staticLibs, i)
   293 				try:
   294 					os.lstat(link)
   295 				except:
   296 					job.AddCommand(SymlinkCommand(link, target))
   297 		elif AMBuild.target['platform'] == 'windows':
   298 			libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
   299 			if sdk == 'swarm':
   300 				libs.append('interfaces')
   301 			for lib in libs:
   302 				libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
   303 				builder.RebuildIfNewer(libPath)
   304 				builder['POSTLINKFLAGS'].append(libPath)
   305 
   306 	def PostSetupHL2Job(self, job, builder, sdk):
   307 		if AMBuild.target['platform'] in ['linux', 'darwin']:
   308 			builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
   309 	
   310 	def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
   311 		compiler = self.DefaultExtCompiler(path)
   312 
   313 		mms = 'core'
   314 		if sdk == 'ep1':
   315 			mms += oldMms
   316 
   317 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
   318 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
   319 
   320 		info = self.possibleSdks
   321 		compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
   322 
   323 		paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
   324 						 ['public', 'tier0'], ['public', 'tier1']]
   325 		if sdk == 'ep1' or sdk == 'darkm':
   326 			paths.append(['public', 'dlls'])
   327 			paths.append(['game_shared'])
   328 		else:
   329 			paths.append(['public', 'game', 'server'])
   330 			paths.append(['public', 'toolframework'])
   331 			paths.append(['game', 'shared'])
   332 			paths.append(['common'])
   333 
   334 		info = self.sdkInfo[sdk]
   335 		sdkPath = AMBuild.cache[info['sdk']]
   336 
   337 		compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
   338 
   339 		if sdk == 'swarm' and AMBuild.target['platform'] == 'windows':
   340 			compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
   341 
   342 		if sdk == 'ep1':
   343 			if AMBuild.target['platform'] == 'linux':
   344 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   345 		else:
   346 			if AMBuild.target['platform'] == 'linux':
   347 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   348 			elif AMBuild.target['platform'] == 'darwin':
   349 				staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   350 
   351 		for i in paths:
   352 			compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
   353 
   354 		if not noLink:
   355 			if AMBuild.target['platform'] == 'linux':
   356 				compiler['POSTLINKFLAGS'][0:0] = ['-lm']
   357 				if sdk in ['ep2v', 'l4d', 'l4d2']:
   358 					compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
   359 					compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
   360 				else:
   361 					compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
   362 					compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
   363 			elif AMBuild.target['platform'] == 'darwin':
   364 				compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
   365 				compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
   366 
   367 		return compiler
   368 
   369 sm = SM()
   370 globals = {
   371 	'SM': sm
   372 }
   373 
   374 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
   375 
   376 FileList = [
   377 		['loader', 'AMBuilder'],
   378 		['core', 'AMBuilder'],
   379 		['core', 'logic', 'AMBuilder'],
   380 		['extensions', 'bintools', 'AMBuilder'],
   381 		['extensions', 'clientprefs', 'AMBuilder'],
   382 		['extensions', 'cstrike', 'AMBuilder'],
   383 		['extensions', 'curl', 'AMBuilder'],
   384 		['extensions', 'geoip', 'AMBuilder'],
   385 		['extensions', 'mysql', 'AMBuilder'],
   386 		['extensions', 'sdktools', 'AMBuilder'],
   387 		['extensions', 'topmenus', 'AMBuilder'],
   388 		['extensions', 'updater', 'AMBuilder'],
   389 		['extensions', 'sqlite', 'AMBuilder'],
   390 		['extensions', 'regex', 'AMBuilder'],
   391 		['extensions', 'tf2', 'AMBuilder'],
   392 		['sourcepawn', 'jit', 'AMBuilder'],
   393 		['sourcepawn', 'compiler', 'AMBuilder'],
   394 		['plugins', 'AMBuilder'],
   395 		['tools', 'buildbot', 'PackageScript'],
   396 		['tools', 'buildbot', 'BreakpadSymbols']
   397 	]
   398 
   399 for parts in FileList:
   400 	AMBuild.Include(os.path.join(*parts), globals)
   401