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