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