SConstruct: further refinement of debug control at build time. A new DEBUG_MESSAGES...
[ffado.git] / libffado / SConstruct
blob0ac054b279301e502483ca93b0fb61459b45e647
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 Build with \"-g -Wall\" rather than \"-O2\", and include extra debugging
44 checks in the code.""", True ),
45 BoolVariable( "DEBUG_MESSAGES", "Enable support for debug messages", True ),
46 BoolVariable( "PROFILE", "Build with symbols, warnings and other profiling info", False ),
47 PathVariable( "PREFIX", "The prefix where ffado will be installed to.", "/usr/local", PathVariable.PathAccept ),
48 PathVariable( "BINDIR", "Overwrite the directory where apps are installed to.", "$PREFIX/bin", PathVariable.PathAccept ),
49 PathVariable( "LIBDIR", "Overwrite the directory where libs are installed to.", "$PREFIX/lib", PathVariable.PathAccept ),
50 PathVariable( "INCLUDEDIR", "Overwrite the directory where headers are installed to.", "$PREFIX/include", PathVariable.PathAccept ),
51 PathVariable( "SHAREDIR", "Overwrite the directory where misc shared files are installed to.", "$PREFIX/share/libffado", PathVariable.PathAccept ),
52 PathVariable( "MANDIR", "Overwrite the directory where manpages are installed", "$PREFIX/man", PathVariable.PathAccept ),
53 PathVariable( "PYPKGDIR", "The directory where the python modules get installed.",
54 distutils.sysconfig.get_python_lib( prefix="$PREFIX" ), PathVariable.PathAccept ),
55 PathVariable( "UDEVDIR", "Overwrite the directory where udev rules are installed to.", "/lib/udev/rules.d/", PathVariable.PathAccept ),
56 BoolVariable( "ENABLE_BEBOB", "Enable/Disable support for the BeBoB platform.", True ),
57 BoolVariable( "ENABLE_FIREWORKS", "Enable/Disable support for the ECHO Audio FireWorks platform.", True ),
58 BoolVariable( "ENABLE_OXFORD", "Enable/Disable support for the Oxford Semiconductor FW platform.", True ),
59 BoolVariable( "ENABLE_MOTU", "Enable/Disable support for the MOTU platform.", True ),
60 BoolVariable( "ENABLE_DICE", "Enable/Disable support for the TCAT DICE platform.", True ),
61 BoolVariable( "ENABLE_METRIC_HALO", "Enable/Disable support for the Metric Halo platform.", False ),
62 BoolVariable( "ENABLE_RME", "Enable/Disable support for the RME platform.", True ),
63 BoolVariable( "ENABLE_DIGIDESIGN", "Enable/Disable support for Digidesign interfaces.", False ),
64 BoolVariable( "ENABLE_BOUNCE", "Enable/Disable the BOUNCE device.", False ),
65 BoolVariable( "ENABLE_GENERICAVC", """\
66 Enable/Disable the the generic avc part (mainly used by apple).
67 Note that disabling this option might be overwritten by other devices needing
68 this code.""", False ),
69 BoolVariable( "ENABLE_ALL", "Enable/Disable support for all devices.", False ),
70 BoolVariable( "SERIALIZE_USE_EXPAT", "Use libexpat for XML serialization.", False ),
71 BoolVariable( "BUILD_TESTS", """\
72 Build the tests in their directory. As some contain quite some functionality,
73 this is on by default.
74 If you just want to use ffado with jack without the tools, you can disable this.\
75 """, True ),
76 BoolVariable( "BUILD_STATIC_TOOLS", "Build a statically linked version of the FFADO tools.", False ),
77 EnumVariable('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'powerpc64', 'none' ), ignorecase=2),
78 BoolVariable( "ENABLE_OPTIMIZATIONS", "Enable optimizations and the use of processor specific extentions (MMX/SSE/...).", False ),
79 BoolVariable( "PEDANTIC", "Enable -Werror and more pedantic options during compile.", False ),
80 ( "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!" ),
81 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),
85 ## Load the builders in config
86 buildenv=os.environ
88 env = Environment( tools=['default','scanreplace','pyuic','pyuic4','dbus','doxygen','pkgconfig'], toolpath=['admin'], ENV = buildenv, options=opts )
90 if env.has_key('COMPILE_FLAGS') and len(env['COMPILE_FLAGS']) > 0:
91 print '''
92 * Usage of additional flags is not supported by the ffado-devs.
93 * Use at own risk!
95 * Currentl value is '%s'
96 ''' % env['COMPILE_FLAGS']
97 env.MergeFlags(env['COMPILE_FLAGS'])
99 Help( """
100 For building ffado you can set different options as listed below. You have to
101 specify them only once, scons will save the last value you used and re-use
102 that.
103 To really undo your settings and return to the factory defaults, remove the
104 "cache"-folder and the file ".sconsign.dblite" from this directory.
105 For example with: "rm -Rf .sconsign.dblite cache"
107 Note that this is a development version! Don't complain if its not working!
108 See www.ffado.org for stable releases.
109 """ )
110 Help( opts.GenerateHelpText( env ) )
112 # make sure the necessary dirs exist
113 if not os.path.isdir( "cache" ):
114 os.makedirs( "cache" )
115 if not os.path.isdir( 'cache/objects' ):
116 os.makedirs( 'cache/objects' )
118 CacheDir( 'cache/objects' )
120 opts.Save( 'cache/options.cache', env )
122 def ConfigGuess( context ):
123 context.Message( "Trying to find the system triple: " )
124 ret = os.popen( "/bin/sh admin/config.guess" ).read()[:-1]
125 context.Result( ret )
126 return ret
128 def CheckForApp( context, app ):
129 context.Message( "Checking whether '" + app + "' executes " )
130 ret = context.TryAction( app )
131 context.Result( ret[0] )
132 return ret[0]
134 def CheckForPyModule( context, module ):
135 context.Message( "Checking for the python module '" + module + "' " )
136 ret = context.TryAction( "python $SOURCE", "import %s" % module, ".py" )
137 context.Result( ret[0] )
138 return ret[0]
140 def CompilerCheck( context ):
141 context.Message( "Checking for a working C-compiler " )
142 ret = context.TryRun( """
143 #include <stdio.h>
145 int main() {
146 printf( "Hello World!" );
147 return 0;
148 }""", '.c' )[0]
149 context.Result( ret )
150 if ret == 0:
151 return False;
152 context.Message( "Checking for a working C++-compiler " )
153 ret = context.TryRun( """
154 #include <iostream>
156 int main() {
157 std::cout << "Hello World!" << std::endl;
158 return 0;
159 }""", ".cpp" )[0]
160 context.Result( ret )
161 return ret
163 def CheckPKG(context, name):
164 context.Message( 'Checking for %s... ' % name )
165 ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
166 context.Result( ret )
167 return ret
169 tests = {
170 "ConfigGuess" : ConfigGuess,
171 "CheckForApp" : CheckForApp,
172 "CheckForPyModule": CheckForPyModule,
173 "CompilerCheck" : CompilerCheck,
174 "CheckPKG" : CheckPKG,
176 tests.update( env['PKGCONFIG_TESTS'] )
177 tests.update( env['PYUIC_TESTS'] )
178 tests.update( env['PYUIC4_TESTS'] )
180 conf = Configure( env,
181 custom_tests = tests,
182 conf_dir = "cache/",
183 log_file = 'cache/config.log' )
185 version_re = re.compile(r'^(\d+)\.(\d+)\.(\d+)')
187 def VersionInt(vers):
188 match = version_re.match(vers)
189 if not match:
190 return -1
191 (maj, min, patch) = match.group(1, 2, 3)
192 # For now allow "min" to run up to 65535. "maj" and "patch" are
193 # restricted to 0-255.
194 return (int(maj) << 24) | (int(min) << 8) | int(patch)
196 def CheckJackdVer():
197 print 'Checking jackd version...',
198 ret = Popen("which jackd >/dev/null 2>&1 && jackd --version | tail -n 1 | cut -d ' ' -f 3", shell=True, stdout=PIPE).stdout.read()[:-1]
199 if (ret == ""):
200 print "not installed"
201 return -1
202 else:
203 print ret
204 return VersionInt(ret)
206 if env['SERIALIZE_USE_EXPAT']:
207 env['SERIALIZE_USE_EXPAT']=1
208 else:
209 env['SERIALIZE_USE_EXPAT']=0
211 if env['ENABLE_BOUNCE'] or env['ENABLE_ALL']:
212 env['REQUIRE_LIBAVC']=1
213 else:
214 env['REQUIRE_LIBAVC']=0
216 if not env.GetOption('clean'):
218 # Check for working gcc and g++ compilers and their environment.
220 if not conf.CompilerCheck():
221 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++."
222 Exit( 1 )
224 # Check for pkg-config before using pkg-config to check for other dependencies.
225 if not conf.CheckForPKGConfig():
226 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."
227 Exit( 1 )
230 # The following checks are for headers and libs and packages we need.
232 allpresent = 1;
233 # for cache-serialization.
234 if env['SERIALIZE_USE_EXPAT']:
235 allpresent &= conf.CheckHeader( "expat.h" )
236 allpresent &= conf.CheckLib( 'expat', 'XML_ExpatVersion', '#include <expat.h>' )
238 pkgs = {
239 'libraw1394' : '2.0.5',
240 'libiec61883' : '1.1.0',
241 'libconfig++' : '0'
244 if env['REQUIRE_LIBAVC']:
245 pkgs['libavc1394'] = '0.5.3'
247 if not env['SERIALIZE_USE_EXPAT']:
248 pkgs['libxml++-2.6'] = '2.13.0'
250 # Provide a way for users to compile newer libffado which will work
251 # against older jack installations which will not accept the new API
252 # version reported at runtime.
253 jackd_ver = CheckJackdVer()
254 if (jackd_ver != -1):
255 # If jackd is available, use the version number reported by it. This
256 # means users don't have to have jack development files present on
257 # their system for this to work.
258 have_jack = (jackd_ver >= VersionInt('0.0.0'))
259 good_jack1 = (jackd_ver < VersionInt('1.9.0')) and (jackd_ver >= VersionInt('0.121.4'))
260 good_jack2 = (jackd_ver >= VersionInt('1.9.9'))
261 else:
262 # Jackd is not runnable. Attempt to identify a version from
263 # pkgconfig on the off-chance jack details are available from there.
264 print "Will retry jack detection using pkg-config"
265 have_jack = conf.CheckPKG('jack >= 0.0.0')
266 good_jack1 = conf.CheckPKG('jack < 1.9.0') and conf.CheckPKG('jack >= 0.122.0')
267 good_jack2 = conf.CheckPKG('jack >= 1.9.9')
268 if env['ENABLE_SETBUFFERSIZE_API_VER'] == 'auto':
269 if not(have_jack):
270 print """
271 No Jack Audio Connection Kit (JACK) installed: assuming a FFADO
272 setbuffersize-compatible version will be used.
274 elif not(good_jack1 or good_jack2):
275 FFADO_API_VERSION="8"
276 print """
277 Installed Jack Audio Connection Kit (JACK) jack does not support FFADO
278 setbuffersize API: will report earlier API version at runtime. Consider
279 upgrading to jack1 >=0.122.0 or jack2 >=1.9.9 at some point, and then
280 recompile ffado to gain access to this added feature.
282 else:
283 print "Installed Jack Audio Connection Kit (JACK) supports FFADO setbuffersize API"
284 elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'true':
285 if (have_jack and not(good_jack1) and not(good_jack2)):
286 print """
287 SetBufferSize API version is enabled but no suitable version of Jack Audio
288 Connection Kit (JACK) has been found. The resulting FFADO would cause your
289 jackd to abort with "incompatible FFADO version". Please upgrade to
290 jack1 >=0.122.0 or jack2 >=1.9.9, or set ENABLE_SETBUFFERSIZE_API_VER to "auto"
291 or "false".
293 # Although it's not strictly an error, in almost every case that
294 # this occurs the user will want to know about it and fix the
295 # problem, so we exit so they're guaranteed of seeing the above
296 # message.
297 Exit( 1 )
298 else:
299 print "Will report SetBufferSize API version at runtime"
300 elif env['ENABLE_SETBUFFERSIZE_API_VER'] == 'force':
301 print "Will report SetBufferSize API version at runtime"
302 else:
303 FFADO_API_VERSION="8"
304 print "Will not report SetBufferSize API version at runtime"
306 for pkg in pkgs:
307 name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
308 env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
309 #print '%s_FLAGS' % name2
310 if env['%s_FLAGS'%name2] == 0:
311 allpresent &= 0
313 if not allpresent:
314 print """
315 (At least) One of the dependencies is missing. I can't go on without it, please
316 install the needed packages for each of the lines saying "no".
317 (Remember to also install the *-devel packages!)
319 And remember to remove the cache with "rm -Rf .sconsign.dblite cache" so the
320 results above get rechecked.
322 Exit( 1 )
324 # Check for C99 lrint() and lrintf() functions used to convert from
325 # float to integer more efficiently via float_cast.h. If not
326 # present the standard slower methods will be used instead. This
327 # might not be the best way of testing for these but it's the only
328 # way which seems to work properly. CheckFunc() fails due to
329 # argument count problems.
330 if env.has_key( 'CFLAGS' ):
331 oldcf = env['CFLAGS']
332 else:
333 oldcf = ""
334 oldcf = env.Append(CFLAGS = '-std=c99')
335 if conf.CheckLibWithHeader( "m", "math.h", "c", "lrint(3.2);" ):
336 HAVE_LRINT = 1
337 else:
338 HAVE_LRINT = 0
339 if conf.CheckLibWithHeader( "m", "math.h", "c", "lrintf(3.2);" ):
340 HAVE_LRINTF = 1
341 else:
342 HAVE_LRINTF = 0
343 env['HAVE_LRINT'] = HAVE_LRINT;
344 env['HAVE_LRINTF'] = HAVE_LRINTF;
345 env.Replace(CFLAGS=oldcf)
348 # Optional checks follow:
351 # PyQT checks
352 build_mixer = False
353 if conf.CheckForApp( 'which pyuic4' ) and conf.CheckForPyModule( 'dbus' ) and conf.CheckForPyModule( 'PyQt4' ) and conf.CheckForPyModule( 'dbus.mainloop.qt' ):
354 env['PYUIC4'] = True
355 build_mixer = True
357 if conf.CheckForApp( 'xdg-desktop-menu --help' ):
358 env['XDG_TOOLS'] = True
359 else:
360 print """
361 I couldn't find the program 'xdg-desktop-menu'. Together with xdg-icon-resource
362 this is needed to add the fancy entry to your menu. But if the mixer will be
363 installed, you can start it by executing "ffado-mixer".
366 if not build_mixer and not env.GetOption('clean'):
367 print """
368 I couldn't find all the prerequisites ('pyuic4' and the python-modules 'dbus'
369 and 'PyQt4', the packages could be named like dbus-python and PyQt) to build the
370 mixer.
371 Therefor the qt4 mixer will not get installed.
375 # Optional pkg-config
377 pkgs = {
378 'alsa': '0',
379 'dbus-1': '1.0',
380 'dbus-c++-1' : '0',
382 for pkg in pkgs:
383 name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
384 env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
386 if not env['DBUS1_FLAGS'] or not env['DBUSC1_FLAGS'] or not conf.CheckForApp('which dbusxx-xml2cpp'):
387 env['DBUS1_FLAGS'] = ""
388 env['DBUSC1_FLAGS'] = ""
389 print """
390 One of the dbus-headers, the dbus-c++-headers and/or the application
391 'dbusxx-xml2cpp' where not found. The dbus-server for ffado will therefore not
392 be built.
394 else:
395 # Get the directory where dbus stores the service-files
396 env['dbus_service_dir'] = conf.GetPKGVariable( 'dbus-1', 'session_bus_services_dir' ).strip()
397 # this is required to indicate that the DBUS version we use has support
398 # for platform dependent threading init functions
399 # this is true for DBUS >= 0.96 or so. Since we require >= 1.0 it is
400 # always true
401 env['DBUS1_FLAGS'] += " -DDBUS_HAS_THREADS_INIT_DEFAULT"
404 config_guess = conf.ConfigGuess()
406 env = conf.Finish()
408 if env['DEBUG']:
409 print "Doing a debug build"
410 env.MergeFlags( "-Wall -g -DDEBUG" )
411 else:
412 env.MergeFlags( "-O2" )
414 if env['DEBUG_MESSAGES']:
415 env.MergeFlags( "-DDEBUG_MESSAGES" )
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