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