root/trunk/libffado/SConstruct

Revision 1154, 19.0 kB (checked in by ppalmers, 16 years ago)

add expat based parsing of the device cache. add compile-time selection between libxml++ and expat. will allow to get rid of the libxml++ dependency on the long run. scons SERIALIZE_USE_EXPAT=0Only compile testedscons SERIALIZE_USE_EXPAT=0

Line 
1 #! /usr/bin/python
2 #
3 # Copyright (C) 2007-2008 Arnold Krille
4 # Copyright (C) 2007-2008 Pieter Palmers
5 # Copyright (C) 2008 Jonathan Woithe
6 #
7 # This file is part of FFADO
8 # FFADO = Free Firewire (pro-)audio drivers for linux
9 #
10 # FFADO is based upon FreeBoB.
11 #
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.
16 #
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.
21 #
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/>.
24 #
25
26 FFADO_API_VERSION="8"
27 FFADO_VERSION="1.999.27"
28
29 import os
30 import re
31 from string import Template
32 import imp
33
34 build_dir = ARGUMENTS.get('BUILDDIR', "")
35 if build_dir:
36         build_base=build_dir+'/'
37         if not os.path.isdir( build_base ):
38                 os.makedirs( build_base )
39         print "Building into: " + build_base
40 else:
41         build_base=''
42
43 destdir = ARGUMENTS.get( 'DESTDIR', "" )
44
45 if not os.path.isdir( "cache" ):
46         os.makedirs( "cache" )
47
48 opts = Options( "cache/"+build_base+"options.cache" )
49
50 #
51 # If this is just to display a help-text for the variable used via ARGUMENTS, then its wrong...
52 opts.Add( "BUILDDIR", "Path to place the built files in", "")
53
54 opts.AddOptions(
55         BoolOption( "DEBUG", """\
56 Toggle debug-build. DEBUG means \"-g -Wall\" and more, otherwise we will use
57   \"-O2\" to optimise.""", True ),
58         BoolOption( "PROFILE", "Build with symbols and other profiling info", False ),
59         PathOption( "PREFIX", "The prefix where ffado will be installed to.", "/usr/local", PathOption.PathAccept ),
60         PathOption( "BINDIR", "Overwrite the directory where apps are installed to.", "$PREFIX/bin", PathOption.PathAccept ),
61         PathOption( "LIBDIR", "Overwrite the directory where libs are installed to.", "$PREFIX/lib", PathOption.PathAccept ),
62         PathOption( "INCLUDEDIR", "Overwrite the directory where headers are installed to.", "$PREFIX/include", PathOption.PathAccept ),
63         PathOption( "SHAREDIR", "Overwrite the directory where misc shared files are installed to.", "$PREFIX/share/libffado", PathOption.PathAccept ),
64         BoolOption( "ENABLE_BEBOB", "Enable/Disable the bebob part.", True ),
65         BoolOption( "ENABLE_FIREWORKS", "Enable/Disable the ECHO Audio FireWorks AV/C part.", True ),
66         BoolOption( "ENABLE_MOTU", "Enable/Disable the MOTU part.", True ),
67         BoolOption( "ENABLE_DICE", "Enable/Disable the DICE part.", False ),
68         BoolOption( "ENABLE_METRIC_HALO", "Enable/Disable the Metric Halo part.", False ),
69         BoolOption( "ENABLE_RME", "Enable/Disable the RME part.", False ),
70         BoolOption( "ENABLE_BOUNCE", "Enable/Disable the BOUNCE part.", False ),
71         BoolOption( "ENABLE_GENERICAVC", """\
72 Enable/Disable the the generic avc part (mainly used by apple).
73   Note that disabling this option might be overwritten by other devices needing
74   this code.""", False ),
75         BoolOption( "ENABLE_ALL", "Enable/Disable support for all devices.", False ),
76         BoolOption( "SERIALIZE_USE_EXPAT", "Use libexpat for XML serialization.", False ),
77         BoolOption( "BUILD_TESTS", """\
78 Build the tests in their directory. As some contain quite some functionality,
79   this is on by default.
80   If you just want to use ffado with jack without the tools, you can disable this.\
81 """, True ),
82     BoolOption( "BUILD_STATIC_TOOLS", "Build a statically linked version of the FFADO tools.", False ),
83     EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'powerpc64', 'none' ), ignorecase=2),
84     BoolOption( "ENABLE_OPTIMIZATIONS", "Enable optimizations and the use of processor specific extentions (MMX/SSE/...).", False ),
85
86         )
87
88 ## Load the builders in config
89 buildenv=os.environ
90 vars_to_check = [
91         'PATH',
92         'PKG_CONFIG_PATH',
93         'LD_LIBRARY_PATH',
94         'XDG_CONFIG_DIRS',
95         'XDG_DATA_DIRS',
96         'HOME',
97 ]
98 for var in vars_to_check:
99         if os.environ.has_key(var):
100                 buildenv[var]=os.environ[var]
101         else:
102                 buildenv[var]=''
103
104 env = Environment( tools=['default','scanreplace','pyuic','dbus','doxygen','pkgconfig'], toolpath=['admin'], ENV = buildenv, options=opts )
105
106
107 Help( """
108 For building ffado you can set different options as listed below. You have to
109 specify them only once, scons will save the last value you used and re-use
110 that.
111 To really undo your settings and return to the factory defaults, remove the
112 "cache"-folder and the file ".sconsign.dblite" from this directory.
113 For example with: "rm -Rf .sconsign.dblite cache"
114
115 Note that this is a development version! Don't complain if its not working!
116 See www.ffado.org for stable releases.
117 """ )
118 Help( opts.GenerateHelpText( env ) )
119
120 # make sure the necessary dirs exist
121 if not os.path.isdir( "cache/" + build_base ):
122         os.makedirs( "cache/" + build_base )
123 if not os.path.isdir( 'cache/objects' ):
124         os.makedirs( 'cache/objects' )
125
126 CacheDir( 'cache/objects' )
127
128 opts.Save( 'cache/' + build_base + "options.cache", env )
129
130 def ConfigGuess( context ):
131         context.Message( "Trying to find the system triple: " )
132         ret = os.popen( "admin/config.guess" ).read()[:-1]
133         context.Result( ret )
134         return ret
135
136 def CheckForApp( context, app ):
137         context.Message( "Checking wether '" + app + "' executes " )
138         ret = context.TryAction( app )
139         context.Result( ret[0] )
140         return ret[0]
141
142 def CheckForPyModule( context, module ):
143         context.Message( "Checking for the python module '" + module + "' " )
144         ret = True
145         try:
146                 imp.find_module( module )
147         except ImportError:
148                 ret = False
149         context.Result( ret )
150         return ret
151
152 tests = {
153         "ConfigGuess" : ConfigGuess,
154         "CheckForApp" : CheckForApp,
155         "CheckForPyModule": CheckForPyModule,
156 }
157 tests.update( env['PKGCONFIG_TESTS'] )
158 tests.update( env['PYUIC_TESTS'] )
159
160 conf = Configure( env,
161         custom_tests = tests,
162         conf_dir = "cache/" + build_base,
163         log_file = "cache/" + build_base + 'config.log' )
164
165 if env['SERIALIZE_USE_EXPAT']:
166         env['SERIALIZE_USE_EXPAT']=1
167 else:
168         env['SERIALIZE_USE_EXPAT']=0
169
170 if not env.GetOption('clean'):
171         #
172         # Check if the environment can actually compile c-files by checking for a
173         # header shipped with gcc.
174         #
175         if not conf.CheckHeader( "stdio.h", language="C" ):
176                 print "It seems as if stdio.h is missing. This probably means that your build environment is broken, please make sure you have a working c-compiler and libstdc installed and usable."
177                 Exit( 1 )
178         #
179         # ... and do the same with a c++-header. Because some distributions have
180         # distinct packages for gcc and g++.
181         #
182         if not conf.CheckHeader( "iostream", language="C++" ):
183                 print "It seems as if iostream is missing. This probably means that your build environment is broken, please make sure you have a working c++-compiler installed and usable."
184                 Exit( 1 )
185
186         #
187         # The following checks are for headers and libs and packages we need.
188         #
189         allpresent = 1;
190         # for DBUS C++ bindings
191         allpresent &= conf.CheckHeader( "expat.h" )
192         allpresent &= conf.CheckLib( 'expat', 'XML_ExpatVersion', '#include <expat.h>' )
193        
194         allpresent &= conf.CheckForPKGConfig();
195
196         pkgs = {
197                 'libraw1394' : '1.3.0',
198                 'libavc1394' : '0.5.3',
199                 'libiec61883' : '1.1.0',
200                 'dbus-1' : '1.0',
201                 }
202         if not env['SERIALIZE_USE_EXPAT']:
203                 pkgs['libxml++-2.6'] = '2.13.0'
204
205         for pkg in pkgs:
206                 name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
207                 env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
208                 if env['%s_FLAGS'%name2] == 0:
209                         allpresent &= 0
210
211         if not allpresent:
212                 print """
213 (At least) One of the dependencies is missing. I can't go on without it, please
214 install the needed packages for each of the lines saying "no".
215 (Remember to also install the *-devel packages!)
216
217 And remember to remove the cache with "rm -Rf .sconsign.dblite cache" so the
218 results above get rechecked.
219 """
220                 Exit( 1 )
221
222         # Check for C99 lrint() and lrintf() functions used to convert from
223         # float to integer more efficiently via float_cast.h.  If not
224         # present the standard slower methods will be used instead.  This
225         # might not be the best way of testing for these but it's the only
226         # way which seems to work properly.  CheckFunc() fails due to
227         # argument count problems.
228         oldcf = env['CFLAGS']
229         oldcf = env.Append(CFLAGS = '-std=c99')
230         if conf.CheckLibWithHeader( "m", "math.h", "c", "lrint(3.2);" ):
231                 HAVE_LRINT = 1
232         else:
233                 HAVE_LRINT = 0
234         if conf.CheckLibWithHeader( "m", "math.h", "c", "lrintf(3.2);" ):
235                 HAVE_LRINTF = 1
236         else:
237                 HAVE_LRINTF = 0
238         env['HAVE_LRINT'] = HAVE_LRINT;
239         env['HAVE_LRINTF'] = HAVE_LRINTF;
240         env.Replace(CFLAGS=oldcf)
241
242         #
243         # Optional checks follow:
244         #
245
246 if conf.CheckForApp( "which pyuic" ) and conf.CheckForPyModule( 'dbus' ) and conf.CheckForPyModule( 'qt' ):
247         env['PYUIC'] = True
248
249         if conf.CheckForApp( "xdg-desktop-menu --help" ):
250                 env['XDG_TOOLS'] = True
251         else:
252                 print """
253 I couldn't find the program 'xdg-desktop-menu'. Together with xdg-icon-resource
254 this is needed to add the fancy entry to your menu. But the mixer will be installed, you can start it by executing "ffadomixer".
255 """
256
257 else:
258         print """
259 I couldn't find all the prerequisites ('pyuic' and the python-modules 'dbus' and
260 'qt', the packages could be named like dbus-python and PyQt) to build the mixer.
261 Therefor the mixer won't get installed.
262 """
263
264 config_guess = conf.ConfigGuess()
265
266 env = conf.Finish()
267
268 if env['DEBUG']:
269         print "Doing a DEBUG build"
270         # -Werror could be added to, which would force the devs to really remove all the warnings :-)
271         env.AppendUnique( CCFLAGS=["-DDEBUG","-Wall","-g"] )
272         env.AppendUnique( CFLAGS=["-DDEBUG","-Wall","-g"] )
273 else:
274         env.AppendUnique( CCFLAGS=["-O2","-DNDEBUG"] )
275         env.AppendUnique( CFLAGS=["-O2","-DNDEBUG"] )
276
277 if env['PROFILE']:
278         print "Doing a PROFILE build"
279         # -Werror could be added to, which would force the devs to really remove all the warnings :-)
280         env.AppendUnique( CCFLAGS=["-Wall","-g"] )
281         env.AppendUnique( CFLAGS=["-Wall","-g"] )
282
283
284 # this is required to indicate that the DBUS version we use has support
285 # for platform dependent threading init functions
286 # this is true for DBUS >= 0.96 or so. Since we require >= 1.0 it is
287 # always true
288 env.AppendUnique( CCFLAGS=["-DDBUS_HAS_THREADS_INIT_DEFAULT"] )
289
290 if env['ENABLE_ALL']:
291         env['ENABLE_BEBOB'] = True
292         env['ENABLE_FIREWORKS'] = True
293         env['ENABLE_MOTU'] = True
294         env['ENABLE_DICE'] = True
295         env['ENABLE_METRIC_HALO'] = True
296         env['ENABLE_RME'] = True
297         env['ENABLE_BOUNCE'] = True
298
299 if env['ENABLE_BEBOB'] or env['ENABLE_DICE'] or env['ENABLE_BOUNCE'] or env['ENABLE_FIREWORKS']:
300         env['ENABLE_GENERICAVC'] = True
301
302 env['BUILD_STATIC_LIB'] = False
303 if env['BUILD_STATIC_TOOLS']:
304     print "Building static versions of the tools..."
305     env['BUILD_STATIC_LIB'] = True
306
307 if build_base:
308         env['build_base']="#/"+build_base
309 else:
310         env['build_base']="#/"
311
312 #
313 # Uppercase variables are for usage in code, lowercase versions for usage in
314 # scons-files for installing.
315 #
316 env['BINDIR'] = Template( env['BINDIR'] ).safe_substitute( env )
317 env['LIBDIR'] = Template( env['LIBDIR'] ).safe_substitute( env )
318 env['INCLUDEDIR'] = Template( env['INCLUDEDIR'] ).safe_substitute( env )
319 env['SHAREDIR'] = Template( env['SHAREDIR'] ).safe_substitute( env )
320 env['bindir'] = Template( destdir + env['BINDIR'] ).safe_substitute( env )
321 env['libdir'] = Template( destdir + env['LIBDIR'] ).safe_substitute( env )
322 env['includedir'] = Template( destdir + env['INCLUDEDIR'] ).safe_substitute( env )
323 env['sharedir'] = Template( destdir + env['SHAREDIR'] ).safe_substitute( env )
324
325 env.Command( target=env['sharedir'], source="", action=Mkdir( env['sharedir'] ) )
326
327 env.Alias( "install", env['libdir'] )
328 env.Alias( "install", env['includedir'] )
329 env.Alias( "install", env['sharedir'] )
330 env.Alias( "install", env['bindir'] )
331
332 #
333 # shamelessly copied from the Ardour scons file
334 #
335
336 opt_flags = []
337 env['USE_SSE'] = 0
338
339 # guess at the platform, used to define compiler flags
340
341 config_cpu = 0
342 config_arch = 1
343 config_kernel = 2
344 config_os = 3
345 config = config_guess.split ("-")
346
347 # Autodetect
348 if env['DIST_TARGET'] == 'auto':
349     if re.search ("x86_64", config[config_cpu]) != None:
350         env['DIST_TARGET'] = 'x86_64'
351     elif re.search("i[0-5]86", config[config_cpu]) != None:
352         env['DIST_TARGET'] = 'i386'
353     elif re.search("powerpc64", config[config_cpu]) != None:
354         env['DIST_TARGET'] = 'powerpc64'
355     elif re.search("powerpc", config[config_cpu]) != None:
356         env['DIST_TARGET'] = 'powerpc'
357     else:
358         env['DIST_TARGET'] = 'i686'
359     print "Detected DIST_TARGET = " + env['DIST_TARGET']
360
361 if ((re.search ("i[0-9]86", config[config_cpu]) != None) or (re.search ("x86_64", config[config_cpu]) != None) or (re.search ("powerpc", config[config_cpu]) != None)):
362    
363     build_host_supports_sse = 0
364     build_host_supports_sse2 = 0
365     build_host_supports_sse3 = 0
366
367     if config[config_kernel] == 'linux' :
368        
369         if (env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64'):
370            
371             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
372             x86_flags = flag_line.split (": ")[1:][0].split ()
373            
374             if "mmx" in x86_flags:
375                 opt_flags.append ("-mmmx")
376             if "sse" in x86_flags:
377                 build_host_supports_sse = 1
378             if "sse2" in x86_flags:
379                 build_host_supports_sse2 = 1
380             #if "sse3" in x86_flags:
381                 #build_host_supports_sse3 = 1
382             if "3dnow" in x86_flags:
383                 opt_flags.append ("-m3dnow")
384            
385             if config[config_cpu] == "i586":
386                 opt_flags.append ("-march=i586")
387             elif config[config_cpu] == "i686":
388                 opt_flags.append ("-march=i686")
389
390         elif (env['DIST_TARGET'] == 'powerpc') or (env['DIST_TARGET'] == 'powerpc64'):
391
392             cpu_line = os.popen ("cat /proc/cpuinfo | grep '^cpu'").read()[:-1]
393
394             ppc_type = cpu_line.split (": ")[1]
395             if re.search ("altivec", ppc_type) != None:
396                 opt_flags.append ("-maltivec")
397                 opt_flags.append ("-mabi=altivec")
398
399             ppc_type = ppc_type.split (", ")[0]
400             if re.match ("74[0145][0578]A?", ppc_type) != None:
401                 opt_flags.append ("-mcpu=7400")
402                 opt_flags.append ("-mtune=7400")
403             elif re.match ("750", ppc_type) != None:
404                 opt_flags.append ("-mcpu=750")
405                 opt_flags.append ("-mtune=750")
406             elif re.match ("PPC970", ppc_type) != None:
407                 opt_flags.append ("-mcpu=970")
408                 opt_flags.append ("-mtune=970")
409             elif re.match ("Cell Broadband Engine", ppc_type) != None:
410                 opt_flags.append ("-mcpu=cell")
411                 opt_flags.append ("-mtune=cell")
412
413     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) \
414        and build_host_supports_sse and env['ENABLE_OPTIMIZATIONS']:
415         opt_flags.extend (["-msse", "-mfpmath=sse"])
416         env['USE_SSE'] = 1
417
418     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) \
419        and build_host_supports_sse2 and env['ENABLE_OPTIMIZATIONS']:
420         opt_flags.extend (["-msse2"])
421         env['USE_SSE2'] = 1
422
423     #if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) \
424        #and build_host_supports_sse2 and env['ENABLE_OPTIMIZATIONS']:
425         #opt_flags.extend (["-msse3"])
426         #env['USE_SSE3'] = 1
427
428     # build for 64-bit userland? (TODO: add x86_64 here, too?)
429     if env['DIST_TARGET'] == "powerpc64":
430         print "Doing a 64-bit build"
431         env.AppendUnique( CCFLAGS=["-m64"] )
432         env.AppendUnique( CFLAGS=["-m64"] )
433     else:
434         print "Doing a 32-bit build"
435         env.AppendUnique( CCFLAGS=["-m32"] )
436         env.AppendUnique( CFLAGS=["-m32"] )
437
438 # end of processor-specific section
439 if env['ENABLE_OPTIMIZATIONS']:
440     opt_flags.extend (["-fomit-frame-pointer","-ffast-math","-funroll-loops"])
441     env.AppendUnique( CCFLAGS=opt_flags )
442     env.AppendUnique( CFLAGS=opt_flags )
443     print "Doing an optimized build..."
444
445 env['REVISION'] = os.popen('svnversion .').read()[:-1]
446 # This may be as simple as '89' or as complex as '4123:4184M'.
447 # We'll just use the last bit.
448 env['REVISION'] = env['REVISION'].split(':')[-1]
449
450 if env['REVISION'] == 'exported':
451         env['REVISION'] = ''
452
453 env['FFADO_API_VERSION']=FFADO_API_VERSION
454
455 env['PACKAGE'] = "libffado"
456 env['VERSION'] = FFADO_VERSION
457 env['LIBVERSION'] = "1.0.0"
458
459 env['CONFIGDIR'] = "~/.ffado"
460 env['CACHEDIR'] = "~/.ffado"
461
462 env['REGISTRATION_URL'] = "http://ffado.org/deviceregistration/register.php?action=register"
463
464 #
465 # To have the top_srcdir as the doxygen-script is used from auto*
466 #
467 env['top_srcdir'] = env.Dir( "." ).abspath
468
469 #
470 # Start building
471 #
472 env.ScanReplace( "config.h.in" )
473 # ensure that the config.h is updated with the version
474
475 env.Depends( "config.h", "SConstruct" )
476 env.Depends( "config.h", 'cache/' + build_base + "options.cache" )
477
478 # update config.h whenever the SVN revision changes
479 env.Depends( "config.h", env.Value(env['REVISION']))
480
481 env.Depends( "libffado.pc", "SConstruct" )
482 pkgconfig = env.ScanReplace( "libffado.pc.in" )
483 env.Install( env['libdir'] + '/pkgconfig', pkgconfig )
484
485 subdirs=['external','src','libffado','tests','support','doc']
486 if build_base:
487         env.SConscript( dirs=subdirs, exports="env", build_dir=build_base+subdir )
488 else:
489         env.SConscript( dirs=subdirs, exports="env" )
490
491 if 'debian' in COMMAND_LINE_TARGETS:
492         env.SConscript("deb/SConscript", exports="env")
493
494 # By default only src is built but all is cleaned
495 if not env.GetOption('clean'):
496     Default( 'src' )
497     Default( 'support' )
498     if env['BUILD_TESTS']:
499         Default( 'tests' )
500
501 #
502 # Deal with the DESTDIR vs. xdg-tools conflict (which is basicely that the
503 # xdg-tools can't deal with DESTDIR, so the packagers have to deal with this
504 # their own :-/
505 #
506 if len(destdir) > 0:
507         if not len( ARGUMENTS.get( "WILL_DEAL_WITH_XDG_MYSELF", "" ) ) > 0:
508                 print """
509 WARNING!
510 You are using the (packagers) option DESTDIR to install this package to a
511 different place than the real prefix. As the xdg-tools can't cope with
512 that, the .desktop-files are not installed by this build, you have to
513 deal with them your own.
514 (And you have to look into the SConstruct to learn how to disable this
515 message.)
516 """
517 else:
518
519         def CleanAction( action ):
520                 if env.GetOption( "clean" ):
521                         env.Execute( action )
522
523         if env.has_key( 'XDG_TOOLS' ) and env.has_key( 'PYUIC' ):
524                 if not env.GetOption("clean"):
525                         action = "install"
526                 else:
527                         action = "uninstall"
528                 mixerdesktopaction = env.Action( "xdg-desktop-menu %s support/xdg/ffado.org-ffadomixer.desktop" % action )
529                 mixericonaction = env.Action( "xdg-icon-resource %s --size 64 --context apps support/xdg/hi64-apps-ffado.png" % action )
530                 env.Command( "__xdgstuff1", None, mixerdesktopaction )
531                 env.Command( "__xdgstuff2", None, mixericonaction )
532                 env.Alias( "install", ["__xdgstuff1", "__xdgstuff2" ] )
533                 CleanAction( mixerdesktopaction )
534                 CleanAction( mixericonaction )
535
536 #
537 # Create a tags-file for easier emacs/vim-source-browsing
538 #  I don't know if the dependency is right...
539 #
540 findcommand = "find . \( -path \"*.h\" -o -path \"*.cpp\" -o -path \"*.c\" \) \! -path \"*.svn*\" \! -path \"./doc*\" \! -path \"./cache*\""
541 env.Command( "tags", "", findcommand + " |xargs ctags" )
542 env.Command( "TAGS", "", findcommand + " |xargs etags" )
543 env.AlwaysBuild( "tags", "TAGS" )
544 env.NoCache( "tags", "TAGS" )
545
Note: See TracBrowser for help on using the browser.