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