| 1 |
# scons build script |
|---|
| 2 |
# http://scons.sourceforge.net |
|---|
| 3 |
|
|---|
| 4 |
import commands, re, sys, os, pickle, string, popen2 |
|---|
| 5 |
from makeversion import radiant_makeversion, get_version |
|---|
| 6 |
|
|---|
| 7 |
# to access some internal stuff |
|---|
| 8 |
import SCons |
|---|
| 9 |
|
|---|
| 10 |
conf_filename='site.conf' |
|---|
| 11 |
# there is a default hardcoded value, you can override on command line, those are saved between runs |
|---|
| 12 |
# we only handle strings |
|---|
| 13 |
serialized=['CC', 'CXX', 'JOBS', 'BUILD'] |
|---|
| 14 |
|
|---|
| 15 |
# help ------------------------------------------- |
|---|
| 16 |
|
|---|
| 17 |
Help(""" |
|---|
| 18 |
Usage: scons [OPTIONS] [TARGET] [CONFIG] |
|---|
| 19 |
|
|---|
| 20 |
[OPTIONS] and [TARGET] are covered in command line options, use scons -H |
|---|
| 21 |
|
|---|
| 22 |
[CONFIG]: KEY="VALUE" [...] |
|---|
| 23 |
a number of configuration options saved between runs in the """ + conf_filename + """ file |
|---|
| 24 |
erase """ + conf_filename + """ to start with default settings again |
|---|
| 25 |
|
|---|
| 26 |
CC |
|---|
| 27 |
CXX |
|---|
| 28 |
Specify C and C++ compilers (defaults gcc and g++) |
|---|
| 29 |
ex: CC="gcc-3.2" |
|---|
| 30 |
You can use ccache and distcc, for instance: |
|---|
| 31 |
CC="ccache distcc gcc" CXX="ccache distcc g++" |
|---|
| 32 |
|
|---|
| 33 |
JOBS |
|---|
| 34 |
Parallel build |
|---|
| 35 |
ex: JOBS="4" is a good setting on SMP machines |
|---|
| 36 |
|
|---|
| 37 |
BUILD |
|---|
| 38 |
Use debug/release to select build settings |
|---|
| 39 |
ex: BUILD="debug" - default is debug |
|---|
| 40 |
""" |
|---|
| 41 |
) |
|---|
| 42 |
|
|---|
| 43 |
# end help --------------------------------------- |
|---|
| 44 |
|
|---|
| 45 |
# sanity ----------------------------------------- |
|---|
| 46 |
|
|---|
| 47 |
# get a recent python release |
|---|
| 48 |
# that is broken in current version: |
|---|
| 49 |
# http://sourceforge.net/tracker/index.php?func=detail&aid=794145&group_id=30337&atid=398971 |
|---|
| 50 |
#EnsurePythonVersion(2,1) |
|---|
| 51 |
# above 0.90 |
|---|
| 52 |
EnsureSConsVersion( 0, 96 ) |
|---|
| 53 |
print 'SCons ' + SCons.__version__ |
|---|
| 54 |
|
|---|
| 55 |
# end sanity ------------------------------------- |
|---|
| 56 |
|
|---|
| 57 |
# system detection ------------------------------- |
|---|
| 58 |
|
|---|
| 59 |
# TODO: detect Darwin / OSX |
|---|
| 60 |
|
|---|
| 61 |
# CPU type |
|---|
| 62 |
g_cpu = commands.getoutput('uname -m') |
|---|
| 63 |
exp = re.compile('.*i?86.*') |
|---|
| 64 |
if (g_cpu == 'Power Macintosh' or g_cpu == 'ppc'): |
|---|
| 65 |
g_cpu = 'ppc' |
|---|
| 66 |
elif exp.match(g_cpu): |
|---|
| 67 |
g_cpu = 'x86' |
|---|
| 68 |
else: |
|---|
| 69 |
g_cpu = 'cpu' |
|---|
| 70 |
|
|---|
| 71 |
# OS |
|---|
| 72 |
OS = commands.getoutput('uname') |
|---|
| 73 |
print "OS=\"" + OS + "\"" |
|---|
| 74 |
|
|---|
| 75 |
if (OS == 'Linux'): |
|---|
| 76 |
# libc .. do the little magic! |
|---|
| 77 |
libc = commands.getoutput('/lib/libc.so.6 |grep "GNU C "|grep version|awk -F "version " \'{ print $2 }\'|cut -b -3') |
|---|
| 78 |
|
|---|
| 79 |
# end system detection --------------------------- |
|---|
| 80 |
|
|---|
| 81 |
# default settings ------------------------------- |
|---|
| 82 |
|
|---|
| 83 |
CC='gcc' |
|---|
| 84 |
CXX='g++' |
|---|
| 85 |
JOBS='1' |
|---|
| 86 |
BUILD='debug' |
|---|
| 87 |
INSTALL='#install' |
|---|
| 88 |
g_build_root = 'build' |
|---|
| 89 |
|
|---|
| 90 |
# end default settings --------------------------- |
|---|
| 91 |
|
|---|
| 92 |
# site settings ---------------------------------- |
|---|
| 93 |
|
|---|
| 94 |
site_dict = {} |
|---|
| 95 |
if (os.path.exists(conf_filename)): |
|---|
| 96 |
site_file = open(conf_filename, 'r') |
|---|
| 97 |
p = pickle.Unpickler(site_file) |
|---|
| 98 |
site_dict = p.load() |
|---|
| 99 |
print 'Loading build configuration from ' + conf_filename |
|---|
| 100 |
for k, v in site_dict.items(): |
|---|
| 101 |
exec_cmd = k + '=\"' + v + '\"' |
|---|
| 102 |
print exec_cmd |
|---|
| 103 |
exec(exec_cmd) |
|---|
| 104 |
|
|---|
| 105 |
# end site settings ------------------------------ |
|---|
| 106 |
|
|---|
| 107 |
# command line settings -------------------------- |
|---|
| 108 |
|
|---|
| 109 |
for k in serialized: |
|---|
| 110 |
if (ARGUMENTS.has_key(k)): |
|---|
| 111 |
exec_cmd = k + '=\"' + ARGUMENTS[k] + '\"' |
|---|
| 112 |
print 'Command line: ' + exec_cmd |
|---|
| 113 |
exec(exec_cmd) |
|---|
| 114 |
|
|---|
| 115 |
# end command line settings ---------------------- |
|---|
| 116 |
|
|---|
| 117 |
# sanity check ----------------------------------- |
|---|
| 118 |
|
|---|
| 119 |
|
|---|
| 120 |
def GetGCCVersion(name): |
|---|
| 121 |
ret = commands.getstatusoutput('%s -dumpversion' % name) |
|---|
| 122 |
if ( ret[0] != 0 ): |
|---|
| 123 |
return None |
|---|
| 124 |
vers = string.split(ret[1], '.') |
|---|
| 125 |
if ( len(vers) == 2 ): |
|---|
| 126 |
return [ vers[0], vers[1], 0 ] |
|---|
| 127 |
elif ( len(vers) == 3 ): |
|---|
| 128 |
return vers |
|---|
| 129 |
return None |
|---|
| 130 |
|
|---|
| 131 |
ver_cc = GetGCCVersion(CC) |
|---|
| 132 |
ver_cxx = GetGCCVersion(CXX) |
|---|
| 133 |
|
|---|
| 134 |
if ( ver_cc is None or ver_cxx is None or ver_cc[0] < '3' or ver_cxx[0] < '3' or ver_cc != ver_cxx ): |
|---|
| 135 |
print 'Compiler version check failed - need gcc 3.x or later:' |
|---|
| 136 |
print 'CC: %s %s\nCXX: %s %s' % ( CC, repr(ver_cc), CXX, repr(ver_cxx) ) |
|---|
| 137 |
Exit(1) |
|---|
| 138 |
|
|---|
| 139 |
# end sanity check ------------------------------- |
|---|
| 140 |
|
|---|
| 141 |
# save site configuration ---------------------- |
|---|
| 142 |
|
|---|
| 143 |
for k in serialized: |
|---|
| 144 |
exec_cmd = 'site_dict[\'' + k + '\'] = ' + k |
|---|
| 145 |
exec(exec_cmd) |
|---|
| 146 |
|
|---|
| 147 |
site_file = open(conf_filename, 'w') |
|---|
| 148 |
p = pickle.Pickler(site_file) |
|---|
| 149 |
p.dump(site_dict) |
|---|
| 150 |
site_file.close() |
|---|
| 151 |
|
|---|
| 152 |
# end save site configuration ------------------ |
|---|
| 153 |
|
|---|
| 154 |
# general configuration, target selection -------- |
|---|
| 155 |
|
|---|
| 156 |
SConsignFile( "scons.signatures" ) |
|---|
| 157 |
|
|---|
| 158 |
g_build = g_build_root + '/' + BUILD |
|---|
| 159 |
|
|---|
| 160 |
SetOption('num_jobs', JOBS) |
|---|
| 161 |
|
|---|
| 162 |
LINK = CXX |
|---|
| 163 |
# common flags |
|---|
| 164 |
warningFlags = '-W -Wall -Wcast-align -Wcast-qual -Wno-unused-parameter ' |
|---|
| 165 |
warningFlagsCXX = '-Wno-non-virtual-dtor -Wreorder ' # -Wold-style-cast |
|---|
| 166 |
# POSIX macro: platform supports posix IEEE Std 1003.1:2001 |
|---|
| 167 |
# XWINDOWS macro: platform supports X-Windows API |
|---|
| 168 |
CCFLAGS = '-DPOSIX -DXWINDOWS ' + warningFlags |
|---|
| 169 |
CXXFLAGS = '-pipe -DPOSIX -DXWINDOWS ' + warningFlags + warningFlagsCXX |
|---|
| 170 |
CPPPATH = [] |
|---|
| 171 |
if (BUILD == 'debug'): |
|---|
| 172 |
CXXFLAGS += '-g3 -D_DEBUG ' |
|---|
| 173 |
CCFLAGS += '-g3 -D_DEBUG ' |
|---|
| 174 |
elif (BUILD == 'release' or BUILD == 'final'): |
|---|
| 175 |
CXXFLAGS += '-O2 ' |
|---|
| 176 |
CCFLAGS += '-O2 ' |
|---|
| 177 |
else: |
|---|
| 178 |
print 'Unknown build configuration ' + BUILD |
|---|
| 179 |
sys.exit( 0 ) |
|---|
| 180 |
|
|---|
| 181 |
LINKFLAGS = '' |
|---|
| 182 |
if ( OS == 'Linux' ): |
|---|
| 183 |
|
|---|
| 184 |
if ( BUILD == 'final' ): |
|---|
| 185 |
# static |
|---|
| 186 |
# 2112833 /opt/gtkradiant/radiant.x86 |
|---|
| 187 |
# 35282 /opt/gtkradiant/modules/archivezip.so |
|---|
| 188 |
# 600099 /opt/gtkradiant/modules/entity.so |
|---|
| 189 |
|
|---|
| 190 |
# dynamic |
|---|
| 191 |
# 2237060 /opt/gtkradiant/radiant.x86 |
|---|
| 192 |
# 110605 /opt/gtkradiant/modules/archivezip.so |
|---|
| 193 |
# 730222 /opt/gtkradiant/modules/entity.so |
|---|
| 194 |
|
|---|
| 195 |
# EVIL HACK - force static-linking for libstdc++ - create a symbolic link to the static libstdc++ in the root |
|---|
| 196 |
os.system("ln -s `g++ -print-file-name=libstdc++.a`") |
|---|
| 197 |
|
|---|
| 198 |
#if not os.path.exists("./install"): |
|---|
| 199 |
# os.mkdir("./install") |
|---|
| 200 |
#os.system("cp `g++ -print-file-name=libstdc++.so` ./install") |
|---|
| 201 |
|
|---|
| 202 |
# -fPIC might be worth removing when building for 32-bit x86 |
|---|
| 203 |
CCFLAGS += '-fPIC ' |
|---|
| 204 |
CXXFLAGS += '-fPIC -fno-exceptions -fno-rtti ' |
|---|
| 205 |
LINKFLAGS += '-fPIC -Wl,-fini,fini_stub -L. -static-libgcc ' |
|---|
| 206 |
|
|---|
| 207 |
if ( OS == 'Darwin' ): |
|---|
| 208 |
CCFLAGS += '-force_cpusubtype_ALL -fPIC ' |
|---|
| 209 |
CXXFLAGS += '-force_cpusubtype_ALL -fPIC -fno-exceptions -fno-rtti ' |
|---|
| 210 |
CPPPATH.append('/sw/include') |
|---|
| 211 |
CPPPATH.append('/usr/X11R6/include') |
|---|
| 212 |
LINKFLAGS += '-L/sw/lib -L/usr/lib -L/usr/X11R6/lib ' |
|---|
| 213 |
|
|---|
| 214 |
CPPPATH.append('libs') |
|---|
| 215 |
|
|---|
| 216 |
# extend the standard Environment a bit |
|---|
| 217 |
class idEnvironment(Environment): |
|---|
| 218 |
|
|---|
| 219 |
def __init__(self): |
|---|
| 220 |
Environment.__init__(self, |
|---|
| 221 |
ENV = os.environ, |
|---|
| 222 |
CC = CC, |
|---|
| 223 |
CXX = CXX, |
|---|
| 224 |
LINK = LINK, |
|---|
| 225 |
CCFLAGS = CCFLAGS, |
|---|
| 226 |
CXXFLAGS = CXXFLAGS, |
|---|
| 227 |
CPPPATH = CPPPATH, |
|---|
| 228 |
LINKFLAGS = LINKFLAGS) |
|---|
| 229 |
|
|---|
| 230 |
def useGlib2(self): |
|---|
| 231 |
self['CXXFLAGS'] += '`pkg-config glib-2.0 --cflags` ' |
|---|
| 232 |
self['CCFLAGS'] += '`pkg-config glib-2.0 --cflags` ' |
|---|
| 233 |
if BUILD == 'final': |
|---|
| 234 |
self['LINKFLAGS'] += '-lglib-2.0 ' |
|---|
| 235 |
else: |
|---|
| 236 |
self['LINKFLAGS'] += '`pkg-config glib-2.0 --libs` ' |
|---|
| 237 |
|
|---|
| 238 |
|
|---|
| 239 |
def useXML2(self): |
|---|
| 240 |
self['CXXFLAGS'] += '`xml2-config --cflags` ' |
|---|
| 241 |
self['CCFLAGS'] += '`xml2-config --cflags` ' |
|---|
| 242 |
if BUILD == 'final': |
|---|
| 243 |
self['LINKFLAGS'] += '-lxml2 ' |
|---|
| 244 |
else: |
|---|
| 245 |
self['LINKFLAGS'] += '`xml2-config --libs` ' |
|---|
| 246 |
|
|---|
| 247 |
def useGtk2(self): |
|---|
| 248 |
self['CXXFLAGS'] += '`pkg-config gtk+-2.0 --cflags` ' |
|---|
| 249 |
self['CCFLAGS'] += '`pkg-config gtk+-2.0 --cflags` ' |
|---|
| 250 |
if BUILD == 'final': |
|---|
| 251 |
self['LINKFLAGS'] += '-lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lpango-1.0 -lgdk_pixbuf-2.0 ' |
|---|
| 252 |
else: |
|---|
| 253 |
self['LINKFLAGS'] += '`pkg-config gtk+-2.0 --libs-only-L` `pkg-config gtk+-2.0 --libs-only-l` ' |
|---|
| 254 |
|
|---|
| 255 |
def useGtkGLExt(self): |
|---|
| 256 |
self['CXXFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` ' |
|---|
| 257 |
self['CCFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` ' |
|---|
| 258 |
#if BUILD == 'final': |
|---|
| 259 |
self['LINKFLAGS'] += '-lgtkglext-x11-1.0 -lgdkglext-x11-1.0 ' |
|---|
| 260 |
# apparently pkg-config for gtkglext includes --export-dynamic, which b0rks everything. |
|---|
| 261 |
#else: |
|---|
| 262 |
# self['LINKFLAGS'] += 'pkg-config gtkglext-1.0 --libs-only-L` `pkg-config gtkglext-1.0 --libs-only-l` ' |
|---|
| 263 |
|
|---|
| 264 |
def usePNG(self): |
|---|
| 265 |
self['CXXFLAGS'] += '`libpng-config --cflags` ' |
|---|
| 266 |
self['CCFLAGS'] += '`libpng-config --cflags` ' |
|---|
| 267 |
self['LINKFLAGS'] += '`libpng-config --ldflags` ' |
|---|
| 268 |
|
|---|
| 269 |
def useMHash(self): |
|---|
| 270 |
self['LINKFLAGS'] += '-lmhash ' |
|---|
| 271 |
|
|---|
| 272 |
def useZLib(self): |
|---|
| 273 |
self['LINKFLAGS'] += '-lz ' |
|---|
| 274 |
|
|---|
| 275 |
def usePThread(self): |
|---|
| 276 |
if ( OS == 'Darwin' ): |
|---|
| 277 |
self['LINKFLAGS'] += '-lpthread -Wl,-stack_size,0x400000 ' |
|---|
| 278 |
else: |
|---|
| 279 |
self['LINKFLAGS'] += '-lpthread ' |
|---|
| 280 |
|
|---|
| 281 |
def CheckLDD(self, target, source, env): |
|---|
| 282 |
file = target[0] |
|---|
| 283 |
if (not os.path.isfile(file.abspath)): |
|---|
| 284 |
print('ERROR: CheckLDD: target %s not found\n' % target[0]) |
|---|
| 285 |
Exit(1) |
|---|
| 286 |
# not using os.popen3 as I want to check the return code |
|---|
| 287 |
ldd = popen2.Popen3('`which ldd` -r %s' % target[0], 1) |
|---|
| 288 |
stdout_lines = ldd.fromchild.readlines() |
|---|
| 289 |
stderr_lines = ldd.childerr.readlines() |
|---|
| 290 |
ldd_ret = ldd.wait() |
|---|
| 291 |
del ldd |
|---|
| 292 |
have_undef = 0 |
|---|
| 293 |
if ( ldd_ret != 0 ): |
|---|
| 294 |
print "ERROR: ldd command returned with exit code %d" % ldd_ret |
|---|
| 295 |
os.system('rm %s' % target[0]) |
|---|
| 296 |
Exit() |
|---|
| 297 |
for i_line in stderr_lines: |
|---|
| 298 |
print repr(i_line) |
|---|
| 299 |
regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)\n') |
|---|
| 300 |
if ( regex.match(i_line) ): |
|---|
| 301 |
symbol = regex.sub('\\1', i_line) |
|---|
| 302 |
try: |
|---|
| 303 |
env['ALLOWED_SYMBOLS'].index(symbol) |
|---|
| 304 |
except: |
|---|
| 305 |
have_undef = 1 |
|---|
| 306 |
else: |
|---|
| 307 |
print "ERROR: failed to parse ldd stderr line: %s" % i_line |
|---|
| 308 |
os.system('rm %s' % target[0]) |
|---|
| 309 |
Exit(1) |
|---|
| 310 |
if ( have_undef ): |
|---|
| 311 |
print "ERROR: undefined symbols" |
|---|
| 312 |
os.system('rm %s' % target[0]) |
|---|
| 313 |
Exit(1) |
|---|
| 314 |
|
|---|
| 315 |
def SharedLibrarySafe(self, target, source, LIBS=[], LIBPATH='.'): |
|---|
| 316 |
result = self.SharedLibrary(target, source, LIBS=LIBS, LIBPATH=LIBPATH) |
|---|
| 317 |
if (OS != 'Darwin'): |
|---|
| 318 |
AddPostAction(target + '.so', self.CheckLDD) |
|---|
| 319 |
return result |
|---|
| 320 |
|
|---|
| 321 |
g_env = idEnvironment() |
|---|
| 322 |
|
|---|
| 323 |
# export the globals |
|---|
| 324 |
GLOBALS = 'g_env INSTALL g_cpu' |
|---|
| 325 |
|
|---|
| 326 |
radiant_makeversion('\\ngcc version: %s.%s.%s' % ( ver_cc[0], ver_cc[1], ver_cc[2] ) ) |
|---|
| 327 |
|
|---|
| 328 |
# end general configuration ---------------------- |
|---|
| 329 |
|
|---|
| 330 |
# targets ---------------------------------------- |
|---|
| 331 |
|
|---|
| 332 |
Default('.') |
|---|
| 333 |
|
|---|
| 334 |
Export('GLOBALS ' + GLOBALS) |
|---|
| 335 |
BuildDir(g_build, '.', duplicate = 0) |
|---|
| 336 |
SConscript(g_build + '/SConscript') |
|---|
| 337 |
|
|---|
| 338 |
# end targets ------------------------------------ |
|---|