SConstruct: split the functionality of the DEBUG option. DEBUG_BUILD (default: false...
[ffado.git] / libffado / SConstruct
bloba7ca8a2d9b3e7a6dad074ce37aa1983c3ae5534e
1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007, 2008, 2010 Arnold Krille
4 # Copyright (C) 2007, 2008 Pieter Palmers
5 # Copyright (C) 2008, 2012 Jonathan Woithe
7 # This file is part of FFADO
8 # FFADO = Free Firewire (pro-)audio drivers for linux
10 # FFADO is based upon FreeBoB.
12 # This program is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation, either version 2 of the License, or
15 # (at your option) version 3 of the License.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 FFADO_API_VERSION = "9"
27 FFADO_VERSION="2.1.9999"
29 from subprocess import Popen, PIPE
30 import os
31 import re
32 from string import Template
33 import imp
34 import distutils.sysconfig
36 if not os.path.isdir( "cache" ):
37 os.makedirs( "cache" )
39 opts = Variables( "cache/options.cache" )
41 opts.AddVariables(
42 BoolVariable( "DEBUG_BUILD", "Build with \"-g -Wall\" rather than \"-O2\"", False ),
43 BoolVariable( "DEBUG", "Enable support for debug messages", True ),
44 BoolVariable( "PROFILE", "Build with symbols and other profiling info", False ),
45 PathVariable( "PREFIX", "The prefix where ffado will be installed to.", "/usr/local", PathVariable.PathAccept ),
46 PathVariable( "BINDIR", "Overwrite the directory where apps are installed to.", "$PREFIX/bin", PathVariable.PathAccept ),
47 PathVariable( "LIBDIR", "Overwrite the directory where libs are installed to.", "$PREFIX/lib", PathVariable.PathAccept ),
48 PathVariable( "INCLUDEDIR", "Overwrite the directory where headers are installed to.", "$PREFIX/include", PathVariable.PathAccept ),
49 PathVariable( "SHAREDIR", "Overwrite the directory where misc shared files are installed to.", "$PREFIX/share/libffado", PathVariable.PathAccept ),
50 PathVariable( "MANDIR", "Overwrite the directory where manpages are installed", "$PREFIX/man", PathVariable.PathAccept ),
51 PathVariable( "PYPKGDIR", "The directory where the python modules get installed.",
52 distutils.sysconfig.get_python_lib( prefix="$PREFIX" ), PathVariable.PathAccept ),
53 PathVariable( "UDEVDIR", "Overwrite the directory where udev rules are installed to.", "/lib/udev/rules.d/", PathVariable.PathAccept ),
54 BoolVariable( "ENABLE_BEBOB", "Enable/Disable support for the BeBoB platform.", True ),
55 BoolVariable( "ENABLE_FIREWORKS", "Enable/Disable support for the ECHO Audio FireWorks platform.", True ),
56 BoolVariable( "ENABLE_OXFORD", "Enable/Disable support for the Oxford Semiconductor FW platform.", True ),
57 BoolVariable( "ENABLE_MOTU", "Enable/Disable support for the MOTU platform.", True ),
58 BoolVariable( "ENABLE_DICE", "Enable/Disable support for the TCAT DICE platform.", True ),
59 BoolVariable( "ENABLE_METRIC_HALO", "Enable/Disable support for the Metric Halo platform.", False ),
60 BoolVariable( "ENABLE_RME", "Enable/Disable support for the RME platform.", True ),
61 BoolVariable( "ENABLE_DIGIDESIGN", "Enable/Disable support for Digidesign interfaces.", False ),
62 BoolVariable( "ENABLE_BOUNCE", "Enable/Disable the BOUNCE device.", False ),
63 BoolVariable( "ENABLE_GENERICAVC", """\
64 Enable/Disable the the generic avc part (mainly used by apple).
65 Note that disabling this option might be overwritten by other devices needing
66 this code.""", False ),
67 BoolVariable( "ENABLE_ALL", "Enable/Disable support for all devices.", False ),
68 BoolVariable( "SERIALIZE_USE_EXPAT", "Use libexpat for XML serialization.", False ),
69 BoolVariable( "BUILD_TESTS", """\
70 Build the tests in their directory. As some contain quite some functionality,
71 this is on by default.
72 If you just want to use ffado with jack without the tools, you can disable this.\
73 """, True ),
74 BoolVariable( "BUILD_STATIC_TOOLS", "Build a statically linked version of the FFADO tools.", False ),
75 EnumVariable('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'powerpc64', 'none' ), ignorecase=2),
76 BoolVariable( "ENABLE_OPTIMIZATIONS", "Enable optimizations and the use of processor specific extentions (MMX/SSE/...).", False ),
77 BoolVariable( "PEDANTIC", "Enable -Werror and more pedantic options during compile.", False ),
78 ( "COMPILE_FLAGS", "Add additional flags to the environment.\nOnly meant for distributors and gentoo-users who want to over-optimize their built.\n Using this is not supported by the ffado-devs!" ),
79 EnumVariable( "ENABLE_SETBUFFERSIZE_API_VER", "Report API version at runtime which includes support for dynamic buffer resizing (requires recent jack).", 'auto', allowed_values=('auto', 'true', 'false', 'force'), ignorecase=2),
83 ## Load the builders in config
84 buildenv=os.environ
86 env = Environment( tools=['default','scanreplace','pyuic','pyuic4','dbus','doxygen','pkgconfig'], toolpath=['admin'], ENV = buildenv, options=opts )
88 if env.has_key('COMPILE_FLAGS') and len(env['COMPILE_FLAGS']) > 0:
89 print '''
90 * Usage of additional flags is not supported by the ffado-devs.
91 * Use at own risk!
93 * Currentl value is '%s'
94 ''' % env['COMPILE_FLAGS']
95 env.MergeFlags(env['COMPILE_FLAGS'])
97 Help( """
98 For building ffado you can set different options as listed below. You have to
99 specify them only once, scons will save the last value you used and re-use
100 that.
101 To really undo your settings and return to the factory defaults, remove the
102 "cache"-folder and the file ".sconsign.dblite" from this directory.
103 For example with: "rm -Rf .sconsign.dblite cache"
105 Note that this is a development version! Don't complain if its not working!
106 See www.ffado.org for stable releases.
107 """ )
108 Help( opts.GenerateHelpText( env ) )
110 # make sure the necessary dirs exist
111 if not os.path.isdir( "cache" ):
112 os.makedirs( "cache" )
113 if not os.path.isdir( 'cache/objects' ):
114 os.makedirs( 'cache/objects' )
116 CacheDir( 'cache/objects' )
118 opts.Save( 'cache/options.cache', env )
120 def ConfigGuess( context ):
121 context.Message( "Trying to find the system triple: " )
122 ret = os.popen( "/bin/sh admin/config.guess" ).read()[:-1]
123 context.Result( ret )
124 return ret
126 def CheckForApp( context, app ):
127 context.Message( "Checking whether '" + app + "' executes " )
128 ret = context.TryAction( app )
129 context.Result( ret[0] )
130 return ret[0]
132 def CheckForPyModule( context, module ):
133 context.Message( "Checking for the python module '" + module + "' " )
134 ret = context.TryAction( "python $SOURCE", "import %s" % module, ".py" )
135 context.Result( ret[0] )
136 return ret[0]
138 def CompilerCheck( context ):
139 context.Message( "Checking for a working C-compiler " )
140 ret = context.TryRun( """
141 #include <stdio.h>
143 int main() {
144 printf( "Hello World!" );
145 return 0;
146 }""", '.c' )[0]
147 context.Result( ret )
148 if ret == 0:
149 return False;
150 context.Message( "Checking for a working C++-compiler " )
151 ret = context.TryRun( """
152 #include <iostream>
154 int main() {
155 std::cout << "Hello World!" << std::endl;
156 return 0;
157 }""", ".cpp" )[0]
158 context.Result( ret )
159 return ret
161 def CheckPKG(context, name):
162 context.Message( 'Checking for %s... ' % name )
163 ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
164 context.Result( ret )
165 return ret
167 tests = {
168 "ConfigGuess" : ConfigGuess,
169 "CheckForApp" : CheckForApp,
170 "CheckForPyModule": CheckForPyModule,
171 "CompilerCheck" : CompilerCheck,
172 "CheckPKG" : CheckPKG,
174 tests.update( env['PKGCONFIG_TESTS'] )
175 tests.update( env['PYUIC_TESTS'] )
176 tests.update( env['PYUIC4_TESTS'] )
178 conf = Configure( env,
179 custom_tests = tests,
180 conf_dir = "cache/",
181 log_file = 'cache/config.log' )
183 version_re = re.compile(r'^(\d+)\.(\d+)\.(\d+)')
185 def VersionInt(vers):
186 match = version_re.match(vers)
187 if not match:
188 return -1
189 (maj, min, patch) = match.group(1, 2, 3)
190 # For now allow "min" to run up to 65535. "maj" and "patch" are
191 # restricted to 0-255.
192 return (int(maj) << 24) | (int(min) << 8) | int(patch)
194 def CheckJackdVer():
195 print 'Checking jackd version...',
196 ret = Popen("which jackd >/dev/null 2>&1 && jackd --version | tail -n 1 | cut -d ' ' -f 3", shell=True, stdout=PIPE).stdout.read()[:-1]
197 if (ret == ""):
198 print "not installed"
199 return -1
200 else:
201 print ret
202 return VersionInt(ret)
204 if env['SERIALIZE_USE_EXPAT']:
205 env['SERIALIZE_USE_EXPAT']=1
206 else:
207 env['SERIALIZE_USE_EXPAT']=0
209 if env['ENABLE_BOUNCE'] or env['ENABLE_ALL']:
210 env['REQUIRE_LIBAVC']=1
211 else:
212 env['REQUIRE_LIBAVC']=0
214 if not env.GetOption('clean'):
216 # Check for working gcc and g++ compilers and their environment.
218 if not conf.CompilerCheck():
219 print "\nIt seems as if your system isn't even able to compile any C-/C++-programs. Probably you don't have gcc and g++ installed. Compiling a package from source without a working compiler is very hard to do, please install the needed packages.\nHint: on *ubuntu you need both gcc- and g++-packages installed, easiest solution is to install build-essential which depends on gcc and g++."
220 Exit( 1 )
222 # Check for pkg-config before using pkg-config to check for other dependencies.
223 if not conf.CheckForPKGConfig():
224 print "\nThe program 'pkg-config' could not be found.\nEither you have to install the corresponding package first or make sure that PATH points to the right directions."
225 Exit( 1 )
228 # The following checks are for headers and libs and packages we need.
230 allpresent = 1;
231 # for cache-serialization.
232 if env['SERIALIZE_USE_EXPAT']:
233 allpresent &= conf.CheckHeader( "expat.h" )
234 allpresent &= conf.CheckLib( 'expat', 'XML_ExpatVersion', '#include <expat.h>' )
236 pkgs = {
237 'libraw1394' : '2.0.5',
238 'libiec61883' : '1.1.0',
239 'libconfig++' : '0'
242 if env['REQUIRE_LIBAVC']:
243 pkgs['libavc1394'] = '0.5.3'
245 if not env['SERIALIZE_USE_EXPAT']:
246 pkgs['libxml++-2.6'] = '2.13.0'
248 # Provide a way for users to compile newer libffado which will work
249 # against older jack installations which will not accept the new API
250 # version reported at runtime.
251 jackd_ver = CheckJackdVer()
252 if (jackd_ver != -1):
253 # If jackd is available, use the version number reported by it. This
254 # means users don't have to have jack development files present on
255 # their system for this to work.
256 have_jack = (jackd_ver >= VersionInt('0.0.0'))
257 good_jack1 = (jackd_ver < VersionInt('1.9.0')) and (jackd_ver >= VersionInt('0.121.4'))
258 good_jack2 = (jackd_ver >= VersionInt('1.9.9'))
259 else:
260 # Jackd is not runnable. Attempt to identify a version from
261 # pkgconfig on the off-chance jack details are available from there.
262 print "Will retry jack detection using pkg-config"
263 have_jack = conf.CheckPKG('jack >= 0.0.0')
264 good_jack1 = conf.CheckPKG('jack < 1.9.0') and conf.CheckPKG('jack >= 0.122.0')
265 good_jack2 = conf.CheckPKG('jack >= 1.9.9')
266 if env['ENABLE_SETBUFFERSIZE_API_VER'] == 'auto':
267 if not(have_jack):
268 print """
269 No Jack Audio Connection Kit (JACK) installed: assuming a FFADO
270 setbuffersize-compatible version will be used.
272 elif not(good_jack1 or good_jack2):
273 FFADO_API_VERSION="8"
274 print """
275 Installed Jack Audio Connection Kit (JACK) jack does not support FFADO
276 setbuffersize API: will report earlier API version at runtime. Consider
277 upgrading to jack1 >=0.122.0 or jack2 >=1.9.9 at some point, and then
278 recompile ffado to gain access to this added feature.
280 else:
281 print "Installed Jack Audio Connection Kit (JACK) supports FFADO setbuffersize API"
282 elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'true':
283 if (have_jack and not(good_jack1) and not(good_jack2)):
284 print """
285 SetBufferSize API version is enabled but no suitable version of Jack Audio
286 Connection Kit (JACK) has been found. The resulting FFADO would cause your
287 jackd to abort with "incompatible FFADO version". Please upgrade to
288 jack1 >=0.122.0 or jack2 >=1.9.9, or set ENABLE_SETBUFFERSIZE_API_VER to "auto"
289 or "false".
291 # Although it's not strictly an error, in almost every case that
292 # this occurs the user will want to know about it and fix the
293 # problem, so we exit so they're guaranteed of seeing the above
294 # message.
295 Exit( 1 )
296 else:
297 print "Will report SetBufferSize API version at runtime"
298 elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'force':
299 print "Will report SetBufferSize API version at runtime"
300 else:
301 FFADO_API_VERSION="8"
302 print "Will not report SetBufferSize API version at runtime"
304 for pkg in pkgs:
305 name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
306 env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
307 #print '%s_FLAGS' % name2
308 if env['%s_FLAGS'%name2] == 0:
309 allpresent &= 0
311 if not allpresent:
312 print """
313 (At least) One of the dependencies is missing. I can't go on without it, please
314 install the needed packages for each of the lines saying "no".
315 (Remember to also install the *-devel packages!)
317 And remember to remove the cache with "rm -Rf .sconsign.dblite cache" so the
318 results above get rechecked.
320 Exit( 1 )
322 # Check for C99 lrint() and lrintf() functions used to convert from
323 # float to integer more efficiently via float_cast.h. If not
324 # present the standard slower methods will be used instead. This
325 # might not be the best way of testing for these but it's the only
326 # way which seems to work properly. CheckFunc() fails due to
327 # argument count problems.
328 if env.has_key( 'CFLAGS' ):
329 oldcf = env['CFLAGS']
330 else:
331 oldcf = ""
332 oldcf = env.Append(CFLAGS = '-std=c99')
333 if conf.CheckLibWithHeader( "m", "math.h", "c", "lrint(3.2);" ):
334 HAVE_LRINT = 1
335 else:
336 HAVE_LRINT = 0
337 if conf.CheckLibWithHeader( "m", "math.h", "c", "lrintf(3.2);" ):
338 HAVE_LRINTF = 1
339 else:
340 HAVE_LRINTF = 0
341 env['HAVE_LRINT'] = HAVE_LRINT;
342 env['HAVE_LRINTF'] = HAVE_LRINTF;
343 env.Replace(CFLAGS=oldcf)
346 # Optional checks follow:
349 # PyQT checks
350 build_mixer = False
351 if conf.CheckForApp( 'which pyuic4' ) and conf.CheckForPyModule( 'dbus' ) and conf.CheckForPyModule( 'PyQt4' ) and conf.CheckForPyModule( 'dbus.mainloop.qt' ):
352 env['PYUIC4'] = True
353 build_mixer = True
355 if conf.CheckForApp( 'xdg-desktop-menu --help' ):
356 env['XDG_TOOLS'] = True
357 else:
358 print """
359 I couldn't find the program 'xdg-desktop-menu'. Together with xdg-icon-resource
360 this is needed to add the fancy entry to your menu. But if the mixer will be
361 installed, you can start it by executing "ffado-mixer".
364 if not build_mixer and not env.GetOption('clean'):
365 print """
366 I couldn't find all the prerequisites ('pyuic4' and the python-modules 'dbus'
367 and 'PyQt4', the packages could be named like dbus-python and PyQt) to build the
368 mixer.
369 Therefor the qt4 mixer will not get installed.
373 # Optional pkg-config
375 pkgs = {
376 'alsa': '0',
377 'dbus-1': '1.0',
378 'dbus-c++-1' : '0',
380 for pkg in pkgs:
381 name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
382 env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
384 if not env['DBUS1_FLAGS'] or not env['DBUSC1_FLAGS'] or not conf.CheckForApp('which dbusxx-xml2cpp'):
385 env['DBUS1_FLAGS'] = ""
386 env['DBUSC1_FLAGS'] = ""
387 print """
388 One of the dbus-headers, the dbus-c++-headers and/or the application
389 'dbusxx-xml2cpp' where not found. The dbus-server for ffado will therefore not
390 be built.
392 else:
393 # Get the directory where dbus stores the service-files
394 env['dbus_service_dir'] = conf.GetPKGVariable( 'dbus-1', 'session_bus_services_dir' ).strip()
395 # this is required to indicate that the DBUS version we use has support
396 # for platform dependent threading init functions
397 # this is true for DBUS >= 0.96 or so. Since we require >= 1.0 it is
398 # always true
399 env['DBUS1_FLAGS'] += " -DDBUS_HAS_THREADS_INIT_DEFAULT"
402 config_guess = conf.ConfigGuess()
404 env = conf.Finish()
406 if env['DEBUG_BUILD']:
407 print "Doing a debug build"
408 env.MergeFlags( "-Wall -g" )
409 else:
410 env.MergeFlags( "-O2" )
412 if env['DEBUG']:
413 env.MergeFlags( "-DDEBUG" )
414 else:
415 env.MergeFlags( "-DNDEBUG" )
417 if env['PROFILE']:
418 print "Doing a PROFILE build"
419 env.MergeFlags( "-Wall -g" )
421 if env['PEDANTIC']:
422 env.MergeFlags( "-Werror" )
425 if env['ENABLE_ALL']:
426 env['ENABLE_BEBOB'] = True
427 env['ENABLE_FIREWORKS'] = True
428 env['ENABLE_OXFORD'] = True
429 env['ENABLE_MOTU'] = True
430 env['ENABLE_DICE'] = True
431 env['ENABLE_METRIC_HALO'] = True
432 env['ENABLE_RME'] = True
433 env['ENABLE_DIGIDESIGN'] = True
434 env['ENABLE_BOUNCE'] = True
437 env['BUILD_STATIC_LIB'] = False
438 if env['BUILD_STATIC_TOOLS']:
439 print "Building static versions of the tools..."
440 env['BUILD_STATIC_LIB'] = True
442 env['build_base']="#/"
445 # Get the DESTDIR (if wanted) from the commandline
447 env.destdir = ARGUMENTS.get( 'DESTDIR', "" )
450 # Uppercase variables are for usage in code, lowercase versions for usage in
451 # scons-files for installing.
453 env['BINDIR'] = Template( env['BINDIR'] ).safe_substitute( env )
454 env['LIBDIR'] = Template( env['LIBDIR'] ).safe_substitute( env )
455 env['INCLUDEDIR'] = Template( env['INCLUDEDIR'] ).safe_substitute( env )
456 env['SHAREDIR'] = Template( env['SHAREDIR'] ).safe_substitute( env )
457 env['UDEVDIR'] = Template( env['UDEVDIR'] ).safe_substitute( env )
458 env['prefix'] = Template( env.destdir + env['PREFIX'] ).safe_substitute( env )
459 env['bindir'] = Template( env.destdir + env['BINDIR'] ).safe_substitute( env )
460 env['libdir'] = Template( env.destdir + env['LIBDIR'] ).safe_substitute( env )
461 env['includedir'] = Template( env.destdir + env['INCLUDEDIR'] ).safe_substitute( env )
462 env['sharedir'] = Template( env.destdir + env['SHAREDIR'] ).safe_substitute( env )
463 env['mandir'] = Template( env.destdir + env['MANDIR'] ).safe_substitute( env )
464 env['pypkgdir'] = Template( env.destdir + env['PYPKGDIR'] ).safe_substitute( env )
465 env['udevdir'] = Template( env.destdir + env['UDEVDIR'] ).safe_substitute( env )
466 env['PYPKGDIR'] = Template( env['PYPKGDIR'] ).safe_substitute( env )
468 env.Command( target=env['sharedir'], source="", action=Mkdir( env['sharedir'] ) )
470 env.Alias( "install", env['libdir'] )
471 env.Alias( "install", env['includedir'] )
472 env.Alias( "install", env['sharedir'] )
473 env.Alias( "install", env['bindir'] )
474 env.Alias( "install", env['mandir'] )
475 if build_mixer:
476 env.Alias( "install", env['pypkgdir'] )
479 # shamelessly copied from the Ardour scons file
482 opt_flags = []
483 env['USE_SSE'] = 0
485 # guess at the platform, used to define compiler flags
487 config_cpu = 0
488 config_arch = 1
489 config_kernel = 2
490 config_os = 3
491 config = config_guess.split ("-")
493 needs_fPIC = False
495 #=== Begin Revised CXXFLAGS =========================================
496 def outputof(*cmd):
497 """Run a command without running a shell, return cmd's stdout
499 p = Popen(cmd, stdout=PIPE)
500 return p.communicate()[0]
502 def cpuinfo_kv():
503 """generator which reads lines from Linux /proc/cpuinfo and splits them
504 into key:value tokens and yields (key, value) tuple.
506 f = open('/proc/cpuinfo', 'r')
507 for line in f:
508 line = line.strip()
509 if line:
510 k,v = line.split(':')
511 yield (k.strip(), v.strip())
512 f.close()
515 class CpuInfo (object):
516 """Collects information about the CPU, mainly from /proc/cpuinfo
518 def __init__(self):
519 self.sysname, self.hostname, self.release, self.version, self.machine = os.uname()
520 # general CPU architecture
521 self.is_x86 = self.machine in ('i686', 'x86_64') or \
522 re.match("i[3-5]86", self.machine) or False
523 self.is_powerpc = self.machine in ('ppc64', 'ppc', 'powerpc', 'powerpc64')
524 #!!! probably not comprehensive
525 self.is_mips = self.machine == 'mips'
526 #!!! not a comprehensive list. uname -m on one android phone reports 'armv71'
527 # I have no other arm devices I can check
528 self.is_arm = self.machine in ('armv71', )
530 self.cpu_count = 0
531 if self.is_x86:
532 self.cpu_info_x86()
533 elif self.is_powerpc:
534 self.cpu_info_ppc()
535 elif self.is_mips:
536 self.cpu_info_mips()
538 # 64-bit (x86_64/AMD64/Intel64)
539 # Long Mode (x86-64: amd64, also known as Intel 64, i.e. 64-bit capable)
540 self.is_64bit = (self.is_x86 and 'lm' in self.x86_flags) or \
541 (self.is_powerpc and '970' in self.ppc_type)
543 # Hardware virtualization capable: vmx (Intel), svm (AMD)
544 self.has_hwvirt = self.is_x86 and (
545 (self.is_amd and 'svm' in self.x86_flags) or
546 (self.is_intel and 'vmx' in self.x86_flags))
548 # Physical Address Extensions (support for more than 4GB of RAM)
549 self.has_pae = self.is_x86 and 'pae' in self.x86_flags
552 def cpu_info_x86(self):
553 "parse /proc/cpuinfo for x86 kernels"
554 for k,v in cpuinfo_kv():
555 if k == 'processor':
556 self.cpu_count += 1
557 if self.cpu_count > 1:
558 # assume all CPUs are identical features, no need to
559 # parse all of them
560 continue
561 elif k == 'vendor_id': # AuthenticAMD, GenuineIntel
562 self.vendor_id = v
563 self.is_amd = v == 'AuthenticAMD'
564 self.is_intel = v == 'GenuineIntel'
565 elif k == 'flags':
566 self.x86_flags = v.split()
567 elif k == 'model name':
568 self.model_name = v
569 elif k == 'cpu family':
570 self.cpu_family = v
571 elif k == 'model':
572 self.model = v
574 def cpu_info_ppc(self):
575 "parse /proc/cpuinfo for PowerPC kernels"
576 # http://en.wikipedia.org/wiki/List_of_PowerPC_processors
577 # PowerPC 7xx family
578 # PowerPC 740 and 750, 233-366 MHz
579 # 745/755, 300–466 MHz
581 # PowerPC G4 series
582 # 7400/7410 350 - 550 MHz, uses AltiVec, a SIMD extension of the original PPC specs
583 # 7450 micro-architecture family up to 1.5 GHz and 256 kB on-chip L2 cache and improved Altivec
584 # 7447/7457 micro-architecture family up to 1.8 GHz with 512 kB on-chip L2 cache
585 # 7448 micro-architecture family (1.5 GHz) in 90 nm with 1MB L2 cache and slightly
586 # improved AltiVec (out of order instructions).
587 # 8640/8641/8640D/8641D with one or two e600 (Formerly known as G4) cores, 1MB L2 cache
589 # PowerPC G5 series
590 # 970 (2003), 64-bit, derived from POWER4, enhanced with VMX, 512 kB L2 cache, 1.4 – 2 GHz
591 # 970FX (2004), manufactured at 90 nm, 1.8 - 2.7 GHz
592 # 970GX (2006), manufactured at 90 nm, 1MB L2 cache/core, 1.2 - 2.5 GHz
593 # 970MP (2005), dual core, 1 MB L2 cache/core, 1.6 - 2.5 GHz
594 for k,v in cpuinfo_kv():
595 if k == 'processor':
596 self.cpu_count += 1
597 elif k == 'cpu':
598 self.is_altivec_supported = 'altivec' in v
599 ppc_type, x = v.split(',')
600 self.ppc_type = ppc_type.strip()
601 # older kernels might not have a 'processor' line
602 if self.cpu_count == 0:
603 self.cpu_count += 1
606 def cpu_info_mips(self):
607 "parse /proc/cpuinfo for MIPS kernels"
608 for k,v in cpuinfo_kv():
609 if k == 'processor':
610 self.cpu_count += 1
611 elif k == 'cpu model':
612 self.mips_cpu_model = v
615 def is_userspace_32bit(cpuinfo):
616 """Even if `uname -m` reports a 64-bit architecture, userspace could still
617 be 32-bit, such as Debian on powerpc64. This function tries to figure out
618 if userspace is 32-bit, i.e. we might need to pass '-m32' or '-m64' to gcc.
620 if not cpuinfo.is_64bit:
621 return True
622 # note that having a 64-bit CPU means nothing for these purposes. You could
623 # run a completely 32-bit system on a 64-bit capable CPU.
624 answer = None
625 # Debian ppc64 returns machine 'ppc64', but userspace might be 32-bit
626 # We'll make an educated guess by examining a known executable
627 exe = '/bin/mount'
628 if os.path.isfile(exe):
629 #print 'Found %s' % exe
630 if os.path.islink(exe):
631 real_exe = os.path.join(os.path.dirname(exe), os.readlink(exe))
632 #print '%s is a symlink to %s' % (exe, real_exe)
633 else:
634 real_exe = exe
635 # presumably if a person is running this script, they should have
636 # a gcc toolchain installed...
637 x = outputof('objdump', '-Wi', real_exe)
638 # should emit a line that looks like this:
639 # /bin/mount: file format elf32-i386
640 # or like this:
641 # /bin/mount: file format elf64-x86-64
642 # or like this:
643 # /bin/mount: file format elf32-powerpc
644 for line in x.split('\n'):
645 line = line.strip()
646 if line.startswith(real_exe):
647 x, fmt = line.rsplit(None, 1)
648 answer = 'elf32' in fmt
649 break
650 else:
651 print '!!! Not found %s' % exe
652 return answer
655 def cc_flags_x86(cpuinfo, enable_optimizations):
656 """add certain gcc -m flags based on CPU features
658 # See http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/i386-and-x86_002d64-Options.html
659 cc_opts = []
660 if cpuinfo.machine == 'i586':
661 cc_opts.append('-march=i586')
662 elif cpuinfo.machine == 'i686':
663 cc_opts.append('-march=i686')
665 if 'mmx' in cpuinfo.x86_flags:
666 cc_opts.append('-mmmx')
668 # map from proc/cpuinfo flags to gcc options
669 opt_flags = [
670 ('sse', ('-mfpmath=sse', '-msse')),
671 ('sse2', '-msse2'),
672 ('ssse3', '-mssse3'),
673 ('sse4', '-msse4'),
674 ('sse4_1', '-msse4.1'),
675 ('sse4_2', '-msse4.2'),
676 ('sse4a', '-msse4a'),
677 ('3dnow', '-m3dnow'),
679 if enable_optimizations:
680 for flag, gccopt in opt_flags:
681 if flag in cpuinfo.x86_flags:
682 if isinstance(gccopt, (tuple, list)):
683 cc_opts.extend(gccopt)
684 else:
685 cc_opts.append(gccopt)
686 return cc_opts
689 def cc_flags_powerpc(cpuinfo, enable_optimizations):
690 """add certain gcc -m flags based on CPU model
692 cc_opts = []
693 if cpuinfo.is_altivec_supported:
694 cc_opts.append ('-maltivec')
695 cc_opts.append ('-mabi=altivec')
697 if re.match('74[0145][0578]A?', cpuinfo.ppc_type) is not None:
698 cc_opts.append ('-mcpu=7400')
699 cc_opts.append ('-mtune=7400')
700 elif re.match('750', cpuinfo.ppc_type) is not None:
701 cc_opts.append ('-mcpu=750')
702 cc_opts.append ('-mtune=750')
703 elif re.match('PPC970', cpuinfo.ppc_type) is not None:
704 cc_opts.append ('-mcpu=970')
705 cc_opts.append ('-mtune=970')
706 elif re.match('Cell Broadband Engine', cpuinfo.ppc_type) is not None:
707 cc_opts.append('-mcpu=cell')
708 cc_opts.append('-mtune=cell')
709 return cc_opts
710 #=== End Revised CXXFLAGS =========================================
712 # Autodetect
713 if env['DIST_TARGET'] == 'auto':
714 if re.search ("x86_64", config[config_cpu]) is not None:
715 env['DIST_TARGET'] = 'x86_64'
716 elif re.search("i[0-5]86", config[config_cpu]) is not None:
717 env['DIST_TARGET'] = 'i386'
718 elif re.search("i686", config[config_cpu]) is not None:
719 env['DIST_TARGET'] = 'i686'
720 elif re.search("powerpc64", config[config_cpu]) is not None:
721 env['DIST_TARGET'] = 'powerpc64'
722 elif re.search("powerpc", config[config_cpu]) is not None:
723 env['DIST_TARGET'] = 'powerpc'
724 else:
725 env['DIST_TARGET'] = config[config_cpu]
726 print "Detected DIST_TARGET = " + env['DIST_TARGET']
728 #=== Begin Revised CXXFLAGS =========================================
729 # comment on DIST_TARGET up top implies it can be used for cross-compiling
730 # but that's not true because even if it is not 'auto' the original
731 # script still reads /proc/cpuinfo to determine gcc arch flags.
732 # This script does the same as the original. Needs to be fixed someday.
733 cpuinfo = CpuInfo()
734 if cpuinfo.is_x86:
735 opt_flags.extend(cc_flags_x86(cpuinfo, env['ENABLE_OPTIMIZATIONS']))
736 if cpuinfo.is_powerpc:
737 opt_flags.extend(cc_flags_powerpc(cpuinfo, env['ENABLE_OPTIMIZATIONS']))
738 if '-msse' in opt_flags:
739 env['USE_SSE'] = 1
740 if '-msse2' in opt_flags:
741 env['USE_SSE2'] = 1
743 m32 = is_userspace_32bit(cpuinfo)
744 print 'User space is %s' % (m32 and '32-bit' or '64-bit')
745 if cpuinfo.is_powerpc:
746 if m32:
747 print "Doing a 32-bit PowerPC build for %s CPU" % cpuinfo.ppc_type
748 machineflags = { 'CXXFLAGS' : ['-m32'] }
749 else:
750 print "Doing a 64-bit PowerPC build for %s CPU" % cpuinfo.ppc_type
751 machineflags = { 'CXXFLAGS' : ['-m64'] }
752 env.MergeFlags( machineflags )
753 elif cpuinfo.is_x86:
754 if m32:
755 print "Doing a 32-bit %s build for %s" % (cpuinfo.machine, cpuinfo.model_name)
756 machineflags = { 'CXXFLAGS' : ['-m32'] }
757 else:
758 print "Doing a 64-bit %s build for %s" % (cpuinfo.machine, cpuinfo.model_name)
759 machineflags = { 'CXXFLAGS' : ['-m64'] }
760 needs_fPIC = True
761 env.MergeFlags( machineflags )
762 #=== End Revised CXXFLAGS =========================================
765 if needs_fPIC or ( env.has_key('COMPILE_FLAGS') and '-fPIC' in env['COMPILE_FLAGS'] ):
766 env.MergeFlags( "-fPIC" )
768 # end of processor-specific section
769 if env['ENABLE_OPTIMIZATIONS']:
770 opt_flags.extend (["-fomit-frame-pointer","-ffast-math","-funroll-loops"])
771 env.MergeFlags( opt_flags )
772 print "Doing an optimized build..."
774 env['REVISION'] = os.popen('svnversion .').read()[:-1]
775 # This may be as simple as '89' or as complex as '4123:4184M'.
776 # We'll just use the last bit.
777 env['REVISION'] = env['REVISION'].split(':')[-1]
779 # try to circumvent localized versions
780 if len(env['REVISION']) >= 5 and env['REVISION'][0:6] == 'export':
781 env['REVISION'] = ''
783 # avoid the 1.999.41- type of version for exported versions
784 if env['REVISION'] != '':
785 env['REVISIONSTRING'] = '-' + env['REVISION']
786 else:
787 env['REVISIONSTRING'] = ''
789 env['FFADO_API_VERSION'] = FFADO_API_VERSION
791 env['PACKAGE'] = "libffado"
792 env['VERSION'] = FFADO_VERSION
793 env['LIBVERSION'] = "1.0.0"
795 env['CONFIGDIR'] = "~/.ffado"
796 env['CACHEDIR'] = "~/.ffado"
798 env['USER_CONFIG_FILE'] = env['CONFIGDIR'] + "/configuration"
799 env['SYSTEM_CONFIG_FILE'] = env['SHAREDIR'] + "/configuration"
801 env['REGISTRATION_URL'] = "http://ffado.org/deviceregistration/register.php?action=register"
804 # To have the top_srcdir as the doxygen-script is used from auto*
806 env['top_srcdir'] = env.Dir( "." ).abspath
809 # Start building
811 env.ScanReplace( "config.h.in" )
812 env.ScanReplace( "config_debug.h.in" )
813 env.ScanReplace( "version.h.in" )
815 # ensure that the config.h is updated
816 env.Depends( "config.h", "SConstruct" )
817 env.Depends( "config.h", 'cache/options.cache' )
819 # update version.h whenever the version or SVN revision changes
820 env.Depends( "version.h", env.Value(env['REVISION']))
821 env.Depends( "version.h", env.Value(env['VERSION']))
823 env.Depends( "libffado.pc", "SConstruct" )
824 pkgconfig = env.ScanReplace( "libffado.pc.in" )
825 env.Install( env['libdir'] + '/pkgconfig', pkgconfig )
827 env.Install( env['sharedir'], 'configuration' )
829 subdirs=['src','libffado','support','doc']
830 if env['BUILD_TESTS']:
831 subdirs.append('tests')
833 env.SConscript( dirs=subdirs, exports="env" )
835 if 'debian' in COMMAND_LINE_TARGETS:
836 env.SConscript("deb/SConscript", exports="env")
838 # By default only src is built but all is cleaned
839 if not env.GetOption('clean'):
840 Default( 'src' )
841 Default( 'support' )
842 if env['BUILD_TESTS']:
843 Default( 'tests' )
846 # Deal with the DESTDIR vs. xdg-tools conflict (which is basicely that the
847 # xdg-tools can't deal with DESTDIR, so the packagers have to deal with this
848 # their own :-/
850 if len(env.destdir) > 0:
851 if not len( ARGUMENTS.get( "WILL_DEAL_WITH_XDG_MYSELF", "" ) ) > 0:
852 print """
853 WARNING!
854 You are using the (packagers) option DESTDIR to install this package to a
855 different place than the real prefix. As the xdg-tools can't cope with
856 that, the .desktop-files are not installed by this build, you have to
857 deal with them your own.
858 (And you have to look into the SConstruct to learn how to disable this
859 message.)
861 else:
863 def CleanAction( action ):
864 if env.GetOption( "clean" ):
865 env.Execute( action )
867 if env.has_key( 'XDG_TOOLS' ) and env.has_key( 'PYUIC4' ):
868 if not env.GetOption("clean"):
869 action = "install"
870 else:
871 action = "uninstall"
872 mixerdesktopaction = env.Action( "-xdg-desktop-menu %s support/xdg/ffado.org-ffadomixer.desktop" % action )
873 mixericonaction = env.Action( "-xdg-icon-resource %s --size 64 --novendor --context apps support/xdg/hi64-apps-ffado.png ffado" % action )
874 env.Command( "__xdgstuff1", None, mixerdesktopaction )
875 env.Command( "__xdgstuff2", None, mixericonaction )
876 env.Alias( "install", ["__xdgstuff1", "__xdgstuff2" ] )
877 CleanAction( mixerdesktopaction )
878 CleanAction( mixericonaction )
881 # Create a tags-file for easier emacs/vim-source-browsing
882 # I don't know if the dependency is right...
884 findcommand = "find . \( -path \"*.h\" -o -path \"*.cpp\" -o -path \"*.c\" \) \! -path \"*.svn*\" \! -path \"./doc*\" \! -path \"./cache*\""
885 env.Command( "tags", "", findcommand + " |xargs ctags" )
886 env.Command( "TAGS", "", findcommand + " |xargs etags" )
887 env.AlwaysBuild( "tags", "TAGS" )
888 if 'NoCache' in dir(env):
889 env.NoCache( "tags", "TAGS" )
891 # Another convinience target
892 if env.GetOption( "clean" ):
893 env.Execute( "rm cache/objects -Rf" )
896 # vim: ts=4 sw=4 et