b12b803121654dddb45e7821cb371da942656f38
[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.0beta3'
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
507 if conf.CheckCHeader('alsa/asoundlib.h'):
508     libraries['sysmidi'] = LibraryInfo (LIBS='asound')
509     env['SYSMIDI'] = 'ALSA Sequencer'
510     subst_dict['%MIDITAG%'] = "seq"
511     subst_dict['%MIDITYPE%'] = "alsa/sequencer"
512 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
513     # this line is needed because scons can't handle -framework in ParseConfig() yet.
514     libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
515     env['SYSMIDI'] = 'CoreMIDI'
516     subst_dict['%MIDITAG%'] = "ardour"
517     subst_dict['%MIDITYPE%'] = "coremidi"
518 else:
519     print "It appears you don't have the required MIDI libraries installed."
520     sys.exit (1)
521
522 env = conf.Finish()
523
524 if env['SYSLIBS']:
525     
526     libraries['sigc2'] = LibraryInfo()
527     libraries['sigc2'].ParseConfig('pkg-config --cflags --libs sigc++-2.0')
528     libraries['glibmm2'] = LibraryInfo()
529     libraries['glibmm2'].ParseConfig('pkg-config --cflags --libs glibmm-2.4')
530     libraries['gdkmm2'] = LibraryInfo()
531     libraries['gdkmm2'].ParseConfig ('pkg-config --cflags --libs gdkmm-2.4')
532     libraries['gtkmm2'] = LibraryInfo()
533     libraries['gtkmm2'].ParseConfig ('pkg-config --cflags --libs gtkmm-2.4')
534     libraries['atkmm'] = LibraryInfo()
535     libraries['atkmm'].ParseConfig ('pkg-config --cflags --libs atkmm-1.6')
536     libraries['pangomm'] = LibraryInfo()
537     libraries['pangomm'].ParseConfig ('pkg-config --cflags --libs pangomm-1.4')
538     libraries['libgnomecanvasmm'] = LibraryInfo()
539     libraries['libgnomecanvasmm'].ParseConfig ('pkg-config --cflags --libs libgnomecanvasmm-2.6')
540
541 #
542 # cannot use system one for the time being
543 #
544     
545     libraries['sndfile'] = LibraryInfo(LIBS='libsndfile',
546                                     LIBPATH='#libs/libsndfile',
547                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
548
549 #    libraries['libglademm'] = LibraryInfo()
550 #    libraries['libglademm'].ParseConfig ('pkg-config --cflags --libs libglademm-2.4')
551
552 #    libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
553     libraries['soundtouch'] = LibraryInfo()
554     libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs soundtouch-1.0')
555
556     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
557                                             LIBPATH='#libs/appleutility',
558                                             CPPPATH='#libs/appleutility')
559     
560     coredirs = [
561         'templates'
562     ]
563     
564     subdirs = [
565         'libs/libsndfile',
566         'libs/pbd',
567         'libs/midi++2',
568         'libs/ardour'
569         ]
570     
571     if env['VST']:
572         subdirs = ['libs/fst'] + subdirs + ['vst']
573
574     if env['COREAUDIO']:
575         subdirs = subdirs + ['libs/appleutility']
576     
577     gtk_subdirs = [
578 #        'libs/flowcanvas',
579         'libs/gtkmm2ext',
580         'gtk2_ardour'
581         ]
582
583 else:
584     libraries['sigc2'] = LibraryInfo(LIBS='sigc++2',
585                                     LIBPATH='#libs/sigc++2',
586                                     CPPPATH='#libs/sigc++2')
587     libraries['glibmm2'] = LibraryInfo(LIBS='glibmm2',
588                                     LIBPATH='#libs/glibmm2',
589                                     CPPPATH='#libs/glibmm2')
590     libraries['pangomm'] = LibraryInfo(LIBS='pangomm',
591                                     LIBPATH='#libs/gtkmm2/pango',
592                                     CPPPATH='#libs/gtkmm2/pango')
593     libraries['atkmm'] = LibraryInfo(LIBS='atkmm',
594                                      LIBPATH='#libs/gtkmm2/atk',
595                                      CPPPATH='#libs/gtkmm2/atk')
596     libraries['gdkmm2'] = LibraryInfo(LIBS='gdkmm2',
597                                       LIBPATH='#libs/gtkmm2/gdk',
598                                       CPPPATH='#libs/gtkmm2/gdk')
599     libraries['gtkmm2'] = LibraryInfo(LIBS='gtkmm2',
600                                      LIBPATH="#libs/gtkmm2/gtk",
601                                      CPPPATH='#libs/gtkmm2/gtk/')
602     libraries['libgnomecanvasmm'] = LibraryInfo(LIBS='libgnomecanvasmm',
603                                                 LIBPATH='#libs/libgnomecanvasmm',
604                                                 CPPPATH='#libs/libgnomecanvasmm')
605     
606     libraries['soundtouch'] = LibraryInfo(LIBS='soundtouch',
607                                           LIBPATH='#libs/soundtouch',
608                                           CPPPATH=['#libs', '#libs/soundtouch'])
609     libraries['sndfile'] = LibraryInfo(LIBS='libsndfile',
610                                     LIBPATH='#libs/libsndfile',
611                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
612 #    libraries['libglademm'] = LibraryInfo(LIBS='libglademm',
613 #                                          LIBPATH='#libs/libglademm',
614 #                                          CPPPATH='#libs/libglademm')
615     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
616                                             LIBPATH='#libs/appleutility',
617                                             CPPPATH='#libs/appleutility')
618
619     coredirs = [
620         'libs/soundtouch',
621         'templates'
622     ]
623     
624     subdirs = [
625         'libs/sigc++2',
626         'libs/libsndfile',
627         'libs/pbd',
628         'libs/midi++2',
629         'libs/ardour'
630         ]
631     
632     if env['VST']:
633         subdirs = ['libs/fst'] + subdirs + ['vst']
634
635     if env['COREAUDIO']:
636         subdirs = subdirs + ['libs/appleutility']
637     
638     gtk_subdirs = [
639         'libs/glibmm2',
640         'libs/gtkmm2/pango',
641         'libs/gtkmm2/atk',
642         'libs/gtkmm2/gdk',
643         'libs/gtkmm2/gtk',
644         'libs/libgnomecanvasmm',
645 #       'libs/flowcanvas',
646     'libs/gtkmm2ext',
647     'gtk2_ardour'
648         ]
649
650 #
651 # always build the LGPL control protocol lib, since we link against it ourselves
652 # ditto for generic MIDI
653 #
654
655 surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi' ]
656
657 if env['SURFACES']:
658     if have_libusb:
659         surface_subdirs += [ 'libs/surfaces/tranzport' ]
660     if os.access ('libs/surfaces/sony9pin', os.F_OK):
661         surface_subdirs += [ 'libs/surfaces/sony9pin' ]
662
663 opts.Save('scache.conf', env)
664 Help(opts.GenerateHelpText(env))
665
666 if os.environ.has_key('PATH'):
667     env.Append(PATH = os.environ['PATH'])
668
669 if os.environ.has_key('PKG_CONFIG_PATH'):
670     env.Append(PKG_CONFIG_PATH = os.environ['PKG_CONFIG_PATH'])
671
672 if os.environ.has_key('CC'):
673     env['CC'] = os.environ['CC']
674
675 if os.environ.has_key('CXX'):
676     env['CXX'] = os.environ['CXX']
677
678 if os.environ.has_key('DISTCC_HOSTS'):
679     env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
680     env['ENV']['HOME'] = os.environ['HOME']
681
682 final_prefix = '$PREFIX'
683
684 if env['DESTDIR'] :
685     install_prefix = '$DESTDIR/$PREFIX'
686 else:
687     install_prefix = env['PREFIX']
688
689 subst_dict['%INSTALL_PREFIX%'] = install_prefix;
690 subst_dict['%FINAL_PREFIX%'] = final_prefix;
691 subst_dict['%PREFIX%'] = final_prefix;
692
693 if env['PREFIX'] == '/usr':
694     final_config_prefix = '/etc'
695 else:
696     final_config_prefix = env['PREFIX'] + '/etc'
697
698 config_prefix = '$DESTDIR' + final_config_prefix
699
700 # SCons should really do this for us
701
702 conf = Configure (env)
703
704 have_cxx = conf.TryAction (Action (env['CXX'] + ' --version'))
705 if have_cxx[0] != 1:
706     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
707     exit (1)
708 else:
709     print "Congratulations, you have a functioning C++ compiler."
710
711 env = conf.Finish()
712
713 #
714 # Compiler flags and other system-dependent stuff
715 #
716
717 opt_flags = []
718 debug_flags = [ '-g' ]
719
720 # guess at the platform, used to define compiler flags
721
722 config_guess = os.popen("tools/config.guess").read()[:-1]
723
724 config_cpu = 0
725 config_arch = 1
726 config_kernel = 2
727 config_os = 3
728 config = config_guess.split ("-")
729
730 print "system triple: " + config_guess
731
732 # Autodetect
733 if env['DIST_TARGET'] == 'auto':
734     if config[config_arch] == 'apple':
735         # The [.] matches to the dot after the major version, "." would match any character
736         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
737             env['DIST_TARGET'] = 'panther'
738         else:
739             env['DIST_TARGET'] = 'tiger'
740     else:
741         if re.search ("x86_64", config[config_cpu]) != None:
742             env['DIST_TARGET'] = 'x86_64'
743         elif re.search("i[0-5]86", config[config_cpu]) != None:
744             env['DIST_TARGET'] = 'i386'
745         elif re.search("powerpc", config[config_cpu]) != None:
746             env['DIST_TARGET'] = 'powerpc'
747         else:
748             env['DIST_TARGET'] = 'i686'
749     print "\n*******************************"
750     print "detected DIST_TARGET = " + env['DIST_TARGET']
751     print "*******************************\n"
752
753
754 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
755     #
756     # Apple/PowerPC optimization options
757     #
758     # -mcpu=7450 does not reliably work with gcc 3.*
759     #
760     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
761         if config[config_arch] == 'apple':
762             opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
763         else:
764             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"])
765     else:
766         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
767     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
768
769 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':
770     
771     build_host_supports_sse = 0
772     
773     debug_flags.append ("-DARCH_X86")
774     opt_flags.append ("-DARCH_X86")
775     
776     if config[config_kernel] == 'linux' :
777         
778         if env['DIST_TARGET'] != 'i386':
779             
780             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
781             x86_flags = flag_line.split (": ")[1:][0].split (' ')
782             
783             if "mmx" in x86_flags:
784                 opt_flags.append ("-mmmx")
785             if "sse" in x86_flags:
786                 build_host_supports_sse = 1
787             if "3dnow" in x86_flags:
788                 opt_flags.append ("-m3dnow")
789             
790             if config[config_cpu] == "i586":
791                 opt_flags.append ("-march=i586")
792             elif config[config_cpu] == "i686":
793                 opt_flags.append ("-march=i686")
794     
795     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
796         opt_flags.extend (["-msse", "-mfpmath=sse"])
797         debug_flags.extend (["-msse", "-mfpmath=sse"])
798 # end of processor-specific section
799
800 # optimization section
801 if env['FPU_OPTIMIZATION']:
802     if env['DIST_TARGET'] == 'tiger':
803         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
804         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
805         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
806     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
807         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
808         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
809         if env['DIST_TARGET'] == 'x86_64':
810             opt_flags.append ("-DUSE_X86_64_ASM")
811             debug_flags.append ("-DUSE_X86_64_ASM")
812         if build_host_supports_sse != 1:
813             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)"
814 # end optimization section
815
816 #
817 # save off guessed arch element in an env
818 #
819 env.Append(CONFIG_ARCH=config[config_arch])
820
821
822 #
823 # ARCH="..." overrides all
824 #
825
826 if env['ARCH'] != '':
827     opt_flags = env['ARCH'].split()
828
829 #
830 # prepend boiler plate optimization flags
831 #
832
833 opt_flags[:0] = [
834     "-O3",
835     "-fomit-frame-pointer",
836     "-ffast-math",
837     "-fstrength-reduce"
838     ]
839
840 if env['DEBUG'] == 1:
841     env.Append(CCFLAGS=" ".join (debug_flags))
842 else:
843     env.Append(CCFLAGS=" ".join (opt_flags))
844
845 #
846 # warnings flags
847 #
848
849 env.Append(CCFLAGS="-Wall")
850 env.Append(CXXFLAGS="-Woverloaded-virtual")
851
852 if env['EXTRA_WARN']:
853     env.Append(CCFLAGS="-Wextra -pedantic")
854     env.Append(CXXFLAGS="-ansi")
855
856 if env['LIBLO']:
857     env.Append(CCFLAGS="-DHAVE_LIBLO")
858
859 #
860 # everybody needs this
861 #
862
863 env.Merge ([ libraries['core'] ])
864
865 #
866 # fix scons nitpickiness on APPLE
867 #
868
869 if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
870     env.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib")
871
872 #
873 # i18n support
874 #
875
876 conf = Configure (env)
877 if env['NLS']:
878     nls_error = 'This system is not configured for internationalized applications.  An english-only version will be built:'
879     print 'Checking for internationalization support ...'
880     have_gettext = conf.TryAction(Action('xgettext --version'))
881     if have_gettext[0] != 1:
882         nls_error += ' No xgettext command.'
883         env['NLS'] = 0
884     else:
885         print "Found xgettext"
886     
887     have_msgmerge = conf.TryAction(Action('msgmerge --version'))
888     if have_msgmerge[0] != 1:
889         nls_error += ' No msgmerge command.'
890         env['NLS'] = 0
891     else:
892         print "Found msgmerge"
893     
894     if not conf.CheckCHeader('libintl.h'):
895         nls_error += ' No libintl.h.'
896         env['NLS'] = 0
897         
898     if env['NLS'] == 0:
899         print nls_error
900     else:
901         print "International version will be built."
902 env = conf.Finish()
903
904 if env['NLS'] == 1:
905     env.Append(CCFLAGS="-DENABLE_NLS")
906
907 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n version subst_dict')
908
909 #
910 # the configuration file may be system dependent
911 #
912
913 conf = env.Configure ()
914
915 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
916     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
917     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
918 else:
919     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
920     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
921
922 # posix_memalign available
923 if not conf.CheckFunc('posix_memalign'):
924     print 'Did not find posix_memalign(), using malloc'
925     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
926
927
928 env = conf.Finish()
929
930 rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
931
932 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
933 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.rc'))
934
935 Default (rcbuild)
936
937 # source tarball
938
939 Precious (env['DISTTREE'])
940
941 #
942 # note the special "cleanfirst" source name. this triggers removal
943 # of the existing disttree
944 #
945
946 env.Distribute (env['DISTTREE'],
947                 [ 'SConstruct',
948                   'COPYING', 'PACKAGER_README', 'README',
949                   'ardour.rc.in',
950                   'ardour_system.rc',
951                   'tools/config.guess'
952                   ] +
953                 glob.glob ('DOCUMENTATION/AUTHORS*') +
954                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
955                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
956                 glob.glob ('DOCUMENTATION/BUILD*') +
957                 glob.glob ('DOCUMENTATION/FAQ*') +
958                 glob.glob ('DOCUMENTATION/README*')
959                 )
960
961 srcdist = env.Tarball(env['TARBALL'], env['DISTTREE'])
962 env.Alias ('srctar', srcdist)
963 #
964 # don't leave the distree around
965 #
966 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
967 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
968
969 #
970 # the subdirs
971 #
972
973 for subdir in coredirs:
974     SConscript (subdir + '/SConscript')
975
976 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
977     for subdir in sublistdir:
978         SConscript (subdir + '/SConscript')
979
980 # cleanup
981 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
982