create a branch for AB sync
[xonotic/netradiant.git] / SConstruct
1 # scons build script\r
2 # http://scons.sourceforge.net\r
3 \r
4 import commands, re, sys, os, pickle, string, popen2\r
5 from makeversion import radiant_makeversion, get_version\r
6 from osx_setup import do_osx_setup\r
7 \r
8 # to access some internal stuff\r
9 import SCons\r
10 \r
11 conf_filename='site.conf'\r
12 # there is a default hardcoded value, you can override on command line, those are saved between runs\r
13 # we only handle strings\r
14 serialized=['CC', 'CXX', 'JOBS', 'BUILD', 'SETUP']\r
15 \r
16 # help -------------------------------------------\r
17 \r
18 Help("""\r
19 Usage: scons [OPTIONS] [TARGET] [CONFIG]\r
20 \r
21 [OPTIONS] and [TARGET] are covered in command line options, use scons -H\r
22 \r
23 [CONFIG]: KEY="VALUE" [...]\r
24 a number of configuration options saved between runs in the """ + conf_filename + """ file\r
25 erase """ + conf_filename + """ to start with default settings again\r
26 \r
27 CC\r
28 CXX\r
29         Specify C and C++ compilers (defaults gcc and g++)\r
30         ex: CC="gcc-3.2"\r
31         You can use ccache and distcc, for instance:\r
32         CC="ccache distcc gcc" CXX="ccache distcc g++"\r
33 \r
34 JOBS\r
35         Parallel build\r
36         ex: JOBS="4" is a good setting on SMP machines\r
37 \r
38 BUILD\r
39         Use debug/release to select build settings\r
40         ex: BUILD="release" - default is debug\r
41         OSX: use BUILD="info" to generate the set of release files\r
42 \r
43 SETUP\r
44   Build a setup - default 0\r
45 """\r
46 )\r
47 \r
48 # end help ---------------------------------------\r
49   \r
50 # sanity -----------------------------------------\r
51 \r
52 # use q decently recent python release\r
53 EnsurePythonVersion( 2, 1 )\r
54 # above 0.90\r
55 EnsureSConsVersion( 0, 95 )\r
56 print 'SCons ' + SCons.__version__\r
57 \r
58 # end sanity -------------------------------------\r
59 \r
60 # system detection -------------------------------\r
61 \r
62 # CPU type\r
63 g_cpu = commands.getoutput('uname -m')\r
64 exp = re.compile('.*i?86.*')\r
65 if (g_cpu == 'Power Macintosh'):\r
66   g_cpu = 'ppc'\r
67 elif exp.match(g_cpu):\r
68   g_cpu = 'x86'\r
69 else:\r
70   g_cpu = 'cpu'\r
71 \r
72 # OS\r
73 OS = commands.getoutput('uname')\r
74 \r
75 if (OS == 'Linux'):\r
76   # libc .. do the little magic!\r
77   # NOTE: this used to work fine up to libc 2.3\r
78   libc = commands.getoutput('/lib/libc.so.6 |grep "GNU C "|grep version|awk -F "version " \'{ print $2 }\'|cut -b -3')\r
79 \r
80 # end system detection ---------------------------\r
81 \r
82 # default settings -------------------------------\r
83 \r
84 CC='gcc'\r
85 CXX='g++'\r
86 JOBS='1'\r
87 BUILD='debug'\r
88 INSTALL='#install'\r
89 SETUP='0'\r
90 g_build_root = 'build'\r
91 \r
92 # end default settings ---------------------------\r
93 \r
94 # site settings ----------------------------------\r
95 \r
96 site_dict = {}\r
97 if (os.path.exists(conf_filename)):\r
98         site_file = open(conf_filename, 'r')\r
99         p = pickle.Unpickler(site_file)\r
100         site_dict = p.load()\r
101         print 'Loading build configuration from ' + conf_filename\r
102         for k, v in site_dict.items():\r
103                 exec_cmd = k + '=\"' + v + '\"'\r
104                 print exec_cmd\r
105                 exec(exec_cmd)\r
106 \r
107 # end site settings ------------------------------\r
108 \r
109 # command line settings --------------------------\r
110 \r
111 for k in serialized:\r
112         if (ARGUMENTS.has_key(k)):\r
113                 exec_cmd = k + '=\"' + ARGUMENTS[k] + '\"'\r
114                 print 'Command line: ' + exec_cmd\r
115                 exec(exec_cmd)\r
116 \r
117 # end command line settings ----------------------\r
118 \r
119 # sanity check -----------------------------------\r
120 \r
121 if (SETUP == '1' and BUILD != 'release' and BUILD != 'info'):\r
122   print 'Forcing release build for setup'\r
123   BUILD = 'release'\r
124 \r
125 def GetGCCVersion(name):\r
126   ret = commands.getstatusoutput('%s -dumpversion' % name)\r
127   if ( ret[0] != 0 ):\r
128     return None\r
129   vers = string.split(ret[1], '.')\r
130   if ( len(vers) == 2 ):\r
131     return [ vers[0], vers[1], 0 ]\r
132   elif ( len(vers) == 3 ):\r
133     return vers\r
134   return None\r
135 \r
136 ver_cc = GetGCCVersion(CC)\r
137 ver_cxx = GetGCCVersion(CXX)\r
138 \r
139 # end sanity check -------------------------------\r
140 \r
141 # save site configuration ----------------------\r
142 \r
143 for k in serialized:\r
144         exec_cmd = 'site_dict[\'' + k + '\'] = ' + k\r
145         exec(exec_cmd)\r
146 \r
147 site_file = open(conf_filename, 'w')\r
148 p = pickle.Pickler(site_file)\r
149 p.dump(site_dict)\r
150 site_file.close()\r
151 \r
152 # end save site configuration ------------------\r
153 \r
154 # general configuration, target selection --------\r
155 \r
156 SConsignFile( "scons.signatures" )\r
157 \r
158 g_build = g_build_root + '/' + BUILD\r
159 \r
160 SetOption('num_jobs', JOBS)\r
161 \r
162 LINK = CXX\r
163 # common flags\r
164 CCFLAGS = ''\r
165 CXXFLAGS = '-pipe -DQ_NO_STLPORT '\r
166 CPPPATH = []\r
167 if (BUILD == 'debug'):\r
168         CXXFLAGS += '-g -D_DEBUG '\r
169         CCFLAGS += '-g -D_DEBUG '\r
170 elif (BUILD == 'release'):\r
171         CXXFLAGS += '-g -O2 '\r
172         CCFLAGS += '-g -O2 '\r
173 elif ( BUILD == 'info' ):\r
174         print 'Preparing OSX release'\r
175         ( line, major, minor ) = get_version()\r
176         do_osx_setup( major, minor, 'osx-radiant-%s.run' % line )\r
177         sys.exit( 0 )\r
178 else:\r
179         print 'Unknown build configuration ' + BUILD\r
180         sys.exit( 0 )\r
181 \r
182 LINKFLAGS = ''\r
183 if ( OS == 'Linux' ):\r
184   LINKFLAGS += '-Wl,-fini,fini_stub '\r
185 if ( OS == 'Darwin' ):\r
186   CCFLAGS += '-force_cpusubtype_ALL -fPIC '\r
187   CXXFLAGS += '-force_cpusubtype_ALL -fPIC -fno-exceptions -fno-rtti '\r
188   CPPPATH.append('/sw/include')\r
189   CPPPATH.append('/usr/X11R6/include')\r
190   LINKFLAGS += '-L/sw/lib -L/usr/lib -L/usr/X11R6/lib '\r
191 \r
192 CPPPATH.append('libs')\r
193 \r
194 # extend the standard Environment a bit\r
195 class idEnvironment(Environment):\r
196 \r
197   def useGlib2(self):\r
198     self['CXXFLAGS'] += '`pkg-config glib-2.0 --cflags` '\r
199     self['CCFLAGS'] += '`pkg-config glib-2.0 --cflags` '\r
200     self['LINKFLAGS'] += '`pkg-config glib-2.0 --libs` '\r
201     \r
202   def useXML2(self):\r
203     self['CXXFLAGS'] += '`xml2-config --cflags` '      \r
204     self['CCFLAGS'] += '`xml2-config --cflags` '      \r
205     self['LINKFLAGS'] += '`xml2-config --libs` '\r
206 \r
207   def useGtk2(self):\r
208     self['CXXFLAGS'] += '`pkg-config gtk+-2.0 --cflags` '\r
209     self['CCFLAGS'] += '`pkg-config gtk+-2.0 --cflags` '\r
210     self['LINKFLAGS'] += '`pkg-config gtk+-2.0 --libs-only-L` `pkg-config gtk+-2.0 --libs-only-l` '\r
211    \r
212   def useGtkGLExt(self):\r
213     self['CXXFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` '\r
214     self['CCFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` '\r
215     self['LINKFLAGS'] += '`pkg-config gtkglext-1.0 --libs-only-L` `pkg-config gtkglext-1.0 --libs-only-l` '      \r
216     \r
217   def usePNG(self):\r
218     self['CXXFLAGS'] += '`libpng-config --cflags` '\r
219     self['CCFLAGS'] += '`libpng-config --cflags` '\r
220     self['LINKFLAGS'] += '`libpng-config --ldflags` '\r
221 \r
222   def usePThread(self):\r
223     if ( OS == 'Darwin' ):\r
224       self['LINKFLAGS'] += '-lpthread -Wl,-stack_size,0x400000 '\r
225     else:\r
226       self['LINKFLAGS'] += '-lpthread '\r
227 \r
228   def CheckLDD(self, target, source, env):\r
229     file = target[0]\r
230     if (not os.path.isfile(file.abspath)):\r
231         print('ERROR: CheckLDD: target %s not found\n' % target[0])\r
232         Exit(1)\r
233     # not using os.popen3 as I want to check the return code\r
234     ldd = popen2.Popen3('`which ldd` -r %s' % target[0], 1)\r
235     stdout_lines = ldd.fromchild.readlines()\r
236     stderr_lines = ldd.childerr.readlines()\r
237     ldd_ret = ldd.wait()\r
238     del ldd\r
239     have_undef = 0\r
240     if ( ldd_ret != 0 ):\r
241         print "ERROR: ldd command returned with exit code %d" % ldd_ret\r
242         os.system('rm %s' % target[0])\r
243         Exit()\r
244     for i_line in stderr_lines:\r
245         print repr(i_line)\r
246         regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)\n')\r
247         if ( regex.match(i_line) ):\r
248             symbol = regex.sub('\\1', i_line)\r
249             try:\r
250                 env['ALLOWED_SYMBOLS'].index(symbol)\r
251             except:\r
252                 have_undef = 1\r
253         else:\r
254             print "ERROR: failed to parse ldd stderr line: %s" % i_line\r
255             os.system('rm %s' % target[0])\r
256             Exit(1)\r
257     if ( have_undef ):\r
258         print "ERROR: undefined symbols"\r
259         os.system('rm %s' % target[0])\r
260         Exit(1)\r
261   \r
262   def SharedLibrarySafe(self, target, source):\r
263     self.SharedLibrary(target, source)\r
264     if (OS != 'Darwin'):\r
265       AddPostAction(target + '.so', self.CheckLDD)\r
266 \r
267 g_env = idEnvironment(ENV = os.environ, \r
268   CC = CC,\r
269   CXX = CXX,\r
270   LINK = LINK,\r
271   CCFLAGS = CCFLAGS,\r
272   CXXFLAGS = CXXFLAGS,\r
273   CPPPATH = CPPPATH,\r
274   LINKFLAGS = LINKFLAGS)\r
275 \r
276 # export the globals\r
277 GLOBALS = 'g_env INSTALL SETUP g_cpu'\r
278 \r
279 radiant_makeversion('\\ngcc version: %s.%s.%s' % ( ver_cc[0], ver_cc[1], ver_cc[2] ) )\r
280 \r
281 # end general configuration ----------------------\r
282 \r
283 # targets ----------------------------------------\r
284 \r
285 Default('.')\r
286 \r
287 Export('GLOBALS ' + GLOBALS)\r
288 BuildDir(g_build, '.', duplicate = 0)\r
289 SConscript(g_build + '/SConscript')\r
290 \r
291 # end targets ------------------------------------\r