AMBuildScript
author Scott Ehlert <ds@alliedmods.net>
Sat Apr 23 21:53:53 2011 -0500 (2011-04-23)
changeset 3261 e4359292e59a
parent 3180 61db674548aa
child 3266 9f60b6ea9c95
permissions -rw-r--r--
Added detection for clang compiler and fixed various warnings triggered by it (bug 4878, r=dvander).
     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 					self.compiler.AddToListVar('CFLAGS', '-static-libgcc')
   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 			elif AMBuild.target['platform'] == 'darwin':
   159 				self.compiler.AddToListVar('CFLAGS', ['-isysroot',
   160 				                                      '/Developer/SDKs/MacOSX10.5.sdk'])
   161 				self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
   162 				self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
   163 				self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
   164 
   165 				# For OS X dylib versioning
   166 				import re
   167 				productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
   168 				productContents = productFile.read()
   169 				productFile.close()
   170 				m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
   171 				if m == None:
   172 					self.version = '1.0.0'
   173 				else:
   174 					major, minor, release = m.groups()
   175 					self.version = '{0}.{1}.{2}'.format(major, minor, release)
   176 				AMBuild.cache.CacheVariable('version', self.version)
   177 			elif AMBuild.target['platform'] == 'windows':
   178 				self.compiler.AddToListVar('CDEFINES', 'WIN32')
   179 				self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
   180 
   181 			#Finish up
   182 			self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
   183 			self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
   184 			self.compiler.AddToListVar('CINCLUDES',
   185 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   186 			self.compiler.ToConfig(AMBuild, 'compiler')
   187 			AMBuild.cache.CacheVariable('vendor', self.vendor)
   188 			self.targetMap = { }
   189 			AMBuild.cache.CacheVariable('targetMap', self.targetMap)
   190 		else:
   191 			self.compiler.FromConfig(AMBuild, 'compiler')
   192 			self.targetMap = AMBuild.cache['targetMap']
   193 
   194 		if AMBuild.target['platform'] == 'windows':
   195 			self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
   196 			self.compiler.AddToListVar('RCINCLUDES',
   197 			                           os.path.join(AMBuild.outputFolder, 'includes'))
   198 		self.mmsPath = AMBuild.cache['MMSOURCE18']
   199 
   200 	def DefaultCompiler(self):
   201 		return self.compiler.Clone()
   202 
   203 	def JobMatters(self, jobname):
   204 		file = sys._getframe().f_code.co_filename
   205 		if AMBuild.mode == 'config':
   206 			self.targetMap[jobname] = file
   207 			return True
   208 		if len(AMBuild.args) == 0:
   209 			return True
   210 		if not jobname in AMBuild.args:
   211 			return False
   212 
   213 	def DefaultExtCompiler(self, path):
   214 		compiler = self.DefaultCompiler()
   215 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
   216 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
   217 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
   218 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
   219 		compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
   220 		return compiler
   221 
   222 	def AutoVersion(self, folder, binary):
   223 		if AMBuild.target['platform'] == 'windows':
   224 			env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
   225 			binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
   226 		elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
   227 			binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
   228 			binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
   229 		else:
   230 			return
   231 
   232 	def PreSetupHL2Job(self, job, builder, sdk):
   233 		info = self.sdkInfo[sdk]
   234 		sdkPath = AMBuild.cache[info['sdk']]
   235 		if AMBuild.target['platform'] == 'linux':
   236 			if sdk == 'ep1':
   237 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   238 			else:
   239 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   240 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   241 			if sdk in ['ep2v', 'l4d', 'l4d2']:
   242 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']:
   243 					link = os.path.join(workFolder, i)
   244 					target = os.path.join(staticLibs, i)
   245 					try:
   246 						os.lstat(link)
   247 					except:
   248 						job.AddCommand(SymlinkCommand(link, target))
   249 			else:
   250 				for i in ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']:
   251 					link = os.path.join(workFolder, i)
   252 					target = os.path.join(staticLibs, i)
   253 					try:
   254 						os.lstat(link)
   255 					except:
   256 						job.AddCommand(SymlinkCommand(link, target))
   257 		elif AMBuild.target['platform'] == 'darwin':
   258 			staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   259 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
   260 			for i in ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']:
   261 				link = os.path.join(workFolder, i)
   262 				target = os.path.join(staticLibs, i)
   263 				try:
   264 					os.lstat(link)
   265 				except:
   266 					job.AddCommand(SymlinkCommand(link, target))
   267 		elif AMBuild.target['platform'] == 'windows':
   268 			libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
   269 			if sdk == 'swarm':
   270 				libs.append('interfaces')
   271 			for lib in libs:
   272 				libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
   273 				builder.RebuildIfNewer(libPath)
   274 				builder['POSTLINKFLAGS'].append(libPath)
   275 
   276 	def PostSetupHL2Job(self, job, builder, sdk):
   277 		if AMBuild.target['platform'] in ['linux', 'darwin']:
   278 			builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
   279 
   280 	def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
   281 		compiler = self.DefaultExtCompiler(path)
   282 
   283 		mms = 'core'
   284 		if sdk == 'ep1':
   285 			mms += oldMms
   286 
   287 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
   288 		compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
   289 
   290 		info = self.sdkInfo
   291 		compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
   292 
   293 		paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
   294 						 ['public', 'tier0'], ['public', 'tier1']]
   295 		if sdk == 'ep1' or sdk == 'darkm':
   296 			paths.append(['public', 'dlls'])
   297 			paths.append(['game_shared'])
   298 		else:
   299 			paths.append(['public', 'game', 'server'])
   300 			paths.append(['game', 'shared'])
   301 			paths.append(['common'])
   302 
   303 		info = self.sdkInfo[sdk]
   304 		sdkPath = AMBuild.cache[info['sdk']]
   305 
   306 		compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
   307 
   308 		if sdk == 'swarm' and AMBuild.target['platform'] == 'windows':
   309 			compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
   310 
   311 		if sdk == 'ep1':
   312 			if AMBuild.target['platform'] == 'linux':
   313 				staticLibs = os.path.join(sdkPath, 'linux_sdk')
   314 		else:
   315 			if AMBuild.target['platform'] == 'linux':
   316 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
   317 			elif AMBuild.target['platform'] == 'darwin':
   318 				staticLibs = os.path.join(sdkPath, 'lib', 'mac')
   319 
   320 		for i in paths:
   321 			compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
   322 
   323 		if not noLink:
   324 			if AMBuild.target['platform'] == 'linux':
   325 				compiler['POSTLINKFLAGS'][0:0] = ['-lm']
   326 				if sdk in ['ep2v', 'l4d', 'l4d2']:
   327 					compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
   328 					compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
   329 				else:
   330 					compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
   331 					compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
   332 			elif AMBuild.target['platform'] == 'darwin':
   333 				compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
   334 				compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
   335 
   336 		return compiler
   337 
   338 sm = SM()
   339 globals = {
   340 	'SM': sm
   341 }
   342 
   343 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
   344 
   345 FileList = [
   346 		['loader', 'AMBuilder'],
   347 		['core', 'AMBuilder'],
   348 		['core', 'logic', 'AMBuilder'],
   349 		['extensions', 'bintools', 'AMBuilder'],
   350 		['extensions', 'clientprefs', 'AMBuilder'],
   351 		['extensions', 'cstrike', 'AMBuilder'],
   352 		['extensions', 'curl', 'AMBuilder'],
   353 		['extensions', 'geoip', 'AMBuilder'],
   354 		['extensions', 'mysql', 'AMBuilder'],
   355 		['extensions', 'sdktools', 'AMBuilder'],
   356 		['extensions', 'topmenus', 'AMBuilder'],
   357 		['extensions', 'updater', 'AMBuilder'],
   358 		['extensions', 'sqlite', 'AMBuilder'],
   359 		['extensions', 'regex', 'AMBuilder'],
   360 		['extensions', 'tf2', 'AMBuilder'],
   361 		['sourcepawn', 'jit', 'AMBuilder'],
   362 		['sourcepawn', 'compiler', 'AMBuilder'],
   363 		['plugins', 'AMBuilder'],
   364 		['tools', 'buildbot', 'PackageScript']
   365 	]
   366 
   367 for parts in FileList:
   368 	AMBuild.Include(os.path.join(*parts), globals)
   369