Another build fix.
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 not self.binary.NeedsRelink(self.outfile):
18 if AMBuild.target['platform'] == 'linux':
19 job.AddCommand(ShellCommand('objcopy --only-keep-debug ' + self.outfile + ' ' + self.outfile + '.dbg'))
20 job.AddCommand(ShellCommand('objcopy --strip-debug ' + self.outfile))
21 job.AddCommand(ShellCommand('objcopy --add-gnu-debuglink=' + os.path.basename(self.outfile) + '.dbg ' + self.outfile))
22 elif AMBuild.target['platform'] == 'darwin':
23 job.AddCommand(ShellCommand('dsymutil ' + self.outfile))
24 job.AddCommand(ShellCommand('strip -S ' + self.outfile))
28 self.compiler = Cpp.Compiler()
31 self.possibleSdks = { }
32 self.possibleSdks['ep1'] = {'sdk': 'HL2SDK', 'ext': '1.ep1', 'def': '1',
33 'name': 'EPISODEONE', 'platform': ['windows', 'linux'],
35 self.possibleSdks['ep2'] = {'sdk': 'HL2SDKOB', 'ext': '2.ep2', 'def': '3',
36 'name': 'ORANGEBOX', 'platform': ['windows', 'linux'],
38 self.possibleSdks['css'] = {'sdk': 'HL2SDKCSS', 'ext': '2.css', 'def': '6',
39 'name': 'CSS', 'platform': ['windows', 'linux', 'darwin'],
41 self.possibleSdks['ep2v'] = {'sdk': 'HL2SDKOBVALVE', 'ext': '2.ep2v', 'def': '7',
42 'name': 'ORANGEBOXVALVE', 'platform': ['windows', 'linux', 'darwin'],
43 'dir': 'hl2sdk-ob-valve'}
44 self.possibleSdks['l4d'] = {'sdk': 'HL2SDKL4D', 'ext': '2.l4d', 'def': '8',
45 'name': 'LEFT4DEAD', 'platform': ['windows', 'linux', 'darwin'],
47 self.possibleSdks['l4d2'] = {'sdk': 'HL2SDKL4D2', 'ext': '2.l4d2', 'def': '9',
48 'name': 'LEFT4DEAD2', 'platform': ['windows', 'linux', 'darwin'],
50 self.possibleSdks['darkm'] = {'sdk': 'HL2SDK-DARKM', 'ext': '2.darkm', 'def': '2',
51 'name': 'DARKMESSIAH', 'platform': ['windows'],
52 'dir': 'hl2sdk-darkm'}
53 self.possibleSdks['swarm'] = {'sdk': 'HL2SDK-SWARM', 'ext': '2.swarm', 'def': '10',
54 'name': 'ALIENSWARM', 'platform': ['windows'],
55 'dir': 'hl2sdk-swarm'}
56 self.possibleSdks['bgt'] = {'sdk': 'HL2SDK-BGT', 'ext': '2.bgt', 'def': '4',
57 'name': 'BLOODYGOODTIME', 'platform': ['windows'],
59 self.possibleSdks['eye'] = {'sdk': 'HL2SDK-EYE', 'ext': '2.eye', 'def': '5',
60 'name': 'EYE', 'platform': ['windows'],
62 self.possibleSdks['csgo'] = {'sdk': 'HL2SDKCSGO', 'ext': '2.csgo', 'def': '12',
63 'name': 'CSGO', 'platform': ['windows', 'linux', 'darwin'],
65 self.possibleSdks['dota'] = {'sdk': 'HL2SDKDOTA', 'ext': '2.dota', 'def': '13',
66 'name': 'DOTA', 'platform': ['windows'],
68 # self.possibleSdks['portal2'] = {'sdk': 'HL2SDK-PORTAL2', 'ext': '2.portal2', 'def': '11',
69 # 'name': 'PORTAL2', 'platform': ['windows'],
70 # 'dir': 'hl2sdk-portal2'}
74 if AMBuild.mode == 'config':
76 self.compiler.DetectAll(AMBuild)
78 self.hasMySql = AMBuild.options.hasMySql
79 AMBuild.cache.CacheVariable('hasMySql', self.hasMySql)
81 #Environment variable paths to external headers
82 envvars = { 'MMSOURCE19': 'mmsource-1.9', 'MYSQL5': 'mysql-5.0' }
84 #Look for Metamod:Source and MySQL if not disabled
86 if not self.hasMySql and env == 'MYSQL5':
88 path = self.ResolveEnvPath(env, envvars[env])
90 raise Exception('Could not find a valid path for {0}'.format(env))
91 AMBuild.cache.CacheVariable(env, path)
93 #Look for SDK directories
94 for sdk in self.possibleSdks:
95 #Get list of SDKs to build against or 'all' or 'present'
96 sdkList = AMBuild.options.sdks.split(',')
97 #Build against all supported SDKs?
98 useAll = sdkList[0] == 'all'
99 #Build against supported SDKs that exist?
100 usePresent = sdkList[0] == 'present'
102 info = self.possibleSdks[sdk]
103 if AMBuild.target['platform'] in info['platform']:
106 sdkPath = self.ResolveEnvPath(env, dir)
108 if useAll or sdk in sdkList:
109 raise Exception('Could not find a valid path for {0}'.format(env))
112 if useAll or usePresent or sdk in sdkList:
113 self.sdkInfo[sdk] = info
114 AMBuild.cache.CacheVariable(env, sdkPath)
116 if len(self.sdkInfo) < 1:
117 raise Exception('At least one SDK must be available.')
119 AMBuild.cache.CacheVariable('sdkInfo', self.sdkInfo)
122 cxx = self.compiler.cxx
123 if isinstance(cxx, Cpp.CompatGCC):
124 if isinstance(cxx, Cpp.GCC):
126 elif isinstance(cxx, Cpp.Clang):
127 self.vendor = 'clang'
128 self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
129 self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
130 self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
131 self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
132 self.compiler.AddToListVar('CFLAGS', '-pipe')
133 self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
134 if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang':
135 self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
136 self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
137 self.compiler.AddToListVar('CFLAGS', '-Wall')
138 self.compiler.AddToListVar('CFLAGS', '-Werror')
139 self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
140 self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
141 self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
142 self.compiler.AddToListVar('CFLAGS', '-msse')
143 self.compiler.AddToListVar('CFLAGS', '-g3')
144 self.compiler.AddToListVar('CFLAGS', '-m32')
145 self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
146 self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
147 self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
148 self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
149 self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
150 if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \
151 (self.vendor == 'clang' and cxx.majorVersion >= 3):
152 self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor')
153 self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
154 self.compiler.AddToListVar('CDEFINES', 'GNUC')
155 if self.vendor == 'gcc':
156 self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
157 elif isinstance(cxx, Cpp.MSVC):
159 if AMBuild.options.debug == '1':
160 self.compiler.AddToListVar('CFLAGS', '/MTd')
161 self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
163 self.compiler.AddToListVar('CFLAGS', '/MT')
164 self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
165 self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
166 self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
167 self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
168 self.compiler.AddToListVar('CXXFLAGS', '/GR-')
169 self.compiler.AddToListVar('CFLAGS', '/W3')
170 self.compiler.AddToListVar('CFLAGS', '/nologo')
171 self.compiler.AddToListVar('CFLAGS', '/Zi')
172 self.compiler.AddToListVar('CXXFLAGS', '/TP')
173 self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
174 self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
175 self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
176 self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
177 self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
178 self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
179 self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
180 self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
181 self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
182 self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
183 self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
184 self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
185 self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
186 self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
187 self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
190 if AMBuild.options.opt == '1':
191 self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
192 if self.vendor == 'gcc' or self.vendor == 'clang':
193 self.compiler.AddToListVar('CFLAGS', '-O3')
194 elif self.vendor == 'msvc':
195 self.compiler.AddToListVar('CFLAGS', '/Ox')
196 self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
197 self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
200 if AMBuild.options.debug == '1':
201 self.compiler.AddToListVar('CDEFINES', 'DEBUG')
202 self.compiler.AddToListVar('CDEFINES', '_DEBUG')
203 if self.vendor == 'msvc':
204 self.compiler.AddToListVar('CFLAGS', '/Od')
205 self.compiler.AddToListVar('CFLAGS', '/RTC1')
208 if AMBuild.target['platform'] == 'linux':
209 self.compiler.AddToListVar('CDEFINES', '_LINUX')
210 if self.vendor == 'gcc':
211 self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
212 if self.vendor == 'clang':
213 self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
214 elif AMBuild.target['platform'] == 'darwin':
215 self.compiler.AddToListVar('CDEFINES', 'OSX')
216 self.compiler.AddToListVar('CDEFINES', '_OSX')
217 self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
218 self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
219 self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
221 # For OS X dylib versioning
223 productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
224 productContents = productFile.read()
226 m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
228 self.version = '1.0.0'
230 major, minor, release = m.groups()
231 self.version = '{0}.{1}.{2}'.format(major, minor, release)
232 AMBuild.cache.CacheVariable('version', self.version)
233 elif AMBuild.target['platform'] == 'windows':
234 self.compiler.AddToListVar('CDEFINES', 'WIN32')
235 self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
238 self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
239 self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
240 self.compiler.AddToListVar('CINCLUDES',
241 os.path.join(AMBuild.outputFolder, 'includes'))
242 self.compiler.ToConfig(AMBuild, 'compiler')
243 AMBuild.cache.CacheVariable('vendor', self.vendor)
245 AMBuild.cache.CacheVariable('targetMap', self.targetMap)
247 self.sdkInfo = AMBuild.cache['sdkInfo']
248 self.compiler.FromConfig(AMBuild, 'compiler')
249 self.targetMap = AMBuild.cache['targetMap']
250 self.hasMySql = AMBuild.cache['hasMySql']
252 if AMBuild.target['platform'] == 'windows':
253 self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
254 self.compiler.AddToListVar('RCINCLUDES',
255 os.path.join(AMBuild.outputFolder, 'includes'))
256 self.mmsPath = AMBuild.cache['MMSOURCE19']
258 def DefaultCompiler(self):
259 return self.compiler.Clone()
261 def JobMatters(self, jobname):
262 file = sys._getframe().f_code.co_filename
263 if AMBuild.mode == 'config':
264 self.targetMap[jobname] = file
266 if len(AMBuild.args) == 0:
268 if not jobname in AMBuild.args:
271 def DefaultExtCompiler(self, path):
272 compiler = self.DefaultCompiler()
273 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
274 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
275 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
276 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
277 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
280 def AutoVersion(self, folder, binary):
281 if AMBuild.target['platform'] == 'windows':
282 env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
283 binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
284 elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
285 binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
286 binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
290 def ExtractDebugInfo(self, job, binary):
291 src = os.path.join('..', AMBuild.outputFolder, job.workFolder, binary.binaryFile)
292 job.AddCommand(ExtractDebugInfoCommand(binary, src))
294 def PreSetupHL2Job(self, job, builder, sdk):
295 info = self.sdkInfo[sdk]
296 sdkPath = AMBuild.cache[info['sdk']]
297 if AMBuild.target['platform'] == 'linux':
299 staticLibs = os.path.join(sdkPath, 'linux_sdk')
301 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
302 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
303 if sdk in ['ep2v', 'css']:
304 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib_srv.so', 'libtier0_srv.so']
306 link = os.path.join(workFolder, lib)
307 target = os.path.join(staticLibs, lib)
311 job.AddCommand(SymlinkCommand(link, target))
312 elif sdk in ['l4d', 'l4d2', 'csgo']:
313 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']
315 libs.append('interfaces_i486.a')
317 link = os.path.join(workFolder, lib)
318 target = os.path.join(staticLibs, lib)
322 job.AddCommand(SymlinkCommand(link, target))
324 libs = ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']
326 link = os.path.join(workFolder, lib)
327 target = os.path.join(staticLibs, lib)
331 job.AddCommand(SymlinkCommand(link, target))
332 elif AMBuild.target['platform'] == 'darwin':
333 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
334 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
335 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']
337 libs.append('interfaces_i486.a')
339 link = os.path.join(workFolder, lib)
340 target = os.path.join(staticLibs, lib)
344 job.AddCommand(SymlinkCommand(link, target))
345 elif AMBuild.target['platform'] == 'windows':
346 libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
347 if sdk in ['swarm', 'csgo', 'dota']:
348 libs.append('interfaces')
350 libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
351 builder.RebuildIfNewer(libPath)
352 builder['POSTLINKFLAGS'].append(libPath)
354 def PostSetupHL2Job(self, job, builder, sdk):
355 if AMBuild.target['platform'] in ['linux', 'darwin']:
356 builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
358 builder.AddObjectFiles(['interfaces_i486.a'])
360 def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
361 compiler = self.DefaultExtCompiler(path)
367 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
368 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
370 info = self.possibleSdks
371 compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
373 # We don't build for Portal 2 (yet?, ever?), but using this define in code as
374 # it saves trouble if we ever need to
375 compiler['CDEFINES'].append('SE_PORTAL2=11')
377 paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
378 ['public', 'tier0'], ['public', 'tier1']]
379 if sdk == 'ep1' or sdk == 'darkm':
380 paths.append(['public', 'dlls'])
381 paths.append(['game_shared'])
383 paths.append(['public', 'game', 'server'])
384 paths.append(['public', 'toolframework'])
385 paths.append(['game', 'shared'])
386 paths.append(['common'])
388 info = self.sdkInfo[sdk]
389 sdkPath = AMBuild.cache[info['sdk']]
391 compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
393 if sdk in ['swarm','csgo','dota']:
394 if AMBuild.target['platform'] == 'windows':
395 compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
397 compiler['CDEFINES'].extend(['COMPILER_GCC', 'POSIX'])
400 if AMBuild.target['platform'] == 'linux':
401 staticLibs = os.path.join(sdkPath, 'linux_sdk')
403 if AMBuild.target['platform'] == 'linux':
404 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
405 elif AMBuild.target['platform'] == 'darwin':
406 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
409 compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
412 if AMBuild.target['platform'] == 'linux':
413 compiler['POSTLINKFLAGS'][0:0] = ['-lm']
414 if sdk in ['ep2v', 'css']:
415 compiler['POSTLINKFLAGS'][0:0] = ['libtier0_srv.so']
416 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib_srv.so']
417 elif sdk in ['l4d', 'l4d2', 'csgo']:
418 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
419 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
421 compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
422 compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
423 elif AMBuild.target['platform'] == 'darwin':
424 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
425 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
429 def ResolveEnvPath(self, env, defaultDir):
430 if env in os.environ:
431 path = os.environ[env]
432 if os.path.isdir(path):
437 while head != None and head != oldhead:
438 path = os.path.join(head, defaultDir)
439 if os.path.isdir(path):
442 head, tail = os.path.split(head)
450 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
453 ['loader', 'AMBuilder'],
454 ['core', 'AMBuilder'],
455 ['core', 'logic', 'AMBuilder'],
456 ['extensions', 'bintools', 'AMBuilder'],
457 ['extensions', 'clientprefs', 'AMBuilder'],
458 ['extensions', 'cstrike', 'AMBuilder'],
459 ['extensions', 'curl', 'AMBuilder'],
460 ['extensions', 'geoip', 'AMBuilder'],
461 ['extensions', 'mysql', 'AMBuilder'],
462 ['extensions', 'sdkhooks', 'AMBuilder'],
463 ['extensions', 'sdktools', 'AMBuilder'],
464 ['extensions', 'topmenus', 'AMBuilder'],
465 ['extensions', 'updater', 'AMBuilder'],
466 ['extensions', 'sqlite', 'AMBuilder'],
467 ['extensions', 'regex', 'AMBuilder'],
468 ['extensions', 'tf2', 'AMBuilder'],
469 ['sourcepawn', 'jit', 'AMBuilder'],
470 ['sourcepawn', 'compiler', 'AMBuilder'],
471 ['plugins', 'AMBuilder'],
472 ['tools', 'buildbot', 'PackageScript'],
473 ['tools', 'buildbot', 'BreakpadSymbols']
477 FileList.remove(['extensions', 'mysql', 'AMBuilder'])
479 for parts in FileList:
480 AMBuild.Include(os.path.join(*parts), globals)