root/trunk/libffado/SConstruct

Revision 1119, 17.0 kB (checked in by ppalmers, 16 years ago)

development version number

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( "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                 'libxml++-2.6' : '2.13.0',
194                 'dbus-1' : '1.0',
195                 }
196         for pkg in pkgs:
197                 name2 = pkg.replace("+","").replace(".","").replace("-","").upper()
198                 env['%s_FLAGS' % name2] = conf.GetPKGFlags( pkg, pkgs[pkg] )
199                 if env['%s_FLAGS'%name2] == 0:
200                         allpresent &= 0
201
202         if not allpresent:
203                 print """
204 (At least) One of the dependencies is missing. I can't go on without it, please
205 install the needed packages for each of the lines saying "no".
206 (Remember to also install the *-devel packages!)
207
208 And remember to remove the cache with "rm -Rf .sconsign.dblite cache" so the
209 results above get rechecked.
210 """
211                 Exit( 1 )
212
213         # Check for C99 lrint() and lrintf() functions used to convert from
214         # float to integer more efficiently via float_cast.h.  If not
215         # present the standard slower methods will be used instead.  This
216         # might not be the best way of testing for these but it's the only
217         # way which seems to work properly.  CheckFunc() fails due to
218         # argument count problems.
219         oldcf = env['CFLAGS']
220         oldcf = env.Append(CFLAGS = '-std=c99')
221         if conf.CheckLibWithHeader( "m", "math.h", "c", "lrint(3.2);" ):
222                 HAVE_LRINT = 1
223         else:
224                 HAVE_LRINT = 0
225         if conf.CheckLibWithHeader( "m", "math.h", "c", "lrintf(3.2);" ):
226                 HAVE_LRINTF = 1
227         else:
228                 HAVE_LRINTF = 0
229         env['HAVE_LRINT'] = HAVE_LRINT;
230         env['HAVE_LRINTF'] = HAVE_LRINTF;
231         env.Replace(CFLAGS=oldcf)
232
233         #
234         # Optional checks follow:
235         #
236
237 if conf.CheckForApp( "which pyuic" ) and conf.CheckForPyModule( 'dbus' ) and conf.CheckForPyModule( 'qt' ):
238         env['PYUIC'] = True
239
240         if conf.CheckForApp( "xdg-desktop-menu --help" ):
241                 env['XDG_TOOLS'] = True
242         else:
243                 print """
244 I couldn't find the program 'xdg-desktop-menu'. Together with xdg-icon-resource
245 this is needed to add the fancy entry to your menu. But the mixer will be installed, you can start it by executing "ffadomixer".
246 """
247
248 else:
249         print """
250 I couldn't find all the prerequisites ('pyuic' and the python-modules 'dbus' and
251 'qt', the packages could be named like dbus-python and PyQt) to build the mixer.
252 Therefor the mixer won't get installed.
253 """
254
255 config_guess = conf.ConfigGuess()
256
257 env = conf.Finish()
258
259 if env['DEBUG']:
260         print "Doing a DEBUG build"
261         # -Werror could be added to, which would force the devs to really remove all the warnings :-)
262         env.AppendUnique( CCFLAGS=["-DDEBUG","-Wall","-g"] )
263         env.AppendUnique( CFLAGS=["-DDEBUG","-Wall","-g"] )
264 else:
265         env.AppendUnique( CCFLAGS=["-O2","-DNDEBUG"] )
266         env.AppendUnique( CFLAGS=["-O2","-DNDEBUG"] )
267
268 if env['PROFILE']:
269         print "Doing a PROFILE build"
270         # -Werror could be added to, which would force the devs to really remove all the warnings :-)
271         env.AppendUnique( CCFLAGS=["-Wall","-g"] )
272         env.AppendUnique( CFLAGS=["-Wall","-g"] )
273
274
275 # this is required to indicate that the DBUS version we use has support
276 # for platform dependent threading init functions
277 # this is true for DBUS >= 0.96 or so. Since we require >= 1.0 it is
278 # always true
279 env.AppendUnique( CCFLAGS=["-DDBUS_HAS_THREADS_INIT_DEFAULT"] )
280
281 if env['ENABLE_ALL']:
282         env['ENABLE_BEBOB'] = True
283         env['ENABLE_FIREWORKS'] = True
284         env['ENABLE_MOTU'] = True
285         env['ENABLE_DICE'] = True
286         env['ENABLE_METRIC_HALO'] = True
287         env['ENABLE_RME'] = True
288         env['ENABLE_BOUNCE'] = True
289
290 if env['ENABLE_BEBOB'] or env['ENABLE_DICE'] or env['ENABLE_BOUNCE'] or env['ENABLE_FIREWORKS']:
291         env['ENABLE_GENERICAVC'] = True
292
293 env['BUILD_STATIC_LIB'] = False
294 if env['BUILD_STATIC_TOOLS']:
295     print "Building static versions of the tools..."
296     env['BUILD_STATIC_LIB'] = True
297
298 if build_base:
299         env['build_base']="#/"+build_base
300 else:
301         env['build_base']="#/"
302
303 #
304 # Uppercase variables are for usage in code, lowercase versions for usage in
305 # scons-files for installing.
306 #
307 env['BINDIR'] = Template( env['BINDIR'] ).safe_substitute( env )
308 env['LIBDIR'] = Template( env['LIBDIR'] ).safe_substitute( env )
309 env['INCLUDEDIR'] = Template( env['INCLUDEDIR'] ).safe_substitute( env )
310 env['SHAREDIR'] = Template( env['SHAREDIR'] ).safe_substitute( env )
311 env['bindir'] = Template( destdir + env['BINDIR'] ).safe_substitute( env )
312 env['libdir'] = Template( destdir + env['LIBDIR'] ).safe_substitute( env )
313 env['includedir'] = Template( destdir + env['INCLUDEDIR'] ).safe_substitute( env )
314 env['sharedir'] = Template( destdir + env['SHAREDIR'] ).safe_substitute( env )
315
316 env.Command( target=env['sharedir'], source="", action=Mkdir( env['sharedir'] ) )
317
318 env.Alias( "install", env['libdir'] )
319 env.Alias( "install", env['includedir'] )
320 env.Alias( "install", env['sharedir'] )
321 env.Alias( "install", env['bindir'] )
322
323 #
324 # shamelessly copied from the Ardour scons file
325 #
326
327 opt_flags = []
328 env['USE_SSE'] = 0
329
330 # guess at the platform, used to define compiler flags
331
332 config_cpu = 0
333 config_arch = 1
334 config_kernel = 2
335 config_os = 3
336 config = config_guess.split ("-")
337
338 # Autodetect
339 if env['DIST_TARGET'] == 'auto':
340     if re.search ("x86_64", config[config_cpu]) != None:
341         env['DIST_TARGET'] = 'x86_64'
342     elif re.search("i[0-5]86", config[config_cpu]) != None:
343         env['DIST_TARGET'] = 'i386'
344     else:
345         env['DIST_TARGET'] = 'i686'
346     print "Detected DIST_TARGET = " + env['DIST_TARGET']
347
348 if ((re.search ("i[0-9]86", config[config_cpu]) != None) or (re.search ("x86_64", config[config_cpu]) != None)):
349    
350     build_host_supports_sse = 0
351     build_host_supports_sse2 = 0
352     build_host_supports_sse3 = 0
353
354     if config[config_kernel] == 'linux' :
355        
356         if env['DIST_TARGET'] != 'i386':
357            
358             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
359             x86_flags = flag_line.split (": ")[1:][0].split ()
360            
361             if "mmx" in x86_flags:
362                 opt_flags.append ("-mmmx")
363             if "sse" in x86_flags:
364                 build_host_supports_sse = 1
365             if "sse2" in x86_flags:
366                 build_host_supports_sse2 = 1
367             #if "sse3" in x86_flags:
368                 #build_host_supports_sse3 = 1
369             if "3dnow" in x86_flags:
370                 opt_flags.append ("-m3dnow")
371            
372             if config[config_cpu] == "i586":
373                 opt_flags.append ("-march=i586")
374             elif config[config_cpu] == "i686":
375                 opt_flags.append ("-march=i686")
376
377     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) \
378        and build_host_supports_sse and env['ENABLE_OPTIMIZATIONS']:
379         opt_flags.extend (["-msse", "-mfpmath=sse"])
380         env['USE_SSE'] = 1
381
382     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) \
383        and build_host_supports_sse2 and env['ENABLE_OPTIMIZATIONS']:
384         opt_flags.extend (["-msse2"])
385         env['USE_SSE2'] = 1
386
387     #if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) \
388        #and build_host_supports_sse2 and env['ENABLE_OPTIMIZATIONS']:
389         #opt_flags.extend (["-msse3"])
390         #env['USE_SSE3'] = 1
391
392 # end of processor-specific section
393 if env['ENABLE_OPTIMIZATIONS']:
394     opt_flags.extend (["-fomit-frame-pointer","-ffast-math","-funroll-loops"])
395     env.AppendUnique( CCFLAGS=opt_flags )
396     env.AppendUnique( CFLAGS=opt_flags )
397     print "Doing an optimized build..."
398
399 env['REVISION'] = os.popen('svnversion .').read()[:-1]
400 # This may be as simple as '89' or as complex as '4123:4184M'.
401 # We'll just use the last bit.
402 env['REVISION'] = env['REVISION'].split(':')[-1]
403
404 if env['REVISION'] == 'exported':
405         env['REVISION'] = ''
406
407 env['FFADO_API_VERSION']=FFADO_API_VERSION
408
409 env['PACKAGE'] = "libffado"
410 env['VERSION'] = FFADO_VERSION
411 env['LIBVERSION'] = "1.0.0"
412
413 env['CONFIGDIR'] = "~/.ffado"
414 env['CACHEDIR'] = "~/.ffado"
415
416 env['REGISTRATION_URL'] = "http://ffado.org/deviceregistration/register.php?action=register"
417
418 #
419 # To have the top_srcdir as the doxygen-script is used from auto*
420 #
421 env['top_srcdir'] = env.Dir( "." ).abspath
422
423 #
424 # Start building
425 #
426 env.ScanReplace( "config.h.in" )
427 # ensure that the config.h is updated with the version
428
429 env.Depends( "config.h", "SConstruct" )
430 env.Depends( "config.h", 'cache/' + build_base + "options.cache" )
431
432 env.Depends( "libffado.pc", "SConstruct" )
433 pkgconfig = env.ScanReplace( "libffado.pc.in" )
434 env.Install( env['libdir'] + '/pkgconfig', pkgconfig )
435
436 subdirs=['external','src','libffado','tests','support','doc']
437 if build_base:
438         env.SConscript( dirs=subdirs, exports="env", build_dir=build_base+subdir )
439 else:
440         env.SConscript( dirs=subdirs, exports="env" )
441
442 if 'debian' in COMMAND_LINE_TARGETS:
443         env.SConscript("deb/SConscript", exports="env")
444
445 # By default only src is built but all is cleaned
446 if not env.GetOption('clean'):
447     Default( 'src' )
448     Default( 'support' )
449     if env['BUILD_TESTS']:
450         Default( 'tests' )
451
452 #
453 # Deal with the DESTDIR vs. xdg-tools conflict (which is basicely that the
454 # xdg-tools can't deal with DESTDIR, so the packagers have to deal with this
455 # their own :-/
456 #
457 if len(destdir) > 0:
458         if not len( ARGUMENTS.get( "WILL_DEAL_WITH_XDG_MYSELF", "" ) ) > 0:
459                 print """
460 WARNING!
461 You are using the (packagers) option DESTDIR to install this package to a
462 different place than the real prefix. As the xdg-tools can't cope with
463 that, the .desktop-files are not installed by this build, you have to
464 deal with them your own.
465 (And you have to look into the SConstruct to learn how to disable this
466 message.)
467 """
468 else:
469
470         def CleanAction( action ):
471                 if env.GetOption( "clean" ):
472                         env.Execute( action )
473
474         if env.has_key( 'XDG_TOOLS' ) and env.has_key( 'PYUIC' ):
475                 if not env.GetOption("clean"):
476                         action = "install"
477                 else:
478                         action = "uninstall"
479                 mixerdesktopaction = env.Action( "xdg-desktop-menu %s support/xdg/ffado.org-ffadomixer.desktop" % action )
480                 mixericonaction = env.Action( "xdg-icon-resource %s --size 64 --context apps support/xdg/hi64-apps-ffado.png" % action )
481                 env.Command( "__xdgstuff1", None, mixerdesktopaction )
482                 env.Command( "__xdgstuff2", None, mixericonaction )
483                 env.Alias( "install", ["__xdgstuff1", "__xdgstuff2" ] )
484                 CleanAction( mixerdesktopaction )
485                 CleanAction( mixericonaction )
486
487 #
488 # Create a tags-file for easier emacs/vim-source-browsing
489 #  I don't know if the dependency is right...
490 #
491 findcommand = "find . \( -path \"*.h\" -o -path \"*.cpp\" -o -path \"*.c\" \) \! -path \"*.svn*\" \! -path \"./doc*\" \! -path \"./cache*\""
492 env.Command( "tags", "", findcommand + " |xargs ctags" )
493 env.Command( "TAGS", "", findcommand + " |xargs etags" )
494 env.AlwaysBuild( "tags", "TAGS" )
495 env.NoCache( "tags", "TAGS" )
496
Note: See TracBrowser for help on using the browser.