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')
212 #This needs to be after our optimization flags which could otherwise disable it.
213 if self.vendor == 'msvc':
214 # Don't omit frame pointer
215 self.compiler.AddToListVar('CFLAGS', '/Oy-')
218 if AMBuild.target['platform'] == 'linux':
219 self.compiler.AddToListVar('CDEFINES', '_LINUX')
220 if self.vendor == 'gcc':
221 self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
222 if self.vendor == 'clang':
223 self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
224 elif AMBuild.target['platform'] == 'darwin':
225 self.compiler.AddToListVar('CDEFINES', 'OSX')
226 self.compiler.AddToListVar('CDEFINES', '_OSX')
227 self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
228 self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
229 self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
231 # For OS X dylib versioning
233 productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
234 productContents = productFile.read()
236 m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
238 self.version = '1.0.0'
240 major, minor, release = m.groups()
241 self.version = '{0}.{1}.{2}'.format(major, minor, release)
242 AMBuild.cache.CacheVariable('version', self.version)
243 elif AMBuild.target['platform'] == 'windows':
244 self.compiler.AddToListVar('CDEFINES', 'WIN32')
245 self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
248 self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
249 self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
250 self.compiler.AddToListVar('CINCLUDES',
251 os.path.join(AMBuild.outputFolder, 'includes'))
252 self.compiler.ToConfig(AMBuild, 'compiler')
253 AMBuild.cache.CacheVariable('vendor', self.vendor)
255 AMBuild.cache.CacheVariable('targetMap', self.targetMap)
257 self.sdkInfo = AMBuild.cache['sdkInfo']
258 self.compiler.FromConfig(AMBuild, 'compiler')
259 self.targetMap = AMBuild.cache['targetMap']
260 self.hasMySql = AMBuild.cache['hasMySql']
262 if AMBuild.target['platform'] == 'windows':
263 self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
264 self.compiler.AddToListVar('RCINCLUDES',
265 os.path.join(AMBuild.outputFolder, 'includes'))
266 self.mmsPath = AMBuild.cache['MMSOURCE19']
268 def DefaultCompiler(self):
269 return self.compiler.Clone()
271 def JobMatters(self, jobname):
272 file = sys._getframe().f_code.co_filename
273 if AMBuild.mode == 'config':
274 self.targetMap[jobname] = file
276 if len(AMBuild.args) == 0:
278 if not jobname in AMBuild.args:
281 def DefaultExtCompiler(self, path):
282 compiler = self.DefaultCompiler()
283 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
284 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
285 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
286 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
287 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
290 def AutoVersion(self, folder, binary):
291 if AMBuild.target['platform'] == 'windows':
292 env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
293 binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
294 elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
295 binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
296 binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
300 def ExtractDebugInfo(self, job, binary):
301 src = os.path.join('..', AMBuild.outputFolder, job.workFolder, binary.binaryFile)
302 job.AddCommand(ExtractDebugInfoCommand(binary, src))
304 def PreSetupHL2Job(self, job, builder, sdk):
305 info = self.sdkInfo[sdk]
306 sdkPath = AMBuild.cache[info['sdk']]
307 if AMBuild.target['platform'] == 'linux':
309 staticLibs = os.path.join(sdkPath, 'linux_sdk')
311 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
312 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
313 if sdk in ['ep2v', 'css', 'l4d2']:
314 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib_srv.so', 'libtier0_srv.so']
316 link = os.path.join(workFolder, lib)
317 target = os.path.join(staticLibs, lib)
321 job.AddCommand(SymlinkCommand(link, target))
322 elif sdk in ['l4d', 'csgo']:
323 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']
325 libs.append('interfaces_i486.a')
327 link = os.path.join(workFolder, lib)
328 target = os.path.join(staticLibs, lib)
332 job.AddCommand(SymlinkCommand(link, target))
334 libs = ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']
336 link = os.path.join(workFolder, lib)
337 target = os.path.join(staticLibs, lib)
341 job.AddCommand(SymlinkCommand(link, target))
342 elif AMBuild.target['platform'] == 'darwin':
343 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
344 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
345 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']
347 libs.append('interfaces_i486.a')
349 link = os.path.join(workFolder, lib)
350 target = os.path.join(staticLibs, lib)
354 job.AddCommand(SymlinkCommand(link, target))
355 elif AMBuild.target['platform'] == 'windows':
356 libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
357 if sdk in ['swarm', 'csgo', 'dota']:
358 libs.append('interfaces')
360 libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
361 builder.RebuildIfNewer(libPath)
362 builder['POSTLINKFLAGS'].append(libPath)
364 def PostSetupHL2Job(self, job, builder, sdk):
365 if AMBuild.target['platform'] in ['linux', 'darwin']:
366 builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
368 builder.AddObjectFiles(['interfaces_i486.a'])
370 def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
371 compiler = self.DefaultExtCompiler(path)
377 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
378 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
380 info = self.possibleSdks
381 compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
383 # We don't build for Portal 2 (yet?, ever?), but using this define in code as
384 # it saves trouble if we ever need to
385 compiler['CDEFINES'].append('SE_PORTAL2=11')
387 paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
388 ['public', 'tier0'], ['public', 'tier1']]
389 if sdk == 'ep1' or sdk == 'darkm':
390 paths.append(['public', 'dlls'])
391 paths.append(['game_shared'])
393 paths.append(['public', 'game', 'server'])
394 paths.append(['public', 'toolframework'])
395 paths.append(['game', 'shared'])
396 paths.append(['common'])
398 info = self.sdkInfo[sdk]
399 sdkPath = AMBuild.cache[info['sdk']]
401 compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
403 if sdk in ['swarm','csgo','dota']:
404 if AMBuild.target['platform'] == 'windows':
405 compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
407 compiler['CDEFINES'].extend(['COMPILER_GCC', 'POSIX'])
410 if AMBuild.target['platform'] == 'linux':
411 staticLibs = os.path.join(sdkPath, 'linux_sdk')
413 if AMBuild.target['platform'] == 'linux':
414 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
415 elif AMBuild.target['platform'] == 'darwin':
416 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
419 compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
422 if AMBuild.target['platform'] == 'linux':
423 compiler['POSTLINKFLAGS'][0:0] = ['-lm']
424 if sdk in ['ep2v', 'css', 'l4d2']:
425 compiler['POSTLINKFLAGS'][0:0] = ['libtier0_srv.so']
426 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib_srv.so']
427 elif sdk in ['l4d', 'csgo']:
428 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
429 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
431 compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
432 compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
433 elif AMBuild.target['platform'] == 'darwin':
434 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
435 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
439 def ResolveEnvPath(self, env, defaultDir):
440 if env in os.environ:
441 path = os.environ[env]
442 if os.path.isdir(path):
447 while head != None and head != oldhead:
448 path = os.path.join(head, defaultDir)
449 if os.path.isdir(path):
452 head, tail = os.path.split(head)
460 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
463 ['loader', 'AMBuilder'],
464 ['core', 'AMBuilder'],
465 ['core', 'logic', 'AMBuilder'],
466 ['extensions', 'bintools', 'AMBuilder'],
467 ['extensions', 'clientprefs', 'AMBuilder'],
468 ['extensions', 'cstrike', 'AMBuilder'],
469 ['extensions', 'curl', 'AMBuilder'],
470 ['extensions', 'geoip', 'AMBuilder'],
471 ['extensions', 'mysql', 'AMBuilder'],
472 ['extensions', 'sdkhooks', 'AMBuilder'],
473 ['extensions', 'sdktools', 'AMBuilder'],
474 ['extensions', 'topmenus', 'AMBuilder'],
475 ['extensions', 'updater', 'AMBuilder'],
476 ['extensions', 'sqlite', 'AMBuilder'],
477 ['extensions', 'regex', 'AMBuilder'],
478 ['extensions', 'tf2', 'AMBuilder'],
479 ['sourcepawn', 'jit', 'AMBuilder'],
480 ['sourcepawn', 'compiler', 'AMBuilder'],
481 ['plugins', 'AMBuilder'],
482 ['tools', 'buildbot', 'PackageScript'],
483 ['tools', 'buildbot', 'BreakpadSymbols']
487 FileList.remove(['extensions', 'mysql', 'AMBuilder'])
489 for parts in FileList:
490 AMBuild.Include(os.path.join(*parts), globals)