1 # vim: set ts=2 sw=2 tw=99 noet ft=python:
4 from ambuild.command import SymlinkCommand
8 self.compiler = Cpp.Compiler()
11 self.possibleSdks = { }
12 self.possibleSdks['ep1'] = {'sdk': 'HL2SDK', 'ext': '1.ep1', 'def': '1',
13 'name': 'EPISODEONE', 'platform': ['windows', 'linux'],
15 self.possibleSdks['ep2'] = {'sdk': 'HL2SDKOB', 'ext': '2.ep2', 'def': '3',
16 'name': 'ORANGEBOX', 'platform': ['windows', 'linux'],
18 self.possibleSdks['css'] = {'sdk': 'HL2SDKCSS', 'ext': '2.css', 'def': '6',
19 'name': 'CSS', 'platform': ['windows', 'linux', 'darwin'],
21 self.possibleSdks['ep2v'] = {'sdk': 'HL2SDKOBVALVE', 'ext': '2.ep2v', 'def': '7',
22 'name': 'ORANGEBOXVALVE', 'platform': ['windows', 'linux', 'darwin'],
23 'dir': 'hl2sdk-ob-valve'}
24 self.possibleSdks['l4d'] = {'sdk': 'HL2SDKL4D', 'ext': '2.l4d', 'def': '8',
25 'name': 'LEFT4DEAD', 'platform': ['windows', 'linux', 'darwin'],
27 self.possibleSdks['l4d2'] = {'sdk': 'HL2SDKL4D2', 'ext': '2.l4d2', 'def': '9',
28 'name': 'LEFT4DEAD2', 'platform': ['windows', 'linux', 'darwin'],
30 self.possibleSdks['darkm'] = {'sdk': 'HL2SDK-DARKM', 'ext': '2.darkm', 'def': '2',
31 'name': 'DARKMESSIAH', 'platform': ['windows'],
32 'dir': 'hl2sdk-darkm'}
33 self.possibleSdks['swarm'] = {'sdk': 'HL2SDK-SWARM', 'ext': '2.swarm', 'def': '10',
34 'name': 'ALIENSWARM', 'platform': ['windows'],
35 'dir': 'hl2sdk-swarm'}
36 self.possibleSdks['bgt'] = {'sdk': 'HL2SDK-BGT', 'ext': '2.bgt', 'def': '4',
37 'name': 'BLOODYGOODTIME', 'platform': ['windows'],
39 self.possibleSdks['eye'] = {'sdk': 'HL2SDK-EYE', 'ext': '2.eye', 'def': '5',
40 'name': 'EYE', 'platform': ['windows'],
42 self.possibleSdks['csgo'] = {'sdk': 'HL2SDKCSGO', 'ext': '2.csgo', 'def': '12',
43 'name': 'CSGO', 'platform': ['windows', 'linux', 'darwin'],
45 # self.possibleSdks['portal2'] = {'sdk': 'HL2SDK-PORTAL2', 'ext': '2.portal2', 'def': '11',
46 # 'name': 'PORTAL2', 'platform': ['windows'],
47 # 'dir': 'hl2sdk-portal2'}
51 if AMBuild.mode == 'config':
53 self.compiler.DetectAll(AMBuild)
55 self.hasMySql = AMBuild.options.hasMySql
56 AMBuild.cache.CacheVariable('hasMySql', self.hasMySql)
58 #Environment variable paths to external headers
59 envvars = { 'MMSOURCE19': 'mmsource-1.9', 'MYSQL5': 'mysql-5.0' }
61 #Look for Metamod:Source and MySQL if not disabled
63 if not self.hasMySql and env == 'MYSQL5':
65 path = self.ResolveEnvPath(env, envvars[env])
67 raise Exception('Could not find a valid path for {0}'.format(env))
68 AMBuild.cache.CacheVariable(env, path)
70 #Look for SDK directories
71 for sdk in self.possibleSdks:
72 #Get list of SDKs to build against or 'all' or 'present'
73 sdkList = AMBuild.options.sdks.split(',')
74 #Build against all supported SDKs?
75 useAll = sdkList[0] == 'all'
76 #Build against supported SDKs that exist?
77 usePresent = sdkList[0] == 'present'
79 info = self.possibleSdks[sdk]
80 if AMBuild.target['platform'] in info['platform']:
83 sdkPath = self.ResolveEnvPath(env, dir)
85 if useAll or sdk in sdkList:
86 raise Exception('Could not find a valid path for {0}'.format(env))
89 if useAll or usePresent or sdk in sdkList:
90 self.sdkInfo[sdk] = info
91 AMBuild.cache.CacheVariable(env, sdkPath)
93 if len(self.sdkInfo) < 1:
94 raise Exception('At least one SDK must be available.')
96 AMBuild.cache.CacheVariable('sdkInfo', self.sdkInfo)
99 cxx = self.compiler.cxx
100 if isinstance(cxx, Cpp.CompatGCC):
101 if isinstance(cxx, Cpp.GCC):
103 elif isinstance(cxx, Cpp.Clang):
104 self.vendor = 'clang'
105 self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp')
106 self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp')
107 self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf')
108 self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf')
109 self.compiler.AddToListVar('CFLAGS', '-pipe')
110 self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing')
111 if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang':
112 self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden')
113 self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden')
114 self.compiler.AddToListVar('CFLAGS', '-Wall')
115 self.compiler.AddToListVar('CFLAGS', '-Werror')
116 self.compiler.AddToListVar('CFLAGS', '-Wno-uninitialized')
117 self.compiler.AddToListVar('CFLAGS', '-Wno-unused')
118 self.compiler.AddToListVar('CFLAGS', '-Wno-switch')
119 self.compiler.AddToListVar('CFLAGS', '-msse')
120 self.compiler.AddToListVar('CFLAGS', '-m32')
121 self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
122 self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
123 self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics')
124 self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor')
125 self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual')
126 if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 7) or \
127 (self.vendor == 'clang' and cxx.majorVersion >= 3):
128 self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor')
129 self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H')
130 self.compiler.AddToListVar('CDEFINES', 'GNUC')
131 if self.vendor == 'gcc':
132 self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
133 elif isinstance(cxx, Cpp.MSVC):
135 if AMBuild.options.debug == '1':
136 self.compiler.AddToListVar('CFLAGS', '/MTd')
137 self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt')
139 self.compiler.AddToListVar('CFLAGS', '/MT')
140 self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE')
141 self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS')
142 self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE')
143 self.compiler.AddToListVar('CXXFLAGS', '/EHsc')
144 self.compiler.AddToListVar('CXXFLAGS', '/GR-')
145 self.compiler.AddToListVar('CFLAGS', '/W3')
146 self.compiler.AddToListVar('CFLAGS', '/nologo')
147 self.compiler.AddToListVar('CFLAGS', '/Zi')
148 self.compiler.AddToListVar('CXXFLAGS', '/TP')
149 self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG')
150 self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86')
151 self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS')
152 self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib')
153 self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib')
154 self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib')
155 self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib')
156 self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib')
157 self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib')
158 self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib')
159 self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib')
160 self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib')
161 self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib')
162 self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib')
163 self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib')
166 if AMBuild.options.opt == '1':
167 self.compiler.AddToListVar('CDEFINES', 'NDEBUG')
168 if self.vendor == 'gcc' or self.vendor == 'clang':
169 self.compiler.AddToListVar('CFLAGS', '-O3')
170 elif self.vendor == 'msvc':
171 self.compiler.AddToListVar('CFLAGS', '/Ox')
172 self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF')
173 self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF')
176 if AMBuild.options.debug == '1':
177 self.compiler.AddToListVar('CDEFINES', 'DEBUG')
178 self.compiler.AddToListVar('CDEFINES', '_DEBUG')
179 if self.vendor == 'gcc' or self.vendor == 'clang':
180 self.compiler.AddToListVar('CFLAGS', '-g3')
181 elif self.vendor == 'msvc':
182 self.compiler.AddToListVar('CFLAGS', '/Od')
183 self.compiler.AddToListVar('CFLAGS', '/RTC1')
186 if AMBuild.target['platform'] == 'linux':
187 self.compiler.AddToListVar('CDEFINES', '_LINUX')
188 if self.vendor == 'gcc':
189 self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc')
190 if self.vendor == 'clang':
191 self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh')
192 elif AMBuild.target['platform'] == 'darwin':
193 self.compiler.AddToListVar('CDEFINES', 'OSX')
194 self.compiler.AddToListVar('CDEFINES', '_OSX')
195 self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5')
196 self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386'])
197 self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++')
199 # For OS X dylib versioning
201 productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r')
202 productContents = productFile.read()
204 m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
206 self.version = '1.0.0'
208 major, minor, release = m.groups()
209 self.version = '{0}.{1}.{2}'.format(major, minor, release)
210 AMBuild.cache.CacheVariable('version', self.version)
211 elif AMBuild.target['platform'] == 'windows':
212 self.compiler.AddToListVar('CDEFINES', 'WIN32')
213 self.compiler.AddToListVar('CDEFINES', '_WINDOWS')
216 self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD')
217 self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD')
218 self.compiler.AddToListVar('CINCLUDES',
219 os.path.join(AMBuild.outputFolder, 'includes'))
220 self.compiler.ToConfig(AMBuild, 'compiler')
221 AMBuild.cache.CacheVariable('vendor', self.vendor)
223 AMBuild.cache.CacheVariable('targetMap', self.targetMap)
225 self.sdkInfo = AMBuild.cache['sdkInfo']
226 self.compiler.FromConfig(AMBuild, 'compiler')
227 self.targetMap = AMBuild.cache['targetMap']
228 self.hasMySql = AMBuild.cache['hasMySql']
230 if AMBuild.target['platform'] == 'windows':
231 self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'public'))
232 self.compiler.AddToListVar('RCINCLUDES',
233 os.path.join(AMBuild.outputFolder, 'includes'))
234 self.mmsPath = AMBuild.cache['MMSOURCE19']
236 def DefaultCompiler(self):
237 return self.compiler.Clone()
239 def JobMatters(self, jobname):
240 file = sys._getframe().f_code.co_filename
241 if AMBuild.mode == 'config':
242 self.targetMap[jobname] = file
244 if len(AMBuild.args) == 0:
246 if not jobname in AMBuild.args:
249 def DefaultExtCompiler(self, path):
250 compiler = self.DefaultCompiler()
251 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path))
252 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, path, 'sdk'))
253 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public'))
254 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'extensions'))
255 compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'public', 'sourcepawn'))
258 def AutoVersion(self, folder, binary):
259 if AMBuild.target['platform'] == 'windows':
260 env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']}
261 binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env)
262 elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder):
263 binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0'])
264 binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']])
268 def PreSetupHL2Job(self, job, builder, sdk):
269 info = self.sdkInfo[sdk]
270 sdkPath = AMBuild.cache[info['sdk']]
271 if AMBuild.target['platform'] == 'linux':
273 staticLibs = os.path.join(sdkPath, 'linux_sdk')
275 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
276 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
277 if sdk in ['ep2v', 'css']:
278 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib_srv.so', 'libtier0_srv.so']
280 link = os.path.join(workFolder, lib)
281 target = os.path.join(staticLibs, lib)
285 job.AddCommand(SymlinkCommand(link, target))
286 elif sdk in ['l4d', 'l4d2', 'csgo']:
287 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.so', 'libtier0.so']
289 libs.append('interfaces_i486.a')
291 link = os.path.join(workFolder, lib)
292 target = os.path.join(staticLibs, lib)
296 job.AddCommand(SymlinkCommand(link, target))
298 libs = ['tier1_i486.a', 'mathlib_i486.a', 'vstdlib_i486.so', 'tier0_i486.so']
300 link = os.path.join(workFolder, lib)
301 target = os.path.join(staticLibs, lib)
305 job.AddCommand(SymlinkCommand(link, target))
306 elif AMBuild.target['platform'] == 'darwin':
307 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
308 workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
309 libs = ['tier1_i486.a', 'mathlib_i486.a', 'libvstdlib.dylib', 'libtier0.dylib']
311 libs.append('interfaces_i486.a')
313 link = os.path.join(workFolder, lib)
314 target = os.path.join(staticLibs, lib)
318 job.AddCommand(SymlinkCommand(link, target))
319 elif AMBuild.target['platform'] == 'windows':
320 libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
321 if sdk in ['swarm', 'csgo']:
322 libs.append('interfaces')
324 libPath = os.path.join(sdkPath, 'lib', 'public', lib) + '.lib'
325 builder.RebuildIfNewer(libPath)
326 builder['POSTLINKFLAGS'].append(libPath)
328 def PostSetupHL2Job(self, job, builder, sdk):
329 if AMBuild.target['platform'] in ['linux', 'darwin']:
330 builder.AddObjectFiles(['tier1_i486.a', 'mathlib_i486.a'])
332 builder.AddObjectFiles(['interfaces_i486.a'])
334 def DefaultHL2Compiler(self, path, sdk, noLink = False, oldMms = '-legacy'):
335 compiler = self.DefaultExtCompiler(path)
341 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms))
342 compiler['CXXINCLUDES'].append(os.path.join(self.mmsPath, mms, 'sourcehook'))
344 info = self.possibleSdks
345 compiler['CDEFINES'].extend(['SE_' + info[i]['name'] + '=' + info[i]['def'] for i in info])
347 # We don't build for Portal 2 (yet?, ever?), but using this define in code as
348 # it saves trouble if we ever need to
349 compiler['CDEFINES'].append('SE_PORTAL2=11')
351 paths = [['public'], ['public', 'engine'], ['public', 'mathlib'], ['public', 'vstdlib'],
352 ['public', 'tier0'], ['public', 'tier1']]
353 if sdk == 'ep1' or sdk == 'darkm':
354 paths.append(['public', 'dlls'])
355 paths.append(['game_shared'])
357 paths.append(['public', 'game', 'server'])
358 paths.append(['public', 'toolframework'])
359 paths.append(['game', 'shared'])
360 paths.append(['common'])
362 info = self.sdkInfo[sdk]
363 sdkPath = AMBuild.cache[info['sdk']]
365 compiler['CDEFINES'].append('SOURCE_ENGINE=' + info['def'])
367 if sdk in ['swarm','csgo']:
368 if AMBuild.target['platform'] == 'windows':
369 compiler['CDEFINES'].extend(['COMPILER_MSVC', 'COMPILER_MSVC32'])
371 compiler['CDEFINES'].extend(['COMPILER_GCC', 'POSIX'])
374 if AMBuild.target['platform'] == 'linux':
375 staticLibs = os.path.join(sdkPath, 'linux_sdk')
377 if AMBuild.target['platform'] == 'linux':
378 staticLibs = os.path.join(sdkPath, 'lib', 'linux')
379 elif AMBuild.target['platform'] == 'darwin':
380 staticLibs = os.path.join(sdkPath, 'lib', 'mac')
383 compiler['CXXINCLUDES'].append(os.path.join(sdkPath, *i))
386 if AMBuild.target['platform'] == 'linux':
387 compiler['POSTLINKFLAGS'][0:0] = ['-lm']
388 if sdk in ['ep2v', 'css']:
389 compiler['POSTLINKFLAGS'][0:0] = ['libtier0_srv.so']
390 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib_srv.so']
391 elif sdk in ['l4d', 'l4d2', 'csgo']:
392 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
393 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
395 compiler['POSTLINKFLAGS'][0:0] = ['tier0_i486.so']
396 compiler['POSTLINKFLAGS'][0:0] = ['vstdlib_i486.so']
397 elif AMBuild.target['platform'] == 'darwin':
398 compiler['POSTLINKFLAGS'][0:0] = ['libtier0.dylib']
399 compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.dylib']
403 def ResolveEnvPath(self, env, defaultDir):
404 if env in os.environ:
405 path = os.environ[env]
406 if os.path.isdir(path):
411 while head != None and head != oldhead:
412 path = os.path.join(head, defaultDir)
413 if os.path.isdir(path):
416 head, tail = os.path.split(head)
424 AMBuild.Include(os.path.join('tools', 'buildbot', 'Versioning'), globals)
427 ['loader', 'AMBuilder'],
428 ['core', 'AMBuilder'],
429 ['core', 'logic', 'AMBuilder'],
430 ['extensions', 'bintools', 'AMBuilder'],
431 ['extensions', 'clientprefs', 'AMBuilder'],
432 ['extensions', 'cstrike', 'AMBuilder'],
433 ['extensions', 'curl', 'AMBuilder'],
434 ['extensions', 'geoip', 'AMBuilder'],
435 ['extensions', 'mysql', 'AMBuilder'],
436 ['extensions', 'sdkhooks', 'AMBuilder'],
437 ['extensions', 'sdktools', 'AMBuilder'],
438 ['extensions', 'topmenus', 'AMBuilder'],
439 ['extensions', 'updater', 'AMBuilder'],
440 ['extensions', 'sqlite', 'AMBuilder'],
441 ['extensions', 'regex', 'AMBuilder'],
442 ['extensions', 'tf2', 'AMBuilder'],
443 ['sourcepawn', 'jit', 'AMBuilder'],
444 ['sourcepawn', 'compiler', 'AMBuilder'],
445 ['plugins', 'AMBuilder'],
446 ['tools', 'buildbot', 'PackageScript'],
447 ['tools', 'buildbot', 'BreakpadSymbols']
451 FileList.remove(['extensions', 'mysql', 'AMBuilder'])
453 for parts in FileList:
454 AMBuild.Include(os.path.join(*parts), globals)