Build fixes for recent hl2sdk-dota updates.
1 # vim: set ts=2 sw=2 tw=99 noet ft=python:
4 from ambuild.command import Command
5 from ambuild.command import ShellCommand
6 from ambuild.command import SymlinkCommand
8 class ExtractDebugInfoCommand(Command):
9 def __init__(self, binary, outfile):
10 Command.__init__(self)
12 self.outfile = outfile
14 def run(self, runner, job):
15 if AMBuild.cache['debug']:
18 if not self.binary.NeedsRelink(self.outfile):
21 if AMBuild.target['platform'] == 'linux':
22 job.AddCommand(ShellCommand('objcopy --only-keep-debug ' + self.outfile + ' ' + self.outfile + '.dbg'))
23 job.AddCommand(ShellCommand('objcopy --strip-debug ' + self.outfile))
24 job.AddCommand(ShellCommand('objcopy --add-gnu-debuglink=' + os.path.basename(self.outfile) + '.dbg ' + self.outfile))
25 elif AMBuild.target['platform'] == 'darwin':
26 job.AddCommand(ShellCommand('dsymutil ' + self.outfile))
27 job.AddCommand(ShellCommand('strip -S ' + self.outfile))
31 self.compiler = Cpp.Compiler()
34 self.possibleSdks = { }
35 self.possibleSdks['ep1'] = {'sdk': 'HL2SDK', 'ext': '1.ep1', 'def': '1',
36 'name': 'EPISODEONE', 'platform': ['windows', 'linux'],
38 self.possibleSdks['ep2'] = {'sdk': 'HL2SDKOB', 'ext': '2.ep2', 'def': '3',
39 'name': 'ORANGEBOX', 'platform': ['windows', 'linux'],
41 self.possibleSdks['css'] = {'sdk': 'HL2SDKCSS', 'ext': '2.css', 'def': '6',
42 'name': 'CSS', 'platform': ['windows', 'linux', 'darwin'],
44 self.possibleSdks['ep2v'] = {'sdk': 'HL2SDKOBVALVE', 'ext': '2.ep2v', 'def': '7',
45 'name': 'ORANGEBOXVALVE', 'platform': ['windows', 'linux', 'darwin'],
46 'dir': 'hl2sdk-ob-valve'}
47 self.possibleSdks['l4d'] = {'sdk': 'HL2SDKL4D', 'ext': '2.l4d', 'def': '8',
48 'name': 'LEFT4DEAD', 'platform': ['windows', 'linux', 'darwin'],
50 self.possibleSdks['l4d2'] = {'sdk': 'HL2SDKL4D2', 'ext': '2.l4d2', 'def': '9',
51 'name': 'LEFT4DEAD2', 'platform': ['windows', 'linux', 'darwin'],
53 self.possibleSdks['darkm'] = {'sdk': 'HL2SDK-DARKM', 'ext': '2.darkm', 'def': '2',
54 'name': 'DARKMESSIAH', 'platform': ['windows'],
55 'dir': 'hl2sdk-darkm'}
56 self.possibleSdks['swarm'] = {'sdk': 'HL2SDK-SWARM', 'ext': '2.swarm', 'def': '10',
57 'name': 'ALIENSWARM', 'platform': ['windows'],
58 'dir': 'hl2sdk-swarm'}
59 self.possibleSdks['bgt'] = {'sdk': 'HL2SDK-BGT', 'ext': '2.bgt', 'def': '4',
60 'name': 'BLOODYGOODTIME', 'platform': ['windows'],
62 self.possibleSdks['eye'] = {'sdk': 'HL2SDK-EYE', 'ext': '2.eye', 'def': '5',
63 'name': 'EYE', 'platform': ['windows'],
65 self.possibleSdks['csgo'] = {'sdk': 'HL2SDKCSGO', 'ext': '2.csgo', 'def': '12',
66 'name': 'CSGO', 'platform': ['windows', 'linux', 'darwin'],
68 self.possibleSdks['dota'] = {'sdk': 'HL2SDKDOTA', 'ext': '2.dota', 'def': '13',
69 'name': 'DOTA', 'platform': ['windows'],
71 # self.possibleSdks['portal2'] = {'sdk': 'HL2SDK-PORTAL2', 'ext': '2.portal2', 'def': '11',
72 # 'name': 'PORTAL2', 'platform': ['windows'],
73 # 'dir': 'hl2sdk-portal2'}
77 if AMBuild.mode == 'config':
79 self.compiler.DetectAll(AMBuild)
81 self.hasMySql = AMBuild.options.hasMySql
82 AMBuild.cache.CacheVariable('hasMySql', self.hasMySql)
84 AMBuild.cache.CacheVariable('debug', AMBuild.options.debug)
86 #Environment variable paths to external headers
87 envvars = { 'MMSOURCE19': 'mmsource-1.9', 'MYSQL5': 'mysql-5.0' }
89 #Look for Metamod:Source and MySQL if not disabled
91 if not self.hasMySql and env == 'MYSQL5':
93 path = self.ResolveEnvPath(env, envvars[env])
95 raise Exception('Could not find a valid path for {0}'.format(env))
96 AMBuild.cache.CacheVariable(env, path)
98 #Look for SDK directories
99 for sdk in self.possibleSdks:
100 #Get list of SDKs to build against or 'all' or 'present'
101 sdkList = AMBuild.options.sdks.split(',')
102 #Build against all supported SDKs?
103 useAll = sdkList[0] == 'all'
104 #Build against supported SDKs that exist?
105 usePresent = sdkList[0] == 'present'
107 info = self.possibleSdks[sdk]
108 if AMBuild.target['platform'] in info['platform']:
111 sdkPath = self.ResolveEnvPath(env, dir)
113 if useAll or sdk in sdkList:
114 raise Exception('Could not find a valid path for {0}'.format(env))
117 if useAll or usePresent or sdk in sdkList:
118 self.sdkInfo[sdk] = info
119 AMBuild.cache.CacheVariable(env, sdkPath)
121 if len(self.sdkInfo) < 1:
122 raise Exception('At least one SDK must be available.')
124 AMBuild.cache.CacheVariable('sdkInfo', self.sdkInfo)
127 cxx = self.compiler.cxx
128 if isinstance(cxx, Cpp.CompatGCC):
129 if isinstance(cxx, Cpp.GCC):
131 elif isinstance(cxx, Cpp.Clang):
132 self.vendor = 'clang'
133 self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
134 self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
135 self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
136 self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
137 self.compiler.AddToListVar('CFLAGS', '-pipe')
138 self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
139 if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang':
140 self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
141 self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
142 self.compiler.AddToListVar('CFLAGS', '-Wall')
143 self.compiler.AddToListVar('CFLAGS', '-Werror')
144 self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
145 self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
146 self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
147 self.compiler.AddToListVar('CFLAGS', '-msse')
148 self.compiler.AddToListVar('CFLAGS', '-g3')
149 self.compiler.AddToListVar('CFLAGS', '-m32')
150 self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
151 self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
152 self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
153 self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
154 self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
155 if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \
156 (self.vendor == 'clang' and cxx.majorVersion >= 3):
157 self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor')
158 self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
159 self.compiler.AddToListVar('CDEFINES', 'GNUC')
160 if self.vendor == 'gcc':
161 self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
162 elif isinstance(cxx, Cpp.MSVC):
164 if AMBuild.options.debug == '1':
165 self.compiler.AddToListVar('CFLAGS', '/MTd')
166 self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
168 self.compiler.AddToListVar('CFLAGS', '/MT')
169 self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
170 self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
171 self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
172 self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
173 self.compiler.AddToListVar('CXXFLAGS', '/GR-')
174 self.compiler.AddToListVar('CFLAGS', '/W3')
175 self.compiler.AddToListVar('CFLAGS', '/nologo')
176 self.compiler.AddToListVar('CFLAGS', '/Zi')
177 self.compiler.AddToListVar('CXXFLAGS', '/TP')
178 self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
179 self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
180 self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
181 self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
182 self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
183 self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
184 self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
185 self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
186 self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
187 self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
188 self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
189 self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
190 self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
191 self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
192 self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
195 if AMBuild.options.opt == '1':
196 self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
197 if self.vendor == 'gcc' or self.vendor == 'clang':
198 self.compiler.AddToListVar('CFLAGS', '-O3')
199 elif self.vendor == 'msvc':
200 self.compiler.AddToListVar('CFLAGS', '/Ox')
201 self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
202 self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
205 if AMBuild.options.debug == '1':
206 self.compiler.AddToListVar('CDEFINES', 'DEBUG')
207 self.compiler.AddToListVar('CDEFINES', '_DEBUG')
208 if self.vendor == 'msvc':
209 self.compiler.AddToListVar('CFLAGS', '/Od')
210 self.compiler.AddToListVar('CFLAGS', '/RTC1')
213 if AMBuild.target['platform'] == 'linux':
214 self.compiler.AddToListVar('CDEFINES', '_LINUX')
215 if self.vendor == 'gcc':
216 self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
217 if self.vendor == 'clang':
218 self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
219 elif AMBuild.target['platform'] == 'darwin':
220 self.compiler.AddToListVar('CDEFINES', 'OSX')
221 self.compiler.AddToListVar('CDEFINES', '_OSX')
222 self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
223 self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
224 self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
226 # For OS X dylib versioning
228 productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
229 productContents = productFile.read()
231 m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
233 self.version = '1.0.0'
235 major, minor, release = m.groups()
236 self.version = '{0}.{1}.{2}'.format(major, minor, release)
237 AMBuild.cache.CacheVariable('version', self.version)
238 elif AMBuild.target['platform'] == 'windows':
239 self.compiler.AddToListVar('CDEFINES', 'WIN32')
240 self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
243 self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
244 self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
245 self.compiler.AddToListVar('CINCLUDES',
246 os.path.join(AMBuild.outputFolder, 'includes'))
247 self.compiler.ToConfig(AMBuild, 'compiler')
248 AMBuild.cache.CacheVariable('vendor', self.vendor)
250 AMBuild.cache.CacheVariable('targetMap', self.targetMap)
252 self.sdkInfo = AMBuild.cache['sdkInfo']
253 self.compiler.FromConfig(AMBuild, 'compiler')
254 self.targetMap = AMBuild.cache['targetMap']
255 self.hasMySql = AMBuild.cache['hasMySql']
257 if AMBuild.target['platform'] == 'windows':
258 self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
259 self.compiler.AddToListVar('RCINCLUDES',
260 os.path.join(AMBuild.outputFolder, 'includes'))
261 self.mmsPath = AMBuild.cache['MMSOURCE19']
263 def DefaultCompiler(self):
264 return self.compiler.Clone()
266 def JobMatters(self, jobname):
267 file = sys._getframe().f_code.co_filename
268 if AMBuild.mode == 'config':
269 self.targetMap[jobname] = file
271 if len(AMBuild.args) == 0:
273 if not jobname in AMBuild.args:
276 def DefaultExtCompiler(self, path):
277 compiler = self.DefaultCompiler()
278 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
279 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
280 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
281 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
282 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
285 def AutoVersion(self, folder, binary):
286 if AMBuild.target['platform'] == 'windows':
287 env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
288 binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
289 elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
290 binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
291 binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
295 def ExtractDebugInfo(self, job, binary):
296 src = os.path.join('..', AMBuild.outputFolder, job.workFolder, binary.binaryFile)
297 job.AddCommand(ExtractDebugInfoCommand(binary, src))
299 def PreSetupHL2Job(self, job, builder, sdk):
300 info = self.sdkInfo[sdk]
301 sdkPath = AMBuild.cache[info['sdk']]
302 if AMBuild.target['platform'] == 'linux':
304 staticLibs = os.path.join(sdkPath, 'linux_sdk')
306 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
307 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
308 if sdk in ['ep2v', 'css']:
309 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib_srv.so', 'libtier0_srv.so']
311 link = os.path.join(workFolder, lib)
312 target = os.path.join(staticLibs, lib)
316 job.AddCommand(SymlinkCommand(link, target))
317 elif sdk in ['l4d', 'l4d2', 'csgo']:
318 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']
320 libs.append('interfaces_i486.a')
322 link = os.path.join(workFolder, lib)
323 target = os.path.join(staticLibs, lib)
327 job.AddCommand(SymlinkCommand(link, target))
329 libs = ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']
331 link = os.path.join(workFolder, lib)
332 target = os.path.join(staticLibs, lib)
336 job.AddCommand(SymlinkCommand(link, target))
337 elif AMBuild.target['platform'] == 'darwin':
338 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
339 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
340 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']
342 libs.append('interfaces_i486.a')
344 link = os.path.join(workFolder, lib)
345 target = os.path.join(staticLibs, lib)
349 job.AddCommand(SymlinkCommand(link, target))
350 elif AMBuild.target['platform'] == 'windows':
351 libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
352 if sdk in ['swarm', 'csgo', 'dota']:
353 libs.append('interfaces')
355 libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
356 builder.RebuildIfNewer(libPath)
357 builder['POSTLINKFLAGS'].append(libPath)
359 def PostSetupHL2Job(self, job, builder, sdk):
360 if AMBuild.target['platform'] in ['linux', 'darwin']:
361 builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
363 builder.AddObjectFiles(['interfaces_i486.a'])
365 def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
366 compiler = self.DefaultExtCompiler(path)
372 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
373 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
375 info = self.possibleSdks
376 compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
378 # We don't build for Portal 2 (yet?, ever?), but using this define in code as
379 # it saves trouble if we ever need to
380 compiler['CDEFINES'].append('SE_PORTAL2=11')
382 paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
383 ['public', 'tier0'], ['public', 'tier1']]
384 if sdk == 'ep1' or sdk == 'darkm':
385 paths.append(['public', 'dlls'])
386 paths.append(['game_shared'])
388 paths.append(['public', 'game', 'server'])
389 paths.append(['public', 'toolframework'])
390 paths.append(['game', 'shared'])
391 paths.append(['common'])
393 info = self.sdkInfo[sdk]
394 sdkPath = AMBuild.cache[info['sdk']]
396 compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
398 if sdk in ['swarm','csgo','dota']:
399 if AMBuild.target['platform'] == 'windows':
400 compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
402 compiler['CDEFINES'].extend(['COMPILER_GCC', 'POSIX'])
405 if AMBuild.target['platform'] == 'linux':
406 staticLibs = os.path.join(sdkPath, 'linux_sdk')
408 if AMBuild.target['platform'] == 'linux':
409 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
410 elif AMBuild.target['platform'] == 'darwin':
411 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
414 compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
417 if AMBuild.target['platform'] == 'linux':
418 compiler['POSTLINKFLAGS'][0:0] = ['-lm']
419 if sdk in ['ep2v', 'css']:
420 compiler['POSTLINKFLAGS'][0:0] = ['libtier0_srv.so']
421 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib_srv.so']
422 elif sdk in ['l4d', 'l4d2', 'csgo']:
423 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
424 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
426 compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
427 compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
428 elif AMBuild.target['platform'] == 'darwin':
429 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
430 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
434 def ResolveEnvPath(self, env, defaultDir):
435 if env in os.environ:
436 path = os.environ[env]
437 if os.path.isdir(path):
442 while head != None and head != oldhead:
443 path = os.path.join(head, defaultDir)
444 if os.path.isdir(path):
447 head, tail = os.path.split(head)
455 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
458 ['loader', 'AMBuilder'],
459 ['core', 'AMBuilder'],
460 ['core', 'logic', 'AMBuilder'],
461 ['extensions', 'bintools', 'AMBuilder'],
462 ['extensions', 'clientprefs', 'AMBuilder'],
463 ['extensions', 'cstrike', 'AMBuilder'],
464 ['extensions', 'curl', 'AMBuilder'],
465 ['extensions', 'geoip', 'AMBuilder'],
466 ['extensions', 'mysql', 'AMBuilder'],
467 ['extensions', 'sdkhooks', 'AMBuilder'],
468 ['extensions', 'sdktools', 'AMBuilder'],
469 ['extensions', 'topmenus', 'AMBuilder'],
470 ['extensions', 'updater', 'AMBuilder'],
471 ['extensions', 'sqlite', 'AMBuilder'],
472 ['extensions', 'regex', 'AMBuilder'],
473 ['extensions', 'tf2', 'AMBuilder'],
474 ['sourcepawn', 'jit', 'AMBuilder'],
475 ['sourcepawn', 'compiler', 'AMBuilder'],
476 ['plugins', 'AMBuilder'],
477 ['tools', 'buildbot', 'PackageScript'],
478 ['tools', 'buildbot', 'BreakpadSymbols']
482 FileList.remove(['extensions', 'mysql', 'AMBuilder'])
484 for parts in FileList:
485 AMBuild.Include(os.path.join(*parts), globals)