2 # http://scons.sourceforge.net
4 import commands, re, sys, os, pickle, string, popen2
5 from makeversion import radiant_makeversion, get_version
7 # to access some internal stuff
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', 'SETUP']
15 # help -------------------------------------------
18 Usage: scons [OPTIONS] [TARGET] [CONFIG]
20 [OPTIONS] and [TARGET] are covered in command line options, use scons -H
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
28 Specify C and C++ compilers (defaults gcc and g++)
30 You can use ccache and distcc, for instance:
31 CC="ccache distcc gcc" CXX="ccache distcc g++"
35 ex: JOBS="4" is a good setting on SMP machines
38 Use debug/release to select build settings
39 ex: BUILD="release" - default is debug
43 # end help ---------------------------------------
45 # sanity -----------------------------------------
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)
52 EnsureSConsVersion( 0, 96 )
53 print 'SCons ' + SCons.__version__
55 # end sanity -------------------------------------
57 # system detection -------------------------------
59 # TODO: detect Darwin / OSX
62 g_cpu = commands.getoutput('uname -m')
63 exp = re.compile('.*i?86.*')
64 if (g_cpu == 'Power Macintosh' or g_cpu == 'ppc'):
66 elif exp.match(g_cpu):
72 OS = commands.getoutput('uname')
73 print "OS=\"" + OS + "\""
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')
79 # end system detection ---------------------------
81 # default settings -------------------------------
89 g_build_root = 'build'
91 # end default settings ---------------------------
93 # site settings ----------------------------------
96 if (os.path.exists(conf_filename)):
97 site_file = open(conf_filename, 'r')
98 p = pickle.Unpickler(site_file)
100 print 'Loading build configuration from ' + conf_filename
101 for k, v in site_dict.items():
102 exec_cmd = k + '=\"' + v + '\"'
106 # end site settings ------------------------------
108 # command line settings --------------------------
111 if (ARGUMENTS.has_key(k)):
112 exec_cmd = k + '=\"' + ARGUMENTS[k] + '\"'
113 print 'Command line: ' + exec_cmd
116 # end command line settings ----------------------
118 # sanity check -----------------------------------
120 if (SETUP == '1' and BUILD != 'release' and BUILD != 'info'):
121 print 'Forcing release build for setup'
124 def GetGCCVersion(name):
125 ret = commands.getstatusoutput('%s -dumpversion' % name)
128 vers = string.split(ret[1], '.')
129 if ( len(vers) == 2 ):
130 return [ vers[0], vers[1], 0 ]
131 elif ( len(vers) == 3 ):
135 ver_cc = GetGCCVersion(CC)
136 ver_cxx = GetGCCVersion(CXX)
138 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 ):
139 print 'Compiler version check failed - need gcc 3.x or later:'
140 print 'CC: %s %s\nCXX: %s %s' % ( CC, repr(ver_cc), CXX, repr(ver_cxx) )
143 # end sanity check -------------------------------
145 # save site configuration ----------------------
148 exec_cmd = 'site_dict[\'' + k + '\'] = ' + k
151 site_file = open(conf_filename, 'w')
152 p = pickle.Pickler(site_file)
156 # end save site configuration ------------------
158 # general configuration, target selection --------
160 SConsignFile( "scons.signatures" )
162 g_build = g_build_root + '/' + BUILD
164 SetOption('num_jobs', JOBS)
168 warningFlags = '-W -Wall -Wcast-align -Wcast-qual -Wno-unused-parameter '
169 warningFlagsCXX = '-Wno-non-virtual-dtor -Wreorder ' # -Wold-style-cast
170 CCFLAGS = '' + warningFlags
171 CXXFLAGS = '-pipe -DQ_NO_STLPORT ' + warningFlags + warningFlagsCXX
173 if (BUILD == 'debug'):
174 CXXFLAGS += '-g -D_DEBUG '
175 CCFLAGS += '-g -D_DEBUG '
176 elif (BUILD == 'release'):
180 print 'Unknown build configuration ' + BUILD
184 if ( OS == 'Linux' ):
187 # 2112833 /opt/gtkradiant/radiant.x86
188 # 35282 /opt/gtkradiant/modules/archivezip.so
189 # 600099 /opt/gtkradiant/modules/entity.so
192 # 2237060 /opt/gtkradiant/radiant.x86
193 # 110605 /opt/gtkradiant/modules/archivezip.so
194 # 730222 /opt/gtkradiant/modules/entity.so
196 # EVIL HACK - force static-linking for libstdc++ - create a symbolic link to the static libstdc++ in the root
197 os.system("ln -s `g++ -print-file-name=libstdc++.a`")
199 #if not os.path.exists("./install"):
200 # os.mkdir("./install")
201 #os.system("cp `g++ -print-file-name=libstdc++.so` ./install")
203 CXXFLAGS += '-fno-exceptions -fno-rtti '
204 LINKFLAGS += '-Wl,-fini,fini_stub -L. -static-libgcc '
205 if ( OS == 'Darwin' ):
206 CCFLAGS += '-force_cpusubtype_ALL -fPIC '
207 CXXFLAGS += '-force_cpusubtype_ALL -fPIC -fno-exceptions -fno-rtti '
208 CPPPATH.append('/sw/include')
209 CPPPATH.append('/usr/X11R6/include')
210 LINKFLAGS += '-L/sw/lib -L/usr/lib -L/usr/X11R6/lib '
212 CPPPATH.append('libs')
214 # extend the standard Environment a bit
215 class idEnvironment(Environment):
218 Environment.__init__(self,
226 LINKFLAGS = LINKFLAGS)
229 self['CXXFLAGS'] += '`pkg-config glib-2.0 --cflags` '
230 self['CCFLAGS'] += '`pkg-config glib-2.0 --cflags` '
231 self['LINKFLAGS'] += '-lglib-2.0 '
234 self['CXXFLAGS'] += '`xml2-config --cflags` '
235 self['CCFLAGS'] += '`xml2-config --cflags` '
236 self['LINKFLAGS'] += '-lxml2 '
239 self['CXXFLAGS'] += '`pkg-config gtk+-2.0 --cflags` '
240 self['CCFLAGS'] += '`pkg-config gtk+-2.0 --cflags` '
241 self['LINKFLAGS'] += '-lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lpango-1.0 -lgdk_pixbuf-2.0 '
243 def useGtkGLExt(self):
244 self['CXXFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` '
245 self['CCFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` '
246 self['LINKFLAGS'] += '-lgtkglext-x11-1.0 -lgdkglext-x11-1.0 '
249 self['CXXFLAGS'] += '`libpng-config --cflags` '
250 self['CCFLAGS'] += '`libpng-config --cflags` '
251 self['LINKFLAGS'] += '`libpng-config --ldflags` '
254 self['LINKFLAGS'] += '-lmhash '
257 self['LINKFLAGS'] += '-lz '
259 def usePThread(self):
260 if ( OS == 'Darwin' ):
261 self['LINKFLAGS'] += '-lpthread -Wl,-stack_size,0x400000 '
263 self['LINKFLAGS'] += '-lpthread '
265 def CheckLDD(self, target, source, env):
267 if (not os.path.isfile(file.abspath)):
268 print('ERROR: CheckLDD: target %s not found\n' % target[0])
270 # not using os.popen3 as I want to check the return code
271 ldd = popen2.Popen3('`which ldd` -r %s' % target[0], 1)
272 stdout_lines = ldd.fromchild.readlines()
273 stderr_lines = ldd.childerr.readlines()
278 print "ERROR: ldd command returned with exit code %d" % ldd_ret
279 os.system('rm %s' % target[0])
281 for i_line in stderr_lines:
283 regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)\n')
284 if ( regex.match(i_line) ):
285 symbol = regex.sub('\\1', i_line)
287 env['ALLOWED_SYMBOLS'].index(symbol)
291 print "ERROR: failed to parse ldd stderr line: %s" % i_line
292 os.system('rm %s' % target[0])
295 print "ERROR: undefined symbols"
296 os.system('rm %s' % target[0])
299 def SharedLibrarySafe(self, target, source, LIBS=[], LIBPATH='.'):
300 result = self.SharedLibrary(target, source, LIBS=LIBS, LIBPATH=LIBPATH)
302 AddPostAction(target + '.so', self.CheckLDD)
305 g_env = idEnvironment()
308 GLOBALS = 'g_env INSTALL SETUP g_cpu'
310 radiant_makeversion('\\ngcc version: %s.%s.%s' % ( ver_cc[0], ver_cc[1], ver_cc[2] ) )
312 # end general configuration ----------------------
314 # targets ----------------------------------------
318 Export('GLOBALS ' + GLOBALS)
319 BuildDir(g_build, '.', duplicate = 0)
320 SConscript(g_build + '/SConscript')
322 # end targets ------------------------------------