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