Protect ardour from sessions with errant capture sources stored in the
[ardour.git] / SConstruct
1 # -*- python -*-
2
3 import os
4 import sys
5 import re
6 import shutil
7 import glob
8 import errno
9 import time
10 import platform
11 import string
12 import commands
13 from sets import Set
14 import SCons.Node.FS
15
16 SConsignFile()
17 EnsureSConsVersion(0, 96)
18
19 ardour_version = '2.0.3'
20
21 subst_dict = { }
22
23 #
24 # Command-line options
25 #
26
27 opts = Options('scache.conf')
28 opts.AddOptions(
29     ('ARCH', 'Set architecture-specific compilation flags by hand (all flags as 1 argument)',''),
30     BoolOption('AUDIOUNITS', 'Compile with Apple\'s AudioUnit library. (experimental)', 0),
31     BoolOption('COREAUDIO', 'Compile with Apple\'s CoreAudio library', 0),
32     BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 0),
33     PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'),
34     EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'none' ), ignorecase=2),
35     BoolOption('DMALLOC', 'Compile and link using the dmalloc library', 0),
36     BoolOption('EXTRA_WARN', 'Compile with -Wextra, -ansi, and -pedantic.  Might break compilation.  For pedants', 0),
37     BoolOption('FFT_ANALYSIS', 'Include FFT analysis window', 0),
38     BoolOption('FPU_OPTIMIZATION', 'Build runtime checked assembler code', 1),
39     BoolOption('LIBLO', 'Compile with support for liblo library', 1),
40     BoolOption('NLS', 'Set to turn on i18n support', 1),
41     PathOption('PREFIX', 'Set the install "prefix"', '/usr/local'),
42     BoolOption('SURFACES', 'Build support for control surfaces', 1),
43     BoolOption('SYSLIBS', 'USE AT YOUR OWN RISK: CANCELS ALL SUPPORT FROM ARDOUR AUTHORS: Use existing system versions of various libraries instead of internal ones', 0),
44     BoolOption('UNIVERSAL', 'Compile as universal binary.  Requires that external libraries are already universal.', 0),
45     BoolOption('VERSIONED', 'Add revision information to ardour/gtk executable name inside the build directory', 0),
46     BoolOption('VST', 'Compile with support for VST', 0),
47     BoolOption('GPROFILE', 'Compile with support for gprofile (Developers only)', 0),
48     BoolOption('TRANZPORT', 'Compile with support for Frontier Designs (if libusb is available)', 1)
49 )
50
51 #----------------------------------------------------------------------
52 # a handy helper that provides a way to merge compile/link information
53 # from multiple different "environments"
54 #----------------------------------------------------------------------
55 #
56 class LibraryInfo(Environment):
57     def __init__(self,*args,**kw):
58         Environment.__init__ (self,*args,**kw)
59     
60     def Merge (self,others):
61         for other in others:
62             self.Append (LIBS = other.get ('LIBS',[]))
63             self.Append (LIBPATH = other.get ('LIBPATH', []))
64             self.Append (CPPPATH = other.get('CPPPATH', []))
65             self.Append (LINKFLAGS = other.get('LINKFLAGS', []))
66         self.Replace(LIBPATH = list(Set(self.get('LIBPATH', []))))
67         self.Replace(CPPPATH = list(Set(self.get('CPPPATH',[]))))
68         #doing LINKFLAGS breaks -framework
69         #doing LIBS break link order dependency
70     
71     def ENV_update(self, src_ENV):
72         for k in src_ENV.keys():
73             if k in self['ENV'].keys() and k in [ 'PATH', 'LD_LIBRARY_PATH',
74                                                   'LIB', 'INCLUDE' ]:
75                 self['ENV'][k]=SCons.Util.AppendPath(self['ENV'][k], src_ENV[k])
76             else:
77                 self['ENV'][k]=src_ENV[k]
78
79 env = LibraryInfo (options = opts,
80                    CPPPATH = [ '.' ],
81                    VERSION = ardour_version,
82                    TARBALL='ardour-' + ardour_version + '.tar.bz2',
83                    DISTFILES = [ ],
84                    DISTTREE  = '#ardour-' + ardour_version,
85                    DISTCHECKDIR = '#ardour-' + ardour_version + '/check'
86                    )
87
88 env.ENV_update(os.environ)
89
90 #----------------------------------------------------------------------
91 # Builders
92 #----------------------------------------------------------------------
93
94 # Handy subst-in-file builder
95 #
96
97 def do_subst_in_file(targetfile, sourcefile, dict):
98     """Replace all instances of the keys of dict with their values.
99     For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
100     then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
101     """
102     try:
103         f = open(sourcefile, 'rb')
104         contents = f.read()
105         f.close()
106     except:
107         raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
108     for (k,v) in dict.items():
109         contents = re.sub(k, v, contents)
110     try:
111         f = open(targetfile, 'wb')
112         f.write(contents)
113         f.close()
114     except:
115         raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
116     return 0 # success
117
118 def subst_in_file(target, source, env):
119     if not env.has_key('SUBST_DICT'):
120         raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
121     d = dict(env['SUBST_DICT']) # copy it
122     for (k,v) in d.items():
123         if callable(v):
124             d[k] = env.subst(v())
125         elif SCons.Util.is_String(v):
126             d[k]=env.subst(v)
127         else:
128             raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
129     for (t,s) in zip(target, source):
130         return do_subst_in_file(str(t), str(s), d)
131
132 def subst_in_file_string(target, source, env):
133     """This is what gets printed on the console."""
134     return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
135                       for (t,s) in zip(target, source)])
136
137 def subst_emitter(target, source, env):
138     """Add dependency from substituted SUBST_DICT to target.
139     Returns original target, source tuple unchanged.
140     """
141     d = env['SUBST_DICT'].copy() # copy it
142     for (k,v) in d.items():
143         if callable(v):
144             d[k] = env.subst(v())
145         elif SCons.Util.is_String(v):
146             d[k]=env.subst(v)
147     Depends(target, SCons.Node.Python.Value(d))
148     # Depends(target, source) # this doesn't help the install-sapphire-linux.sh problem
149     return target, source
150
151 subst_action = Action (subst_in_file, subst_in_file_string)
152 env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
153
154 #
155 # internationalization
156 #
157
158 # po_builder: builder function to copy po files to the parent directory while updating them
159 #
160 # first source:  .po file
161 # second source: .pot file
162 #
163
164 def po_builder(target,source,env):
165     os.spawnvp (os.P_WAIT, 'cp', ['cp', str(source[0]), str(target[0])])
166     args = [ 'msgmerge',
167              '--update',
168              str(target[0]),
169              str(source[1])
170              ]
171     print 'Updating ' + str(target[0])
172     return os.spawnvp (os.P_WAIT, 'msgmerge', args)
173
174 po_bld = Builder (action = po_builder)
175 env.Append(BUILDERS = {'PoBuild' : po_bld})
176
177 # mo_builder: builder function for (binary) message catalogs (.mo)
178 #
179 # first source:  .po file
180 #
181
182 def mo_builder(target,source,env):
183     args = [ 'msgfmt',
184              '-c',
185              '-o',
186              target[0].get_path(),
187              source[0].get_path()
188              ]
189     return os.spawnvp (os.P_WAIT, 'msgfmt', args)
190
191 mo_bld = Builder (action = mo_builder)
192 env.Append(BUILDERS = {'MoBuild' : mo_bld})
193
194 # pot_builder: builder function for message templates (.pot)
195 #
196 # source: list of C/C++ etc. files to extract messages from
197 #
198
199 def pot_builder(target,source,env):
200     args = [ 'xgettext',
201              '--keyword=_',
202              '--keyword=N_',
203              '--from-code=UTF-8',
204              '-o', target[0].get_path(),
205              "--default-domain=" + env['PACKAGE'],
206              '--copyright-holder="Paul Davis"' ]
207     args += [ src.get_path() for src in source ]
208     
209     return os.spawnvp (os.P_WAIT, 'xgettext', args)
210
211 pot_bld = Builder (action = pot_builder)
212 env.Append(BUILDERS = {'PotBuild' : pot_bld})
213
214 #
215 # utility function, not a builder
216 #
217
218 def i18n (buildenv, sources, installenv):
219     domain = buildenv['PACKAGE']
220     potfile = buildenv['POTFILE']
221     
222     installenv.Alias ('potupdate', buildenv.PotBuild (potfile, sources))
223     
224     p_oze = [ os.path.basename (po) for po in glob.glob ('po/*.po') ]
225     languages = [ po.replace ('.po', '') for po in p_oze ]
226     
227     for po_file in p_oze:
228         buildenv.PoBuild(po_file, ['po/'+po_file, potfile])
229         mo_file = po_file.replace (".po", ".mo")
230         installenv.Alias ('install', buildenv.MoBuild (mo_file, po_file))
231     
232     for lang in languages:
233         modir = (os.path.join (install_prefix, 'share/locale/' + lang + '/LC_MESSAGES/'))
234         moname = domain + '.mo'
235         installenv.Alias('install', installenv.InstallAs (os.path.join (modir, moname), lang + '.mo'))
236
237
238 def fetch_svn_revision (path):
239     cmd = "LANG= "
240     cmd += "svn info "
241     cmd += path
242     cmd += " | awk '/^Revision:/ { print $2}'"
243     return commands.getoutput (cmd)
244
245 def create_stored_revision (target = None, source = None, env = None):
246     if os.path.exists('.svn'):    
247         rev = fetch_svn_revision ('.');
248         try:
249             text  = "#ifndef __ardour_svn_revision_h__\n"
250             text += "#define __ardour_svn_revision_h__\n"
251             text += "static const char* ardour_svn_revision = \"" + rev + "\";\n";
252             text += "#endif\n"
253             print '============> writing svn revision info to svn_revision.h\n'
254             o = file ('svn_revision.h', 'w')
255             o.write (text)
256             o.close ()
257         except IOError:
258             print "Could not open svn_revision.h for writing\n"
259             sys.exit (-1)
260     else:
261         print "You cannot use \"scons revision\" on without using a checked out"
262         print "copy of the Ardour source code repository"
263         sys.exit (-1)
264
265 #
266 # A generic builder for version.cc files
267 #
268 # note: requires that DOMAIN, MAJOR, MINOR, MICRO are set in the construction environment
269 # note: assumes one source files, the header that declares the version variables
270 #
271
272 def version_builder (target, source, env):
273
274     text  = "int " + env['DOMAIN'] + "_major_version = " + str (env['MAJOR']) + ";\n"
275     text += "int " + env['DOMAIN'] + "_minor_version = " + str (env['MINOR']) + ";\n"
276     text += "int " + env['DOMAIN'] + "_micro_version = " + str (env['MICRO']) + ";\n"
277     
278     try:
279         o = file (target[0].get_path(), 'w')
280         o.write (text)
281         o.close ()
282     except IOError:
283         print "Could not open", target[0].get_path(), " for writing\n"
284         sys.exit (-1)
285
286     text  = "#ifndef __" + env['DOMAIN'] + "_version_h__\n"
287     text += "#define __" + env['DOMAIN'] + "_version_h__\n"
288     text += "extern const char* " + env['DOMAIN'] + "_revision;\n"
289     text += "extern int " + env['DOMAIN'] + "_major_version;\n"
290     text += "extern int " + env['DOMAIN'] + "_minor_version;\n"
291     text += "extern int " + env['DOMAIN'] + "_micro_version;\n"
292     text += "#endif /* __" + env['DOMAIN'] + "_version_h__ */\n"
293     
294     try:
295         o = file (target[1].get_path(), 'w')
296         o.write (text)
297         o.close ()
298     except IOError:
299         print "Could not open", target[1].get_path(), " for writing\n"
300         sys.exit (-1)
301         
302     return None
303
304 version_bld = Builder (action = version_builder)
305 env.Append (BUILDERS = {'VersionBuild' : version_bld})
306
307 #
308 # a builder that makes a hard link from the 'source' executable to a name with
309 # a "build ID" based on the most recent CVS activity that might be reasonably
310 # related to version activity. this relies on the idea that the SConscript
311 # file that builds the executable is updated with new version info and committed
312 # to the source code repository whenever things change.
313 #
314
315 def versioned_builder(target,source,env):
316     w, r = os.popen2( "LANG= svn info | awk '/^Revision:/ { print $2}'")
317     
318     last_revision = r.readline().strip()
319     w.close()
320     r.close()
321     if last_revision == "":
322         print "No SVN info found - versioned executable cannot be built"
323         return -1
324     
325     print "The current build ID is " + last_revision
326     
327     tagged_executable = source[0].get_path() + '-' + last_revision
328     
329     if os.path.exists (tagged_executable):
330         print "Replacing existing executable with the same build tag."
331         os.unlink (tagged_executable)
332     
333     return os.link (source[0].get_path(), tagged_executable)
334
335 verbuild = Builder (action = versioned_builder)
336 env.Append (BUILDERS = {'VersionedExecutable' : verbuild})
337
338 #
339 # source tar file builder
340 #
341
342 def distcopy (target, source, env):
343     treedir = str (target[0])
344     
345     try:
346         os.mkdir (treedir)
347     except OSError, (errnum, strerror):
348         if errnum != errno.EEXIST:
349             print 'mkdir ', treedir, ':', strerror
350     
351     cmd = 'tar cf - '
352     #
353     # we don't know what characters might be in the file names
354     # so quote them all before passing them to the shell
355     #
356     all_files = ([ str(s) for s in source ])
357     cmd += " ".join ([ "'%s'" % quoted for quoted in all_files])
358     cmd += ' | (cd ' + treedir + ' && tar xf -)'
359     p = os.popen (cmd)
360     return p.close ()
361
362 def tarballer (target, source, env):
363     cmd = 'tar -jcf ' + str (target[0]) +  ' ' + str(source[0]) + "  --exclude '*~'"
364     print 'running ', cmd, ' ... '
365     p = os.popen (cmd)
366     return p.close ()
367
368 dist_bld = Builder (action = distcopy,
369                     target_factory = SCons.Node.FS.default_fs.Entry,
370                     source_factory = SCons.Node.FS.default_fs.Entry,
371                     multi = 1)
372
373 tarball_bld = Builder (action = tarballer,
374                        target_factory = SCons.Node.FS.default_fs.Entry,
375                        source_factory = SCons.Node.FS.default_fs.Entry)
376
377 env.Append (BUILDERS = {'Distribute' : dist_bld})
378 env.Append (BUILDERS = {'Tarball' : tarball_bld})
379
380 #
381 # Make sure they know what they are doing
382 #
383
384 if env['VST']:
385     if os.path.isfile('.personal_use_only'):
386         print "Enabling VST support. Note that distributing a VST-enabled ardour\nis a violation of several different licences.\nBuild with VST=false if you intend to distribute ardour to others."
387     else:
388         sys.stdout.write ("Are you building Ardour for personal use (rather than distribution to others)? [no]: ")
389         answer = sys.stdin.readline ()
390         answer = answer.rstrip().strip()
391         if answer == "yes" or answer == "y":
392             fh = open('.personal_use_only', 'w')
393             fh.close()
394             print "OK, VST support will be enabled"
395         else:
396             print 'You cannot build Ardour with VST support for distribution to others.\nIt is a violation of several different licenses. Build with VST=false.'
397             sys.exit (-1);
398 else:
399     if os.path.isfile('.personal_use_only'):
400         os.remove('.personal_use_only')
401
402
403 #######################
404 # Dependency Checking #
405 #######################
406
407 deps = \
408 {
409         'glib-2.0'             : '2.10.1',
410         'gthread-2.0'          : '2.10.1',
411         'gtk+-2.0'             : '2.8.1',
412         'libxml-2.0'           : '2.6.0',
413         'samplerate'           : '0.1.0',
414         'raptor'               : '1.4.2',
415         'lrdf'                 : '0.4.0',
416         'jack'                 : '0.101.1',
417         'libgnomecanvas-2.0'   : '2.0'
418 }
419
420 def DependenciesRequiredMessage():
421         print 'You do not have the necessary dependencies required to build ardour'
422         print 'Please consult http://ardour.org/building for more information'
423
424 def CheckPKGConfig(context, version):
425      context.Message( 'Checking for pkg-config version >= %s... ' %version )
426      ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
427      context.Result( ret )
428      return ret
429
430 def CheckPKGVersion(context, name, version):
431      context.Message( 'Checking for %s... ' % name )
432      ret = context.TryAction('pkg-config --atleast-version=%s %s' %(version,name) )[0]
433      context.Result( ret )
434      return ret
435
436 conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig,
437                                        'CheckPKGVersion' : CheckPKGVersion })
438
439 # I think a more recent version is needed on win32
440 min_pkg_config_version = '0.8.0'
441
442 if not conf.CheckPKGConfig(min_pkg_config_version):
443      print 'pkg-config >= %s not found.' % min_pkg_config_version
444      Exit(1)
445
446 for pkg, version in deps.iteritems():
447         if not conf.CheckPKGVersion( pkg, version ):
448                 print '%s >= %s not found.' %(pkg, version)
449                 DependenciesRequiredMessage()
450                 Exit(1)
451
452 env = conf.Finish()
453
454 # ----------------------------------------------------------------------
455 # Construction environment setup
456 # ----------------------------------------------------------------------
457
458 libraries = { }
459
460 libraries['core'] = LibraryInfo (CCFLAGS = '-Ilibs')
461
462 #libraries['sndfile'] = LibraryInfo()
463 #libraries['sndfile'].ParseConfig('pkg-config --cflags --libs sndfile')
464
465 libraries['lrdf'] = LibraryInfo()
466 libraries['lrdf'].ParseConfig('pkg-config --cflags --libs lrdf')
467
468 libraries['raptor'] = LibraryInfo()
469 libraries['raptor'].ParseConfig('pkg-config --cflags --libs raptor')
470
471 libraries['samplerate'] = LibraryInfo()
472 libraries['samplerate'].ParseConfig('pkg-config --cflags --libs samplerate')
473
474 if env['FFT_ANALYSIS']:
475         libraries['fftw3f'] = LibraryInfo()
476         libraries['fftw3f'].ParseConfig('pkg-config --cflags --libs fftw3f')
477         #
478         # Check for fftw3 header as well as the library
479         conf = Configure (libraries['fftw3f'])
480         if conf.CheckHeader ('fftw3.h') == False:
481                 print "FFT Analysis cannot be compiled without the FFTW3 headers, which don't seem to be installed"
482                 sys.exit (1)
483         libraries['fftw3f'] = conf.Finish();
484
485 libraries['jack'] = LibraryInfo()
486 libraries['jack'].ParseConfig('pkg-config --cflags --libs jack')
487
488 libraries['xml'] = LibraryInfo()
489 libraries['xml'].ParseConfig('pkg-config --cflags --libs libxml-2.0')
490
491 libraries['xslt'] = LibraryInfo()
492 libraries['xslt'].ParseConfig('pkg-config --cflags --libs libxslt')
493
494 libraries['glib2'] = LibraryInfo()
495 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs glib-2.0')
496 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gobject-2.0')
497 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gmodule-2.0')
498 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gthread-2.0')
499
500 libraries['gtk2'] = LibraryInfo()
501 libraries['gtk2'].ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
502
503 libraries['pango'] = LibraryInfo()
504 libraries['pango'].ParseConfig ('pkg-config --cflags --libs pango')
505
506 libraries['libgnomecanvas2'] = LibraryInfo()
507 libraries['libgnomecanvas2'].ParseConfig ('pkg-config --cflags --libs libgnomecanvas-2.0')
508
509 #libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
510
511 # The Ardour Control Protocol Library
512
513 libraries['ardour_cp'] = LibraryInfo (LIBS='ardour_cp', LIBPATH='#libs/surfaces/control_protocol',
514                                       CPPPATH='#libs/surfaces/control_protocol')
515
516 # The Ardour backend/engine
517
518 libraries['ardour'] = LibraryInfo (LIBS='ardour', LIBPATH='#libs/ardour', CPPPATH='#libs/ardour')
519 libraries['midi++2'] = LibraryInfo (LIBS='midi++', LIBPATH='#libs/midi++2', CPPPATH='#libs/midi++2')
520 libraries['pbd']    = LibraryInfo (LIBS='pbd', LIBPATH='#libs/pbd', CPPPATH='#libs/pbd')
521 libraries['gtkmm2ext'] = LibraryInfo (LIBS='gtkmm2ext', LIBPATH='#libs/gtkmm2ext', CPPPATH='#libs/gtkmm2ext')
522
523
524 # SCons should really do this for us
525
526 conf = Configure (env)
527
528 have_cxx = conf.TryAction (Action (str(env['CXX']) + ' --version'))
529 if have_cxx[0] != 1:
530     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
531     sys.exit (1)
532 else:
533     print "Congratulations, you have a functioning C++ compiler."
534
535 env = conf.Finish()
536
537
538 #
539 # Compiler flags and other system-dependent stuff
540 #
541
542 opt_flags = []
543 if env['GPROFILE'] == 1:
544     debug_flags = [ '-g', '-pg' ]
545 else:
546     debug_flags = [ '-g' ]
547
548 # guess at the platform, used to define compiler flags
549
550 config_guess = os.popen("tools/config.guess").read()[:-1]
551
552 config_cpu = 0
553 config_arch = 1
554 config_kernel = 2
555 config_os = 3
556 config = config_guess.split ("-")
557
558 print "system triple: " + config_guess
559
560 # Autodetect
561 if env['DIST_TARGET'] == 'auto':
562     if config[config_arch] == 'apple':
563         # The [.] matches to the dot after the major version, "." would match any character
564         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
565             env['DIST_TARGET'] = 'panther'
566         else:
567             env['DIST_TARGET'] = 'tiger'
568     else:
569         if re.search ("x86_64", config[config_cpu]) != None:
570             env['DIST_TARGET'] = 'x86_64'
571         elif re.search("i[0-5]86", config[config_cpu]) != None:
572             env['DIST_TARGET'] = 'i386'
573         elif re.search("powerpc", config[config_cpu]) != None:
574             env['DIST_TARGET'] = 'powerpc'
575         else:
576             env['DIST_TARGET'] = 'i686'
577     print "\n*******************************"
578     print "detected DIST_TARGET = " + env['DIST_TARGET']
579     print "*******************************\n"
580
581
582 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
583     #
584     # Apple/PowerPC optimization options
585     #
586     # -mcpu=7450 does not reliably work with gcc 3.*
587     #
588     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
589         if config[config_arch] == 'apple':
590             ## opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
591             # to support g3s but still have some optimization for above
592             opt_flags.extend ([ "-mcpu=G3", "-mtune=7450"])
593         else:
594             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"])
595     else:
596         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
597     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
598     opt_flags.extend (["-Os"])
599
600 elif ((re.search ("i[0-9]86", config[config_cpu]) != None) or (re.search ("x86_64", config[config_cpu]) != None)) and env['DIST_TARGET'] != 'none':
601     
602     build_host_supports_sse = 0
603     
604     debug_flags.append ("-DARCH_X86")
605     opt_flags.append ("-DARCH_X86")
606     
607     if config[config_kernel] == 'linux' :
608         
609         if env['DIST_TARGET'] != 'i386':
610             
611             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
612             x86_flags = flag_line.split (": ")[1:][0].split ()
613             
614             if "mmx" in x86_flags:
615                 opt_flags.append ("-mmmx")
616             if "sse" in x86_flags:
617                 build_host_supports_sse = 1
618             if "3dnow" in x86_flags:
619                 opt_flags.append ("-m3dnow")
620             
621             if config[config_cpu] == "i586":
622                 opt_flags.append ("-march=i586")
623             elif config[config_cpu] == "i686":
624                 opt_flags.append ("-march=i686")
625     
626     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
627         opt_flags.extend (["-msse", "-mfpmath=sse", "-DUSE_XMMINTRIN"])
628         debug_flags.extend (["-msse", "-mfpmath=sse", "-DUSE_XMMINTRIN"])
629 # end of processor-specific section
630
631 # optimization section
632 if env['FPU_OPTIMIZATION']:
633     if env['DIST_TARGET'] == 'tiger':
634         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
635         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
636         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
637     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
638         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
639         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
640         if env['DIST_TARGET'] == 'x86_64':
641             opt_flags.append ("-DUSE_X86_64_ASM")
642             debug_flags.append ("-DUSE_X86_64_ASM")
643         if build_host_supports_sse != 1:
644             print "\nWarning: you are building Ardour with SSE support even though your system does not support these instructions. (This may not be an error, especially if you are a package maintainer)"
645 # end optimization section
646
647 # handle x86/x86_64 libdir properly
648
649 if env['DIST_TARGET'] == 'x86_64':
650     env['LIBDIR']='lib64'
651 else:
652     env['LIBDIR']='lib'
653
654 #
655 # save off guessed arch element in an env
656 #
657 env.Append(CONFIG_ARCH=config[config_arch])
658
659
660 #
661 # ARCH="..." overrides all
662 #
663
664 if env['ARCH'] != '':
665     opt_flags = env['ARCH'].split()
666
667 #
668 # prepend boiler plate optimization flags
669 #
670
671 opt_flags[:0] = [
672     "-O3",
673     "-fomit-frame-pointer",
674     "-ffast-math",
675     "-fstrength-reduce",
676     "-pipe"
677     ]
678
679 if env['DEBUG'] == 1:
680     env.Append(CCFLAGS=" ".join (debug_flags))
681     env.Append(LINKFLAGS=" ".join (debug_flags))
682 else:
683     env.Append(CCFLAGS=" ".join (opt_flags))
684     env.Append(LINKFLAGS=" ".join (opt_flags))
685
686 if env['UNIVERSAL'] == 1:
687     env.Append(CCFLAGS="-arch i386 -arch ppc")
688     env.Append(LINKFLAGS="-arch i386 -arch ppc")
689
690 #
691 # warnings flags
692 #
693
694 env.Append(CCFLAGS="-Wall")
695 env.Append(CXXFLAGS="-Woverloaded-virtual")
696
697 if env['EXTRA_WARN']:
698     env.Append(CCFLAGS="-Wextra -pedantic -ansi")
699     env.Append(CXXFLAGS="-ansi")
700 #    env.Append(CFLAGS="-iso")
701
702 if env['LIBLO']:
703     env.Append(CCFLAGS="-DHAVE_LIBLO")
704
705
706 #
707 # fix scons nitpickiness on APPLE
708 #
709
710
711 def prep_libcheck(topenv, libinfo):
712     if topenv['DIST_TARGET'] == 'panther' or topenv['DIST_TARGET'] == 'tiger':
713         libinfo.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib")
714
715 prep_libcheck(env, env)
716
717 #
718 # Check for libusb
719
720 libraries['usb'] = LibraryInfo ()
721 prep_libcheck(env, libraries['usb'])
722
723 conf = Configure (libraries['usb'])
724 if conf.CheckLib ('usb', 'usb_interrupt_write'):
725     have_libusb = True
726 else:
727     have_libusb = False
728
729 # check for linux/input.h while we're at it for powermate
730 if conf.CheckHeader('linux/input.h'):
731     have_linux_input = True
732 else:
733     have_linux_input = False
734
735 libraries['usb'] = conf.Finish ()
736
737 #
738 # Check for FLAC
739
740 libraries['flac'] = LibraryInfo ()
741 prep_libcheck(env, libraries['flac'])
742 libraries['flac'].Append(CCFLAGS="-I/usr/local/include", LINKFLAGS="-L/usr/local/lib")
743
744 #
745 # june 1st 2007: look for a function that is in FLAC 1.1.2 and not in later versions
746 #                since the version of libsndfile we have internally does not support
747 #                the new API that libFLAC has adopted
748 #
749
750 conf = Configure (libraries['flac'])
751 if conf.CheckLib ('FLAC', 'FLAC__seekable_stream_decoder_init', language='CXX'):
752     conf.env.Append(CCFLAGS='-DHAVE_FLAC')
753     use_flac = True
754 else:
755     use_flac = False
756     
757 libraries['flac'] = conf.Finish ()
758
759 # or if that fails...
760 #libraries['flac']    = LibraryInfo (LIBS='FLAC')
761
762 # boost (we don't link against boost, just use some header files)
763
764 libraries['boost'] = LibraryInfo ()
765 prep_libcheck(env, libraries['boost'])
766 libraries['boost'].Append(CCFLAGS="-I/usr/local/include", LINKFLAGS="-L/usr/local/lib")
767 conf = Configure (libraries['boost'])
768 if conf.CheckHeader ('boost/shared_ptr.hpp', language='CXX') == False:
769         print "Boost header files do not appear to be installed."
770         sys.exit (1)
771     
772 libraries['boost'] = conf.Finish ()
773
774 #
775 # Check for liblo
776
777 if env['LIBLO']:
778     libraries['lo'] = LibraryInfo ()
779     prep_libcheck(env, libraries['lo'])
780
781     conf = Configure (libraries['lo'])
782     if conf.CheckLib ('lo', 'lo_server_new') == False:
783         print "liblo does not appear to be installed."
784         sys.exit (1)
785     
786     libraries['lo'] = conf.Finish ()
787
788 #
789 # Check for dmalloc
790
791 libraries['dmalloc'] = LibraryInfo ()
792 prep_libcheck(env, libraries['dmalloc'])
793
794 #
795 # look for the threaded version
796 #
797
798 conf = Configure (libraries['dmalloc'])
799 if conf.CheckLib ('dmallocth', 'dmalloc_shutdown'):
800     have_libdmalloc = True
801 else:
802     have_libdmalloc = False
803
804 libraries['dmalloc'] = conf.Finish ()
805
806 #
807 # Audio/MIDI library (needed for MIDI, since audio is all handled via JACK)
808 #
809
810 conf = Configure(env)
811
812 if conf.CheckCHeader('alsa/asoundlib.h'):
813     libraries['sysmidi'] = LibraryInfo (LIBS='asound')
814     env['SYSMIDI'] = 'ALSA Sequencer'
815     subst_dict['%MIDITAG%'] = "seq"
816     subst_dict['%MIDITYPE%'] = "alsa/sequencer"
817 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
818     # this line is needed because scons can't handle -framework in ParseConfig() yet.
819     libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
820     env['SYSMIDI'] = 'CoreMIDI'
821     subst_dict['%MIDITAG%'] = "ardour"
822     subst_dict['%MIDITYPE%'] = "coremidi"
823 else:
824     print "It appears you don't have the required MIDI libraries installed. For Linux this means you are missing the development package for ALSA libraries."
825     sys.exit (1)
826
827 env = conf.Finish()
828
829 if env['SYSLIBS']:
830
831     syslibdeps = \
832     {
833         'sigc++-2.0'           : '2.0',
834         'gtkmm-2.4'            : '2.8',
835         'libgnomecanvasmm-2.6' : '2.12.0'
836     }
837
838     conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig,
839                     'CheckPKGVersion' : CheckPKGVersion })
840
841     for pkg, version in syslibdeps.iteritems():
842         if not conf.CheckPKGVersion( pkg, version ):
843             print '%s >= %s not found.' %(pkg, version)
844             DependenciesRequiredMessage()
845             Exit(1)
846         
847     env = conf.Finish()
848     
849     libraries['sigc2'] = LibraryInfo()
850     libraries['sigc2'].ParseConfig('pkg-config --cflags --libs sigc++-2.0')
851     libraries['glibmm2'] = LibraryInfo()
852     libraries['glibmm2'].ParseConfig('pkg-config --cflags --libs glibmm-2.4')
853     libraries['cairomm'] = LibraryInfo()
854     libraries['cairomm'].ParseConfig('pkg-config --cflags --libs cairomm-1.0')
855     libraries['gdkmm2'] = LibraryInfo()
856     libraries['gdkmm2'].ParseConfig ('pkg-config --cflags --libs gdkmm-2.4')
857     libraries['gtkmm2'] = LibraryInfo()
858     libraries['gtkmm2'].ParseConfig ('pkg-config --cflags --libs gtkmm-2.4')
859     libraries['atkmm'] = LibraryInfo()
860     libraries['atkmm'].ParseConfig ('pkg-config --cflags --libs atkmm-1.6')
861     libraries['pangomm'] = LibraryInfo()
862     libraries['pangomm'].ParseConfig ('pkg-config --cflags --libs pangomm-1.4')
863     libraries['libgnomecanvasmm'] = LibraryInfo()
864     libraries['libgnomecanvasmm'].ParseConfig ('pkg-config --cflags --libs libgnomecanvasmm-2.6')
865
866 #
867 # cannot use system one for the time being
868 #
869     
870     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
871                                     LIBPATH='#libs/libsndfile',
872                                     CPPPATH=['#libs/libsndfile/src'])
873
874 #    libraries['libglademm'] = LibraryInfo()
875 #    libraries['libglademm'].ParseConfig ('pkg-config --cflags --libs libglademm-2.4')
876
877 #    libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
878     libraries['soundtouch'] = LibraryInfo()
879     libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs soundtouch-1.0')
880     # Comment the previous line and uncomment this for Debian:
881     #libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs libSoundTouch')
882
883     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
884                                             LIBPATH='#libs/appleutility',
885                                             CPPPATH='#libs/appleutility')
886     
887     coredirs = [
888         'templates'
889     ]
890     
891     subdirs = [
892         'libs/libsndfile',
893         'libs/pbd',
894         'libs/midi++2',
895         'libs/ardour',
896     # these are unconditionally included but have
897     # tests internally to avoid compilation etc
898     # if VST is not set
899         'libs/fst',
900         'vst',
901     # this is unconditionally included but has
902     # tests internally to avoid compilation etc
903     # if COREAUDIO is not set
904         'libs/appleutility'
905         ]
906     
907     gtk_subdirs = [
908 #        'libs/flowcanvas',
909         'libs/gtkmm2ext',
910         'gtk2_ardour',
911         'libs/clearlooks'
912         ]
913
914 else:
915     libraries['sigc2'] = LibraryInfo(LIBS='sigc++2',
916                                     LIBPATH='#libs/sigc++2',
917                                     CPPPATH='#libs/sigc++2')
918     libraries['glibmm2'] = LibraryInfo(LIBS='glibmm2',
919                                     LIBPATH='#libs/glibmm2',
920                                     CPPPATH='#libs/glibmm2')
921     libraries['pangomm'] = LibraryInfo(LIBS='pangomm',
922                                     LIBPATH='#libs/gtkmm2/pango',
923                                     CPPPATH='#libs/gtkmm2/pango')
924     libraries['atkmm'] = LibraryInfo(LIBS='atkmm',
925                                      LIBPATH='#libs/gtkmm2/atk',
926                                      CPPPATH='#libs/gtkmm2/atk')
927     libraries['gdkmm2'] = LibraryInfo(LIBS='gdkmm2',
928                                       LIBPATH='#libs/gtkmm2/gdk',
929                                       CPPPATH='#libs/gtkmm2/gdk')
930     libraries['gtkmm2'] = LibraryInfo(LIBS='gtkmm2',
931                                      LIBPATH="#libs/gtkmm2/gtk",
932                                      CPPPATH='#libs/gtkmm2/gtk/')
933     libraries['libgnomecanvasmm'] = LibraryInfo(LIBS='libgnomecanvasmm',
934                                                 LIBPATH='#libs/libgnomecanvasmm',
935                                                 CPPPATH='#libs/libgnomecanvasmm')
936     
937     libraries['soundtouch'] = LibraryInfo(LIBS='soundtouch',
938                                           LIBPATH='#libs/soundtouch',
939                                           CPPPATH=['#libs', '#libs/soundtouch'])
940     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
941                                     LIBPATH='#libs/libsndfile',
942                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
943 #    libraries['libglademm'] = LibraryInfo(LIBS='libglademm',
944 #                                          LIBPATH='#libs/libglademm',
945 #                                          CPPPATH='#libs/libglademm')
946     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
947                                             LIBPATH='#libs/appleutility',
948                                             CPPPATH='#libs/appleutility')
949
950     coredirs = [
951         'libs/soundtouch',
952         'templates'
953     ]
954     
955     subdirs = [
956         'libs/sigc++2',
957         'libs/libsndfile',
958         'libs/pbd',
959         'libs/midi++2',
960         'libs/ardour',
961     # these are unconditionally included but have
962     # tests internally to avoid compilation etc
963     # if VST is not set
964         'libs/fst',
965         'vst',
966     # this is unconditionally included but has
967     # tests internally to avoid compilation etc
968     # if COREAUDIO is not set
969         'libs/appleutility'
970         ]
971     
972     gtk_subdirs = [
973         'libs/glibmm2',
974         'libs/gtkmm2/pango',
975         'libs/gtkmm2/atk',
976         'libs/gtkmm2/gdk',
977         'libs/gtkmm2/gtk',
978         'libs/libgnomecanvasmm',
979 #       'libs/flowcanvas',
980         'libs/gtkmm2ext',
981         'gtk2_ardour',
982         'libs/clearlooks'
983         ]
984
985 #
986 # * always build the LGPL control protocol lib, since we link against it from libardour
987 # * ditto for generic MIDI
988 # * tranzport checks whether it should build internally, but we need here so that
989 #   its included in the tarball
990 #
991
992 surface_subdirs = [ 'libs/surfaces/control_protocol',
993                     'libs/surfaces/generic_midi',
994                     'libs/surfaces/tranzport',
995                     'libs/surfaces/mackie',
996                     'libs/surfaces/powermate'
997                     ]
998
999 if env['SURFACES']:
1000     if have_libusb:
1001         env['TRANZPORT'] = 1
1002     else:
1003         env['TRANZPORT'] = 0
1004         print 'Disabled building Tranzport code because libusb could not be found'
1005
1006     if have_linux_input:
1007         env['POWERMATE'] = 1
1008     else:
1009         env['POWERMATE'] = 0
1010         print 'Disabled building Powermate code because linux/input.h could not be found'
1011
1012     if os.access ('libs/surfaces/sony9pin', os.F_OK):
1013         surface_subdirs += [ 'libs/surfaces/sony9pin' ]
1014 else:
1015     env['POWERMATE'] = 0
1016     env['TRANZPORT'] = 0
1017     
1018 opts.Save('scache.conf', env)
1019 Help(opts.GenerateHelpText(env))
1020
1021 if os.environ.has_key('PATH'):
1022     env.Append(PATH = os.environ['PATH'])
1023
1024 if os.environ.has_key('PKG_CONFIG_PATH'):
1025     env.Append(PKG_CONFIG_PATH = os.environ['PKG_CONFIG_PATH'])
1026
1027 if os.environ.has_key('CC'):
1028     env['CC'] = os.environ['CC']
1029
1030 if os.environ.has_key('CXX'):
1031     env['CXX'] = os.environ['CXX']
1032
1033 if os.environ.has_key('DISTCC_HOSTS'):
1034     env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
1035     env['ENV']['HOME'] = os.environ['HOME']
1036
1037 final_prefix = '$PREFIX'
1038
1039 if env['DESTDIR'] :
1040     install_prefix = '$DESTDIR/$PREFIX'
1041 else:
1042     install_prefix = env['PREFIX']
1043
1044 subst_dict['%INSTALL_PREFIX%'] = install_prefix;
1045 subst_dict['%FINAL_PREFIX%'] = final_prefix;
1046 subst_dict['%PREFIX%'] = final_prefix;
1047
1048 if env['PREFIX'] == '/usr':
1049     final_config_prefix = '/etc'
1050 else:
1051     final_config_prefix = env['PREFIX'] + '/etc'
1052
1053 config_prefix = '$DESTDIR' + final_config_prefix
1054
1055 #
1056 # everybody needs this
1057 #
1058
1059 env.Merge ([ libraries['core'] ])
1060
1061
1062 #
1063 # i18n support
1064 #
1065
1066 conf = Configure (env)
1067 if env['NLS']:
1068     nls_error = 'This system is not configured for internationalized applications.  An english-only version will be built:'
1069     print 'Checking for internationalization support ...'
1070     have_gettext = conf.TryAction(Action('xgettext --version'))
1071     if have_gettext[0] != 1:
1072         nls_error += ' No xgettext command.'
1073         env['NLS'] = 0
1074     else:
1075         print "Found xgettext"
1076     
1077     have_msgmerge = conf.TryAction(Action('msgmerge --version'))
1078     if have_msgmerge[0] != 1:
1079         nls_error += ' No msgmerge command.'
1080         env['NLS'] = 0
1081     else:
1082         print "Found msgmerge"
1083     
1084     if not conf.CheckCHeader('libintl.h'):
1085         nls_error += ' No libintl.h.'
1086         env['NLS'] = 0
1087         
1088     if env['NLS'] == 0:
1089         print nls_error
1090     else:
1091         print "International version will be built."
1092 env = conf.Finish()
1093
1094 if env['NLS'] == 1:
1095     env.Append(CCFLAGS="-DENABLE_NLS")
1096
1097 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n ardour_version subst_dict use_flac')
1098
1099 #
1100 # the configuration file may be system dependent
1101 #
1102
1103 conf = env.Configure ()
1104
1105 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
1106     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
1107     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
1108 else:
1109     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
1110     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
1111
1112 # posix_memalign available
1113 if not conf.CheckFunc('posix_memalign'):
1114     print 'Did not find posix_memalign(), using malloc'
1115     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
1116
1117
1118 env = conf.Finish()
1119
1120 # generate the per-user and system rc files from the same source
1121
1122 sysrcbuild = env.SubstInFile ('ardour_system.rc','ardour.rc.in', SUBST_DICT = subst_dict)
1123
1124 # add to the substitution dictionary
1125
1126 subst_dict['%VERSION%'] = ardour_version[0:3]
1127 subst_dict['%EXTRA_VERSION%'] = ardour_version[3:]
1128 subst_dict['%REVISION_STRING%'] = ''
1129 if os.path.exists('.svn'):
1130     subst_dict['%REVISION_STRING%'] = '.' + fetch_svn_revision ('.') + 'svn'
1131
1132 # specbuild = env.SubstInFile ('ardour.spec','ardour.spec.in', SUBST_DICT = subst_dict)
1133
1134 the_revision = env.Command ('frobnicatory_decoy', [], create_stored_revision)
1135
1136 env.Alias('revision', the_revision)
1137 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
1138
1139 Default (sysrcbuild)
1140
1141 # source tarball
1142
1143 Precious (env['DISTTREE'])
1144
1145 env.Distribute (env['DISTTREE'],
1146                [ 'SConstruct', 'svn_revision.h',
1147                   'COPYING', 'PACKAGER_README', 'README',
1148                   'ardour.rc.in',
1149                   'tools/config.guess',
1150                   'icons/icon/ardour_icon_mac_mask.png',
1151                   'icons/icon/ardour_icon_mac.png',
1152                   'icons/icon/ardour_icon_tango_16px_blue.png',
1153                   'icons/icon/ardour_icon_tango_16px_red.png',
1154                   'icons/icon/ardour_icon_tango_22px_blue.png',
1155                   'icons/icon/ardour_icon_tango_22px_red.png',
1156                   'icons/icon/ardour_icon_tango_32px_blue.png',
1157                   'icons/icon/ardour_icon_tango_32px_red.png',
1158                   'icons/icon/ardour_icon_tango_48px_blue.png',
1159                   'icons/icon/ardour_icon_tango_48px_red.png'
1160                   ] +
1161                 glob.glob ('DOCUMENTATION/AUTHORS*') +
1162                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
1163                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
1164                 glob.glob ('DOCUMENTATION/BUILD*') +
1165                 glob.glob ('DOCUMENTATION/FAQ*') +
1166                 glob.glob ('DOCUMENTATION/README*')
1167                 )
1168
1169 srcdist = env.Tarball(env['TARBALL'], [ env['DISTTREE'], the_revision ])
1170 env.Alias ('srctar', srcdist)
1171
1172 #
1173 # don't leave the distree around
1174 #
1175
1176 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
1177 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
1178
1179 #
1180 # the subdirs
1181 #
1182
1183 for subdir in coredirs:
1184     SConscript (subdir + '/SConscript')
1185
1186 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
1187     for subdir in sublistdir:
1188         SConscript (subdir + '/SConscript')
1189
1190 # cleanup
1191 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
1192