Better error message for missing vst files
[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 create_stored_revision (target = None, source = None, env = None):
242     if os.path.exists('.svn'):    
243         rev = fetch_svn_revision ('.');
244         try:
245             text  = "#ifndef __ardour_svn_revision_h__\n"
246             text += "#define __ardour_svn_revision_h__\n"
247             text += "static const char* ardour_svn_revision = \"" + rev + "\";\n";
248             text += "#endif\n"
249             print '============> writing svn revision info to svn_revision.h\n'
250             o = file ('svn_revision.h', 'w')
251             o.write (text)
252             o.close ()
253         except IOError:
254             print "Could not open svn_revision.h for writing\n"
255             sys.exit (-1)
256     else:
257         print "You cannot use \"scons revision\" on without using a checked out"
258         print "copy of the Ardour source code repository"
259         sys.exit (-1)
260
261 #
262 # A generic builder for version.cc files
263 #
264 # note: requires that DOMAIN, MAJOR, MINOR, MICRO are set in the construction environment
265 # note: assumes one source files, the header that declares the version variables
266 #
267
268 def version_builder (target, source, env):
269
270     text  = "int " + env['DOMAIN'] + "_major_version = " + str (env['MAJOR']) + ";\n"
271     text += "int " + env['DOMAIN'] + "_minor_version = " + str (env['MINOR']) + ";\n"
272     text += "int " + env['DOMAIN'] + "_micro_version = " + str (env['MICRO']) + ";\n"
273     
274     try:
275         o = file (target[0].get_path(), 'w')
276         o.write (text)
277         o.close ()
278     except IOError:
279         print "Could not open", target[0].get_path(), " for writing\n"
280         sys.exit (-1)
281
282     text  = "#ifndef __" + env['DOMAIN'] + "_version_h__\n"
283     text += "#define __" + env['DOMAIN'] + "_version_h__\n"
284     text += "extern const char* " + env['DOMAIN'] + "_revision;\n"
285     text += "extern int " + env['DOMAIN'] + "_major_version;\n"
286     text += "extern int " + env['DOMAIN'] + "_minor_version;\n"
287     text += "extern int " + env['DOMAIN'] + "_micro_version;\n"
288     text += "#endif /* __" + env['DOMAIN'] + "_version_h__ */\n"
289     
290     try:
291         o = file (target[1].get_path(), 'w')
292         o.write (text)
293         o.close ()
294     except IOError:
295         print "Could not open", target[1].get_path(), " for writing\n"
296         sys.exit (-1)
297         
298     return None
299
300 version_bld = Builder (action = version_builder)
301 env.Append (BUILDERS = {'VersionBuild' : version_bld})
302
303 #
304 # a builder that makes a hard link from the 'source' executable to a name with
305 # a "build ID" based on the most recent CVS activity that might be reasonably
306 # related to version activity. this relies on the idea that the SConscript
307 # file that builds the executable is updated with new version info and committed
308 # to the source code repository whenever things change.
309 #
310
311 def versioned_builder(target,source,env):
312     w, r = os.popen2( "svn info | awk '/^Revision:/ { print $2}'")
313     
314     last_revision = r.readline().strip()
315     w.close()
316     r.close()
317     if last_revision == "":
318         print "No SVN info found - versioned executable cannot be built"
319         return -1
320     
321     print "The current build ID is " + last_revision
322     
323     tagged_executable = source[0].get_path() + '-' + last_revision
324     
325     if os.path.exists (tagged_executable):
326         print "Replacing existing executable with the same build tag."
327         os.unlink (tagged_executable)
328     
329     return os.link (source[0].get_path(), tagged_executable)
330
331 verbuild = Builder (action = versioned_builder)
332 env.Append (BUILDERS = {'VersionedExecutable' : verbuild})
333
334 #
335 # source tar file builder
336 #
337
338 def distcopy (target, source, env):
339     treedir = str (target[0])
340     
341     try:
342         os.mkdir (treedir)
343     except OSError, (errnum, strerror):
344         if errnum != errno.EEXIST:
345             print 'mkdir ', treedir, ':', strerror
346     
347     cmd = 'tar cf - '
348     #
349     # we don't know what characters might be in the file names
350     # so quote them all before passing them to the shell
351     #
352     all_files = ([ str(s) for s in source ])
353     cmd += " ".join ([ "'%s'" % quoted for quoted in all_files])
354     cmd += ' | (cd ' + treedir + ' && tar xf -)'
355     p = os.popen (cmd)
356     return p.close ()
357
358 def tarballer (target, source, env):
359     cmd = 'tar -jcf ' + str (target[0]) +  ' ' + str(source[0]) + "  --exclude '*~'"
360     print 'running ', cmd, ' ... '
361     p = os.popen (cmd)
362     return p.close ()
363
364 dist_bld = Builder (action = distcopy,
365                     target_factory = SCons.Node.FS.default_fs.Entry,
366                     source_factory = SCons.Node.FS.default_fs.Entry,
367                     multi = 1)
368
369 tarball_bld = Builder (action = tarballer,
370                        target_factory = SCons.Node.FS.default_fs.Entry,
371                        source_factory = SCons.Node.FS.default_fs.Entry)
372
373 env.Append (BUILDERS = {'Distribute' : dist_bld})
374 env.Append (BUILDERS = {'Tarball' : tarball_bld})
375
376 #
377 # Make sure they know what they are doing
378 #
379
380 if env['VST']:
381     sys.stdout.write ("Are you building Ardour for personal use (rather than distribution to others)? [no]: ")
382     answer = sys.stdin.readline ()
383     answer = answer.rstrip().strip()
384     if answer != "yes" and answer != "y":
385         print 'You cannot build Ardour with VST support for distribution to others.\nIt is a violation of several different licenses. Build with VST=false.'
386         sys.exit (-1);
387     else:
388         print "OK, VST support will be enabled"
389
390
391 # ----------------------------------------------------------------------
392 # Construction environment setup
393 # ----------------------------------------------------------------------
394
395 libraries = { }
396
397 libraries['core'] = LibraryInfo (CCFLAGS = '-Ilibs')
398
399 #libraries['sndfile'] = LibraryInfo()
400 #libraries['sndfile'].ParseConfig('pkg-config --cflags --libs sndfile')
401
402 libraries['lrdf'] = LibraryInfo()
403 libraries['lrdf'].ParseConfig('pkg-config --cflags --libs lrdf')
404
405 libraries['raptor'] = LibraryInfo()
406 libraries['raptor'].ParseConfig('pkg-config --cflags --libs raptor')
407
408 libraries['samplerate'] = LibraryInfo()
409 libraries['samplerate'].ParseConfig('pkg-config --cflags --libs samplerate')
410
411 if env['FFT_ANALYSIS']:
412         libraries['fftw3f'] = LibraryInfo()
413         libraries['fftw3f'].ParseConfig('pkg-config --cflags --libs fftw3f')
414
415 libraries['jack'] = LibraryInfo()
416 libraries['jack'].ParseConfig('pkg-config --cflags --libs jack')
417
418 libraries['xml'] = LibraryInfo()
419 libraries['xml'].ParseConfig('pkg-config --cflags --libs libxml-2.0')
420
421 libraries['xslt'] = LibraryInfo()
422 libraries['xslt'].ParseConfig('pkg-config --cflags --libs libxslt')
423
424 libraries['glib2'] = LibraryInfo()
425 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs glib-2.0')
426 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gobject-2.0')
427 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gmodule-2.0')
428 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gthread-2.0')
429
430 libraries['gtk2'] = LibraryInfo()
431 libraries['gtk2'].ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
432
433 libraries['pango'] = LibraryInfo()
434 libraries['pango'].ParseConfig ('pkg-config --cflags --libs pango')
435
436 libraries['libgnomecanvas2'] = LibraryInfo()
437 libraries['libgnomecanvas2'].ParseConfig ('pkg-config --cflags --libs libgnomecanvas-2.0')
438
439 #libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
440
441 # The Ardour Control Protocol Library
442
443 libraries['ardour_cp'] = LibraryInfo (LIBS='ardour_cp', LIBPATH='#libs/surfaces/control_protocol',
444                                       CPPPATH='#libs/surfaces/control_protocol')
445
446 # The Ardour backend/engine
447
448 libraries['ardour'] = LibraryInfo (LIBS='ardour', LIBPATH='#libs/ardour', CPPPATH='#libs/ardour')
449 libraries['midi++2'] = LibraryInfo (LIBS='midi++', LIBPATH='#libs/midi++2', CPPPATH='#libs/midi++2')
450 libraries['pbd']    = LibraryInfo (LIBS='pbd', LIBPATH='#libs/pbd', CPPPATH='#libs/pbd')
451 libraries['gtkmm2ext'] = LibraryInfo (LIBS='gtkmm2ext', LIBPATH='#libs/gtkmm2ext', CPPPATH='#libs/gtkmm2ext')
452
453 #
454 # Check for libusb
455
456 libraries['usb'] = LibraryInfo ()
457
458 conf = Configure (libraries['usb'])
459 if conf.CheckLib ('usb', 'usb_interrupt_write'):
460     have_libusb = True
461 else:
462     have_libusb = False
463
464 libraries['usb'] = conf.Finish ()
465
466 #
467 # Check for FLAC
468
469 libraries['flac'] = LibraryInfo ()
470
471 conf = Configure (libraries['flac'])
472 conf.CheckLib ('FLAC', 'FLAC__stream_decoder_new', language='CXX')
473 libraries['flac'] = conf.Finish ()
474
475 # or if that fails...
476 #libraries['flac']    = LibraryInfo (LIBS='FLAC')
477
478 # boost (we don't link against boost, just use some header files)
479
480 libraries['boost'] = LibraryInfo ()
481 conf = Configure (libraries['boost'])
482 if conf.CheckHeader ('boost/shared_ptr.hpp', language='CXX') == False:
483         print "Boost header files do not appear to be installed."
484         sys.exit (1)
485     
486 libraries['boost'] = conf.Finish ()
487
488 #
489 # Check for liblo
490
491 if env['LIBLO']:
492     libraries['lo'] = LibraryInfo ()
493     
494     conf = Configure (libraries['lo'])
495     if conf.CheckLib ('lo', 'lo_server_new') == False:
496         print "liblo does not appear to be installed."
497         sys.exit (1)
498     
499     libraries['lo'] = conf.Finish ()
500
501 #
502 # Check for dmalloc
503
504 libraries['dmalloc'] = LibraryInfo ()
505
506 #
507 # look for the threaded version
508 #
509
510 conf = Configure (libraries['dmalloc'])
511 if conf.CheckLib ('dmallocth', 'dmalloc_shutdown'):
512     have_libdmalloc = True
513 else:
514     have_libdmalloc = False
515
516 libraries['dmalloc'] = conf.Finish ()
517
518 #
519 # Audio/MIDI library (needed for MIDI, since audio is all handled via JACK)
520 #
521
522 conf = Configure(env)
523
524 if conf.CheckCHeader('alsa/asoundlib.h'):
525     libraries['sysmidi'] = LibraryInfo (LIBS='asound')
526     env['SYSMIDI'] = 'ALSA Sequencer'
527     subst_dict['%MIDITAG%'] = "seq"
528     subst_dict['%MIDITYPE%'] = "alsa/sequencer"
529 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
530     # this line is needed because scons can't handle -framework in ParseConfig() yet.
531     libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
532     env['SYSMIDI'] = 'CoreMIDI'
533     subst_dict['%MIDITAG%'] = "ardour"
534     subst_dict['%MIDITYPE%'] = "coremidi"
535 else:
536     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."
537     sys.exit (1)
538
539 env = conf.Finish()
540
541 if env['SYSLIBS']:
542     
543     libraries['sigc2'] = LibraryInfo()
544     libraries['sigc2'].ParseConfig('pkg-config --cflags --libs sigc++-2.0')
545     libraries['glibmm2'] = LibraryInfo()
546     libraries['glibmm2'].ParseConfig('pkg-config --cflags --libs glibmm-2.4')
547     libraries['gdkmm2'] = LibraryInfo()
548     libraries['gdkmm2'].ParseConfig ('pkg-config --cflags --libs gdkmm-2.4')
549     libraries['gtkmm2'] = LibraryInfo()
550     libraries['gtkmm2'].ParseConfig ('pkg-config --cflags --libs gtkmm-2.4')
551     libraries['atkmm'] = LibraryInfo()
552     libraries['atkmm'].ParseConfig ('pkg-config --cflags --libs atkmm-1.6')
553     libraries['pangomm'] = LibraryInfo()
554     libraries['pangomm'].ParseConfig ('pkg-config --cflags --libs pangomm-1.4')
555     libraries['libgnomecanvasmm'] = LibraryInfo()
556     libraries['libgnomecanvasmm'].ParseConfig ('pkg-config --cflags --libs libgnomecanvasmm-2.6')
557
558 #
559 # cannot use system one for the time being
560 #
561     
562     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
563                                     LIBPATH='#libs/libsndfile',
564                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
565
566 #    libraries['libglademm'] = LibraryInfo()
567 #    libraries['libglademm'].ParseConfig ('pkg-config --cflags --libs libglademm-2.4')
568
569 #    libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
570     libraries['soundtouch'] = LibraryInfo()
571     libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs soundtouch-1.0')
572
573     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
574                                             LIBPATH='#libs/appleutility',
575                                             CPPPATH='#libs/appleutility')
576     
577     coredirs = [
578         'templates'
579     ]
580     
581     subdirs = [
582         'libs/libsndfile',
583         'libs/pbd',
584         'libs/midi++2',
585         'libs/ardour',
586     # these are unconditionally included but have
587     # tests internally to avoid compilation etc
588     # if VST is not set
589         'libs/fst',
590         'vst',
591     # this is unconditionally included but has
592     # tests internally to avoid compilation etc
593     # if COREAUDIO is not set
594         'libs/appleutility'
595         ]
596     
597     gtk_subdirs = [
598 #        'libs/flowcanvas',
599         'libs/gtkmm2ext',
600         'gtk2_ardour',
601         'libs/clearlooks'
602         ]
603
604 else:
605     libraries['sigc2'] = LibraryInfo(LIBS='sigc++2',
606                                     LIBPATH='#libs/sigc++2',
607                                     CPPPATH='#libs/sigc++2')
608     libraries['glibmm2'] = LibraryInfo(LIBS='glibmm2',
609                                     LIBPATH='#libs/glibmm2',
610                                     CPPPATH='#libs/glibmm2')
611     libraries['pangomm'] = LibraryInfo(LIBS='pangomm',
612                                     LIBPATH='#libs/gtkmm2/pango',
613                                     CPPPATH='#libs/gtkmm2/pango')
614     libraries['atkmm'] = LibraryInfo(LIBS='atkmm',
615                                      LIBPATH='#libs/gtkmm2/atk',
616                                      CPPPATH='#libs/gtkmm2/atk')
617     libraries['gdkmm2'] = LibraryInfo(LIBS='gdkmm2',
618                                       LIBPATH='#libs/gtkmm2/gdk',
619                                       CPPPATH='#libs/gtkmm2/gdk')
620     libraries['gtkmm2'] = LibraryInfo(LIBS='gtkmm2',
621                                      LIBPATH="#libs/gtkmm2/gtk",
622                                      CPPPATH='#libs/gtkmm2/gtk/')
623     libraries['libgnomecanvasmm'] = LibraryInfo(LIBS='libgnomecanvasmm',
624                                                 LIBPATH='#libs/libgnomecanvasmm',
625                                                 CPPPATH='#libs/libgnomecanvasmm')
626     
627     libraries['soundtouch'] = LibraryInfo(LIBS='soundtouch',
628                                           LIBPATH='#libs/soundtouch',
629                                           CPPPATH=['#libs', '#libs/soundtouch'])
630     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
631                                     LIBPATH='#libs/libsndfile',
632                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
633 #    libraries['libglademm'] = LibraryInfo(LIBS='libglademm',
634 #                                          LIBPATH='#libs/libglademm',
635 #                                          CPPPATH='#libs/libglademm')
636     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
637                                             LIBPATH='#libs/appleutility',
638                                             CPPPATH='#libs/appleutility')
639
640     coredirs = [
641         'libs/soundtouch',
642         'templates'
643     ]
644     
645     subdirs = [
646         'libs/sigc++2',
647         'libs/libsndfile',
648         'libs/pbd',
649         'libs/midi++2',
650         'libs/ardour',
651     # these are unconditionally included but have
652     # tests internally to avoid compilation etc
653     # if VST is not set
654         'libs/fst',
655         'vst',
656     # this is unconditionally included but has
657     # tests internally to avoid compilation etc
658     # if COREAUDIO is not set
659         'libs/appleutility'
660         ]
661     
662     gtk_subdirs = [
663         'libs/glibmm2',
664         'libs/gtkmm2/pango',
665         'libs/gtkmm2/atk',
666         'libs/gtkmm2/gdk',
667         'libs/gtkmm2/gtk',
668         'libs/libgnomecanvasmm',
669 #       'libs/flowcanvas',
670         'libs/gtkmm2ext',
671         'gtk2_ardour',
672         'libs/clearlooks'
673         ]
674
675 #
676 # always build the LGPL control protocol lib, since we link against it ourselves
677 # ditto for generic MIDI
678 #
679
680 surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi' ]
681
682 if env['SURFACES']:
683     if have_libusb:
684         surface_subdirs += [ 'libs/surfaces/tranzport' ]
685     if os.access ('libs/surfaces/sony9pin', os.F_OK):
686         surface_subdirs += [ 'libs/surfaces/sony9pin' ]
687
688 opts.Save('scache.conf', env)
689 Help(opts.GenerateHelpText(env))
690
691 if os.environ.has_key('PATH'):
692     env.Append(PATH = os.environ['PATH'])
693
694 if os.environ.has_key('PKG_CONFIG_PATH'):
695     env.Append(PKG_CONFIG_PATH = os.environ['PKG_CONFIG_PATH'])
696
697 if os.environ.has_key('CC'):
698     env['CC'] = os.environ['CC']
699
700 if os.environ.has_key('CXX'):
701     env['CXX'] = os.environ['CXX']
702
703 if os.environ.has_key('DISTCC_HOSTS'):
704     env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
705     env['ENV']['HOME'] = os.environ['HOME']
706
707 final_prefix = '$PREFIX'
708
709 if env['DESTDIR'] :
710     install_prefix = '$DESTDIR/$PREFIX'
711 else:
712     install_prefix = env['PREFIX']
713
714 subst_dict['%INSTALL_PREFIX%'] = install_prefix;
715 subst_dict['%FINAL_PREFIX%'] = final_prefix;
716 subst_dict['%PREFIX%'] = final_prefix;
717
718 if env['PREFIX'] == '/usr':
719     final_config_prefix = '/etc'
720 else:
721     final_config_prefix = env['PREFIX'] + '/etc'
722
723 config_prefix = '$DESTDIR' + final_config_prefix
724
725 # SCons should really do this for us
726
727 conf = Configure (env)
728
729 have_cxx = conf.TryAction (Action (str(env['CXX']) + ' --version'))
730 if have_cxx[0] != 1:
731     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
732     sys.exit (1)
733 else:
734     print "Congratulations, you have a functioning C++ compiler."
735
736 env = conf.Finish()
737
738 #
739 # Compiler flags and other system-dependent stuff
740 #
741
742 opt_flags = []
743 debug_flags = [ '-g' ]
744
745 # guess at the platform, used to define compiler flags
746
747 config_guess = os.popen("tools/config.guess").read()[:-1]
748
749 config_cpu = 0
750 config_arch = 1
751 config_kernel = 2
752 config_os = 3
753 config = config_guess.split ("-")
754
755 print "system triple: " + config_guess
756
757 # Autodetect
758 if env['DIST_TARGET'] == 'auto':
759     if config[config_arch] == 'apple':
760         # The [.] matches to the dot after the major version, "." would match any character
761         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
762             env['DIST_TARGET'] = 'panther'
763         else:
764             env['DIST_TARGET'] = 'tiger'
765     else:
766         if re.search ("x86_64", config[config_cpu]) != None:
767             env['DIST_TARGET'] = 'x86_64'
768         elif re.search("i[0-5]86", config[config_cpu]) != None:
769             env['DIST_TARGET'] = 'i386'
770         elif re.search("powerpc", config[config_cpu]) != None:
771             env['DIST_TARGET'] = 'powerpc'
772         else:
773             env['DIST_TARGET'] = 'i686'
774     print "\n*******************************"
775     print "detected DIST_TARGET = " + env['DIST_TARGET']
776     print "*******************************\n"
777
778
779 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
780     #
781     # Apple/PowerPC optimization options
782     #
783     # -mcpu=7450 does not reliably work with gcc 3.*
784     #
785     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
786         if config[config_arch] == 'apple':
787             opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
788         else:
789             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"])
790     else:
791         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
792     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
793
794 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':
795     
796     build_host_supports_sse = 0
797     
798     debug_flags.append ("-DARCH_X86")
799     opt_flags.append ("-DARCH_X86")
800     
801     if config[config_kernel] == 'linux' :
802         
803         if env['DIST_TARGET'] != 'i386':
804             
805             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
806             x86_flags = flag_line.split (": ")[1:][0].split (' ')
807             
808             if "mmx" in x86_flags:
809                 opt_flags.append ("-mmmx")
810             if "sse" in x86_flags:
811                 build_host_supports_sse = 1
812             if "3dnow" in x86_flags:
813                 opt_flags.append ("-m3dnow")
814             
815             if config[config_cpu] == "i586":
816                 opt_flags.append ("-march=i586")
817             elif config[config_cpu] == "i686":
818                 opt_flags.append ("-march=i686")
819     
820     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
821         opt_flags.extend (["-msse", "-mfpmath=sse"])
822         debug_flags.extend (["-msse", "-mfpmath=sse"])
823 # end of processor-specific section
824
825 # optimization section
826 if env['FPU_OPTIMIZATION']:
827     if env['DIST_TARGET'] == 'tiger':
828         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
829         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
830         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
831     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
832         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
833         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
834         if env['DIST_TARGET'] == 'x86_64':
835             opt_flags.append ("-DUSE_X86_64_ASM")
836             debug_flags.append ("-DUSE_X86_64_ASM")
837         if build_host_supports_sse != 1:
838             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)"
839 # end optimization section
840
841 #
842 # save off guessed arch element in an env
843 #
844 env.Append(CONFIG_ARCH=config[config_arch])
845
846
847 #
848 # ARCH="..." overrides all
849 #
850
851 if env['ARCH'] != '':
852     opt_flags = env['ARCH'].split()
853
854 #
855 # prepend boiler plate optimization flags
856 #
857
858 opt_flags[:0] = [
859     "-O3",
860     "-fomit-frame-pointer",
861     "-ffast-math",
862     "-fstrength-reduce"
863     ]
864
865 if env['DEBUG'] == 1:
866     env.Append(CCFLAGS=" ".join (debug_flags))
867 else:
868     env.Append(CCFLAGS=" ".join (opt_flags))
869
870 #
871 # warnings flags
872 #
873
874 env.Append(CCFLAGS="-Wall")
875 env.Append(CXXFLAGS="-Woverloaded-virtual")
876
877 if env['EXTRA_WARN']:
878     env.Append(CCFLAGS="-Wextra -pedantic")
879     env.Append(CXXFLAGS="-ansi")
880
881 if env['LIBLO']:
882     env.Append(CCFLAGS="-DHAVE_LIBLO")
883
884 #
885 # everybody needs this
886 #
887
888 env.Merge ([ libraries['core'] ])
889
890 #
891 # fix scons nitpickiness on APPLE
892 #
893
894 if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
895     env.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib")
896
897 #
898 # i18n support
899 #
900
901 conf = Configure (env)
902 if env['NLS']:
903     nls_error = 'This system is not configured for internationalized applications.  An english-only version will be built:'
904     print 'Checking for internationalization support ...'
905     have_gettext = conf.TryAction(Action('xgettext --version'))
906     if have_gettext[0] != 1:
907         nls_error += ' No xgettext command.'
908         env['NLS'] = 0
909     else:
910         print "Found xgettext"
911     
912     have_msgmerge = conf.TryAction(Action('msgmerge --version'))
913     if have_msgmerge[0] != 1:
914         nls_error += ' No msgmerge command.'
915         env['NLS'] = 0
916     else:
917         print "Found msgmerge"
918     
919     if not conf.CheckCHeader('libintl.h'):
920         nls_error += ' No libintl.h.'
921         env['NLS'] = 0
922         
923     if env['NLS'] == 0:
924         print nls_error
925     else:
926         print "International version will be built."
927 env = conf.Finish()
928
929 if env['NLS'] == 1:
930     env.Append(CCFLAGS="-DENABLE_NLS")
931
932 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n version subst_dict')
933
934 #
935 # the configuration file may be system dependent
936 #
937
938 conf = env.Configure ()
939
940 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
941     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
942     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
943 else:
944     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
945     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
946
947 # posix_memalign available
948 if not conf.CheckFunc('posix_memalign'):
949     print 'Did not find posix_memalign(), using malloc'
950     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
951
952
953 env = conf.Finish()
954
955 rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
956
957 the_revision = env.Command ('frobnicatory_decoy', [], create_stored_revision)
958
959 env.Alias('revision', the_revision)
960 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
961 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.rc'))
962
963 Default (rcbuild)
964
965 # source tarball
966
967 Precious (env['DISTTREE'])
968
969 env.Distribute (env['DISTTREE'],
970                [ 'SConstruct', 'svn_revision.h',
971                   'COPYING', 'PACKAGER_README', 'README',
972                   'ardour.rc.in',
973                   'ardour_system.rc',
974                   'tools/config.guess',
975                   'icons/icon/ardour_icon_mac_mask.png',
976                   'icons/icon/ardour_icon_mac.png',
977                   'icons/icon/ardour_icon_tango_16px_blue.png',
978                   'icons/icon/ardour_icon_tango_16px_red.png',
979                   'icons/icon/ardour_icon_tango_22px_blue.png',
980                   'icons/icon/ardour_icon_tango_22px_red.png',
981                   'icons/icon/ardour_icon_tango_32px_blue.png',
982                   'icons/icon/ardour_icon_tango_32px_red.png',
983                   'icons/icon/ardour_icon_tango_48px_blue.png',
984                   'icons/icon/ardour_icon_tango_48px_red.png'
985                   ] +
986                 glob.glob ('DOCUMENTATION/AUTHORS*') +
987                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
988                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
989                 glob.glob ('DOCUMENTATION/BUILD*') +
990                 glob.glob ('DOCUMENTATION/FAQ*') +
991                 glob.glob ('DOCUMENTATION/README*')
992                 )
993
994 srcdist = env.Tarball(env['TARBALL'], [ env['DISTTREE'], the_revision ])
995 env.Alias ('srctar', srcdist)
996
997 #
998 # don't leave the distree around
999 #
1000
1001 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
1002 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
1003
1004 #
1005 # the subdirs
1006 #
1007
1008 for subdir in coredirs:
1009     SConscript (subdir + '/SConscript')
1010
1011 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
1012     for subdir in sublistdir:
1013         SConscript (subdir + '/SConscript')
1014
1015 # cleanup
1016 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
1017