root/trunk/libffado/SConstruct

Revision 967, 16.7 kB (checked in by ppalmers, 13 years ago)

- first attempt at not causing total havoc when devices are removed from the bus.

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