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