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