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