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