more fiddling about with placing bits of the scroll/zoom operation in the idle callba...
[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.0beta2'
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. VST support disabled.'
369         env['VST'] = 0;
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 install_prefix = '$DESTDIR/$PREFIX'
684
685 subst_dict['INSTALL_PREFIX'] = install_prefix;
686
687 if env['PREFIX'] == '/usr':
688     final_config_prefix = '/etc'
689 else:
690     final_config_prefix = env['PREFIX'] + '/etc'
691
692 config_prefix = '$DESTDIR' + final_config_prefix
693
694
695 # SCons should really do this for us
696
697 conf = Configure (env)
698
699 have_cxx = conf.TryAction (Action (env['CXX'] + ' --version'))
700 if have_cxx[0] != 1:
701     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
702     exit (1)
703 else:
704     print "Congratulations, you have a functioning C++ compiler."
705
706 env = conf.Finish()
707
708 #
709 # Compiler flags and other system-dependent stuff
710 #
711
712 opt_flags = []
713 debug_flags = [ '-g' ]
714
715 # guess at the platform, used to define compiler flags
716
717 config_guess = os.popen("tools/config.guess").read()[:-1]
718
719 config_cpu = 0
720 config_arch = 1
721 config_kernel = 2
722 config_os = 3
723 config = config_guess.split ("-")
724
725 print "system triple: " + config_guess
726
727 # Autodetect
728 if env['DIST_TARGET'] == 'auto':
729     if config[config_arch] == 'apple':
730         # The [.] matches to the dot after the major version, "." would match any character
731         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
732             env['DIST_TARGET'] = 'panther'
733         else:
734             env['DIST_TARGET'] = 'tiger'
735     else:
736         if re.search ("x86_64", config[config_cpu]) != None:
737             env['DIST_TARGET'] = 'x86_64'
738         elif re.search("i[0-5]86", config[config_cpu]) != None:
739             env['DIST_TARGET'] = 'i386'
740         elif re.search("powerpc", config[config_cpu]) != None:
741             env['DIST_TARGET'] = 'powerpc'
742         else:
743             env['DIST_TARGET'] = 'i686'
744     print "\n*******************************"
745     print "detected DIST_TARGET = " + env['DIST_TARGET']
746     print "*******************************\n"
747
748
749 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
750     #
751     # Apple/PowerPC optimization options
752     #
753     # -mcpu=7450 does not reliably work with gcc 3.*
754     #
755     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
756         if config[config_arch] == 'apple':
757             opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
758         else:
759             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"])
760     else:
761         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
762     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
763
764 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':
765     
766     build_host_supports_sse = 0
767     
768     debug_flags.append ("-DARCH_X86")
769     opt_flags.append ("-DARCH_X86")
770     
771     if config[config_kernel] == 'linux' :
772         
773         if env['DIST_TARGET'] != 'i386':
774             
775             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
776             x86_flags = flag_line.split (": ")[1:][0].split (' ')
777             
778             if "mmx" in x86_flags:
779                 opt_flags.append ("-mmmx")
780             if "sse" in x86_flags:
781                 build_host_supports_sse = 1
782             if "3dnow" in x86_flags:
783                 opt_flags.append ("-m3dnow")
784             
785             if config[config_cpu] == "i586":
786                 opt_flags.append ("-march=i586")
787             elif config[config_cpu] == "i686":
788                 opt_flags.append ("-march=i686")
789     
790     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
791         opt_flags.extend (["-msse", "-mfpmath=sse"])
792         debug_flags.extend (["-msse", "-mfpmath=sse"])
793 # end of processor-specific section
794
795 # optimization section
796 if env['FPU_OPTIMIZATION']:
797     if env['DIST_TARGET'] == 'tiger':
798         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
799         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
800         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
801     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
802         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
803         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
804         if env['DIST_TARGET'] == 'x86_64':
805             opt_flags.append ("-DUSE_X86_64_ASM")
806             debug_flags.append ("-DUSE_X86_64_ASM")
807         if build_host_supports_sse != 1:
808             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)"
809 # end optimization section
810
811 #
812 # save off guessed arch element in an env
813 #
814 env.Append(CONFIG_ARCH=config[config_arch])
815
816
817 #
818 # ARCH="..." overrides all
819 #
820
821 if env['ARCH'] != '':
822     opt_flags = env['ARCH'].split()
823
824 #
825 # prepend boiler plate optimization flags
826 #
827
828 opt_flags[:0] = [
829     "-O3",
830     "-fomit-frame-pointer",
831     "-ffast-math",
832     "-fstrength-reduce"
833     ]
834
835 if env['DEBUG'] == 1:
836     env.Append(CCFLAGS=" ".join (debug_flags))
837 else:
838     env.Append(CCFLAGS=" ".join (opt_flags))
839
840 #
841 # warnings flags
842 #
843
844 env.Append(CCFLAGS="-Wall")
845 env.Append(CXXFLAGS="-Woverloaded-virtual")
846
847 if env['EXTRA_WARN']:
848     env.Append(CCFLAGS="-Wextra -pedantic")
849     env.Append(CXXFLAGS="-ansi")
850
851 if env['LIBLO']:
852     env.Append(CCFLAGS="-DHAVE_LIBLO")
853
854 #
855 # everybody needs this
856 #
857
858 env.Merge ([ libraries['core'] ])
859
860 #
861 # fix scons nitpickiness on APPLE
862 #
863
864 if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
865     env.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib")
866
867 #
868 # i18n support
869 #
870
871 conf = Configure (env)
872 if env['NLS']:
873     nls_error = 'This system is not configured for internationalized applications.  An english-only version will be built:'
874     print 'Checking for internationalization support ...'
875     have_gettext = conf.TryAction(Action('xgettext --version'))
876     if have_gettext[0] != 1:
877         nls_error += ' No xgettext command.'
878         env['NLS'] = 0
879     else:
880         print "Found xgettext"
881     
882     have_msgmerge = conf.TryAction(Action('msgmerge --version'))
883     if have_msgmerge[0] != 1:
884         nls_error += ' No msgmerge command.'
885         env['NLS'] = 0
886     else:
887         print "Found msgmerge"
888     
889     if not conf.CheckCHeader('libintl.h'):
890         nls_error += ' No libintl.h.'
891         env['NLS'] = 0
892         
893     if env['NLS'] == 0:
894         print nls_error
895     else:
896         print "International version will be built."
897 env = conf.Finish()
898
899 if env['NLS'] == 1:
900     env.Append(CCFLAGS="-DENABLE_NLS")
901
902 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n version subst_dict')
903
904 #
905 # the configuration file may be system dependent
906 #
907
908 conf = env.Configure ()
909
910 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
911     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
912     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
913 else:
914     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
915     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
916
917 # posix_memalign available
918 if not conf.CheckFunc('posix_memalign'):
919     print 'Did not find posix_memalign(), using malloc'
920     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
921
922
923 env = conf.Finish()
924
925 rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
926
927 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
928 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.rc'))
929
930 Default (rcbuild)
931
932 # source tarball
933
934 Precious (env['DISTTREE'])
935
936 #
937 # note the special "cleanfirst" source name. this triggers removal
938 # of the existing disttree
939 #
940
941 env.Distribute (env['DISTTREE'],
942                 [ 'SConstruct',
943                   'COPYING', 'PACKAGER_README', 'README',
944                   'ardour.rc.in',
945                   'ardour_system.rc',
946                   'tools/config.guess'
947                   ] +
948                 glob.glob ('DOCUMENTATION/AUTHORS*') +
949                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
950                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
951                 glob.glob ('DOCUMENTATION/BUILD*') +
952                 glob.glob ('DOCUMENTATION/FAQ*') +
953                 glob.glob ('DOCUMENTATION/README*')
954                 )
955
956 srcdist = env.Tarball(env['TARBALL'], env['DISTTREE'])
957 env.Alias ('srctar', srcdist)
958 #
959 # don't leave the distree around
960 #
961 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
962 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
963
964 #
965 # the subdirs
966 #
967
968 for subdir in coredirs:
969     SConscript (subdir + '/SConscript')
970
971 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
972     for subdir in sublistdir:
973         SConscript (subdir + '/SConscript')
974
975 # cleanup
976 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
977