AMBuildScript
author Asher Baker <asherkin@gmail.com>
Mon Jul 18 03:23:03 2011 +0100 (2011-07-18)
changeset 3361 cafdb4df0e3f
parent 3297 89b6aa6e9d37
child 3373 c6463cdc2180
permissions -rw-r--r--
Added ServerCommandEx native to get the response when running a command (bug 3873, r=ds).
     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 				self.compiler.AddToListVar('CDEFINES', 'GNUC')
   101 				if self.vendor == 'gcc':
   102 					self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
   103 			elif isinstance(cxx, Cpp.MSVC):
   104 				self.vendor = 'msvc'
   105 				if AMBuild.options.debug == '1':
   106 					self.compiler.AddToListVar('CFLAGS', '/MTd')
   107 					self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
   108 				else:
   109 					self.compiler.AddToListVar('CFLAGS', '/MT')
   110 				self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
   111 				self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
   112 				self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
   113 				self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
   114 				self.compiler.AddToListVar('CXXFLAGS', '/GR-')
   115 				self.compiler.AddToListVar('CFLAGS', '/W3')
   116 				self.compiler.AddToListVar('CFLAGS', '/nologo')
   117 				self.compiler.AddToListVar('CFLAGS', '/Zi')
   118 				self.compiler.AddToListVar('CXXFLAGS', '/TP')
   119 				self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
   120 				self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
   121 				self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
   122 				self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
   123 				self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
   124 				self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
   125 				self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
   126 				self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
   127 				self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
   128 				self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
   129 				self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
   130 				self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
   131 				self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
   132 				self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
   133 				self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
   134 
   135 			#Optimization
   136 			if AMBuild.options.opt == '1':
   137 				self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
   138 				if self.vendor == 'gcc' or self.vendor == 'clang':
   139 					self.compiler.AddToListVar('CFLAGS', '-O3')
   140 				elif self.vendor == 'msvc':
   141 					self.compiler.AddToListVar('CFLAGS', '/Ox')
   142 					self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
   143 					self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
   144 
   145 			#Debugging
   146 			if AMBuild.options.debug == '1':
   147 				self.compiler.AddToListVar('CDEFINES', 'DEBUG')
   148 				self.compiler.AddToListVar('CDEFINES', '_DEBUG')
   149 				if self.vendor == 'gcc' or self.vendor == 'clang':
   150 					self.compiler.AddToListVar('CFLAGS', '-g3')
   151 				elif self.vendor == 'msvc':
   152 					self.compiler.AddToListVar('CFLAGS', '/Od')
   153 					self.compiler.AddToListVar('CFLAGS', '/RTC1')
   154 
   155 			#Platform-specifics
   156 			if AMBuild.target['platform'] == 'linux':
   157 				self.compiler.AddToListVar('CDEFINES', '_LINUX')
   158 				if self.vendor == 'gcc':
   159 					self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
   160 				if self.vendor == 'clang':
   161 					self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
   162 			elif AMBuild.target['platform'] == 'darwin':
   163 				self.compiler.AddToListVar('CFLAGS', ['-isysroot',
   164 				                                      '/Developer/SDKs/MacOSX10.5.sdk'])
   165 				self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
   166 				self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
   167 				self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
   168 
   169 				# For OS X dylib versioning
   170 				import re
   171 				productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
   172 				productContents = productFile.read()
   173 				productFile.close()
   174 				m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
   175 				if m == None:
   176 					self.version = '1.0.0'
   177 				else:
   178 					major, minor, release = m.groups()
   179 					self.version = '{0}.{1}.{2}'.format(major, minor, release)
   180 				AMBuild.cache.CacheVariable('version', self.version)
   181 			elif AMBuild.target['platform'] == 'windows':
   182 				self.compiler.AddToListVar('CDEFINES', 'WIN32')
   183 				self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
   184 
   185 			#Finish up
   186 			self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
   187 			self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
   188 			self.compiler.AddToListVar('CINCLUDES',
   189 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   190 			self.compiler.ToConfig(AMBuild, 'compiler')
   191 			AMBuild.cache.CacheVariable('vendor', self.vendor)
   192 			self.targetMap = { }
   193 			AMBuild.cache.CacheVariable('targetMap', self.targetMap)
   194 		else:
   195 			self.compiler.FromConfig(AMBuild, 'compiler')
   196 			self.targetMap = AMBuild.cache['targetMap']
   197 
   198 		if AMBuild.target['platform'] == 'windows':
   199 			self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
   200 			self.compiler.AddToListVar('RCINCLUDES',
   201 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   202 		self.mmsPath = AMBuild.cache['MMSOURCE18']
   203 
   204 	def DefaultCompiler(self):
   205 		return self.compiler.Clone()
   206 
   207 	def JobMatters(self, jobname):
   208 		file = sys._getframe().f_code.co_filename
   209 		if AMBuild.mode == 'config':
   210 			self.targetMap[jobname] = file
   211 			return True
   212 		if len(AMBuild.args) == 0:
   213 			return True
   214 		if not jobname in AMBuild.args:
   215 			return False
   216 
   217 	def DefaultExtCompiler(self, path):
   218 		compiler = self.DefaultCompiler()
   219 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
   220 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
   221 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
   222 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
   223 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
   224 		return compiler
   225 
   226 	def AutoVersion(self, folder, binary):
   227 		if AMBuild.target['platform'] == 'windows':
   228 			env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
   229 			binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
   230 		elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
   231 			binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
   232 			binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
   233 		else:
   234 			return
   235 
   236 	def PreSetupHL2Job(self, job, builder, sdk):
   237 		info = self.sdkInfo[sdk]
   238 		sdkPath = AMBuild.cache[info['sdk']]
   239 		if AMBuild.target['platform'] == 'linux':
   240 			if sdk == 'ep1':
   241 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   242 			else:
   243 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   244 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   245 			if sdk in ['ep2v', 'l4d', 'l4d2']:
   246 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']:
   247 					link = os.path.join(workFolder, i)
   248 					target = os.path.join(staticLibs, i)
   249 					try:
   250 						os.lstat(link)
   251 					except:
   252 						job.AddCommand(SymlinkCommand(link, target))
   253 			else:
   254 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']:
   255 					link = os.path.join(workFolder, i)
   256 					target = os.path.join(staticLibs, i)
   257 					try:
   258 						os.lstat(link)
   259 					except:
   260 						job.AddCommand(SymlinkCommand(link, target))
   261 		elif AMBuild.target['platform'] == 'darwin':
   262 			staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   263 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   264 			for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']:
   265 				link = os.path.join(workFolder, i)
   266 				target = os.path.join(staticLibs, i)
   267 				try:
   268 					os.lstat(link)
   269 				except:
   270 					job.AddCommand(SymlinkCommand(link, target))
   271 		elif AMBuild.target['platform'] == 'windows':
   272 			libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
   273 			if sdk == 'swarm':
   274 				libs.append('interfaces')
   275 			for lib in libs:
   276 				libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
   277 				builder.RebuildIfNewer(libPath)
   278 				builder['POSTLINKFLAGS'].append(libPath)
   279 
   280 	def PostSetupHL2Job(self, job, builder, sdk):
   281 		if AMBuild.target['platform'] in ['linux', 'darwin']:
   282 			builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
   283 
   284 	def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
   285 		compiler = self.DefaultExtCompiler(path)
   286 
   287 		mms = 'core'
   288 		if sdk == 'ep1':
   289 			mms += oldMms
   290 
   291 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
   292 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
   293 
   294 		info = self.sdkInfo
   295 		compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
   296 
   297 		paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
   298 						 ['public', 'tier0'], ['public', 'tier1']]
   299 		if sdk == 'ep1' or sdk == 'darkm':
   300 			paths.append(['public', 'dlls'])
   301 			paths.append(['game_shared'])
   302 		else:
   303 			paths.append(['public', 'game', 'server'])
   304 			paths.append(['public', 'toolframework'])
   305 			paths.append(['game', 'shared'])
   306 			paths.append(['common'])
   307 
   308 		info = self.sdkInfo[sdk]
   309 		sdkPath = AMBuild.cache[info['sdk']]
   310 
   311 		compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
   312 
   313 		if sdk == 'swarm' and AMBuild.target['platform'] == 'windows':
   314 			compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
   315 
   316 		if sdk == 'ep1':
   317 			if AMBuild.target['platform'] == 'linux':
   318 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   319 		else:
   320 			if AMBuild.target['platform'] == 'linux':
   321 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   322 			elif AMBuild.target['platform'] == 'darwin':
   323 				staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   324 
   325 		for i in paths:
   326 			compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
   327 
   328 		if not noLink:
   329 			if AMBuild.target['platform'] == 'linux':
   330 				compiler['POSTLINKFLAGS'][0:0] = ['-lm']
   331 				if sdk in ['ep2v', 'l4d', 'l4d2']:
   332 					compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
   333 					compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
   334 				else:
   335 					compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
   336 					compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
   337 			elif AMBuild.target['platform'] == 'darwin':
   338 				compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
   339 				compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
   340 
   341 		return compiler
   342 
   343 sm = SM()
   344 globals = {
   345 	'SM': sm
   346 }
   347 
   348 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
   349 
   350 FileList = [
   351 		['loader', 'AMBuilder'],
   352 		['core', 'AMBuilder'],
   353 		['core', 'logic', 'AMBuilder'],
   354 		['extensions', 'bintools', 'AMBuilder'],
   355 		['extensions', 'clientprefs', 'AMBuilder'],
   356 		['extensions', 'cstrike', 'AMBuilder'],
   357 		['extensions', 'curl', 'AMBuilder'],
   358 		['extensions', 'geoip', 'AMBuilder'],
   359 		['extensions', 'mysql', 'AMBuilder'],
   360 		['extensions', 'sdktools', 'AMBuilder'],
   361 		['extensions', 'topmenus', 'AMBuilder'],
   362 		['extensions', 'updater', 'AMBuilder'],
   363 		['extensions', 'sqlite', 'AMBuilder'],
   364 		['extensions', 'regex', 'AMBuilder'],
   365 		['extensions', 'tf2', 'AMBuilder'],
   366 		['sourcepawn', 'jit', 'AMBuilder'],
   367 		['sourcepawn', 'compiler', 'AMBuilder'],
   368 		['plugins', 'AMBuilder'],
   369 		['tools', 'buildbot', 'PackageScript']
   370 	]
   371 
   372 for parts in FileList:
   373 	AMBuild.Include(os.path.join(*parts), globals)
   374