r111@gandalf: fugalh | 2006-06-22 17:38:14 -0600
[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(CCFLAGS = '-Ilibs/libsndfile/src')
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 liblo
430
431 if env['LIBLO']:
432     libraries['lo'] = LibraryInfo ()
433
434     conf = Configure (libraries['lo'])
435     if conf.CheckLib ('lo', 'lo_server_new') == False:
436         print "liblo does not appear to be installed."
437         sys.exit (1)
438     
439     libraries['lo'] = conf.Finish ()
440
441 #
442 # Check for dmalloc
443
444 libraries['dmalloc'] = LibraryInfo ()
445
446 #
447 # look for the threaded version
448 #
449
450 conf = Configure (libraries['dmalloc'])
451 if conf.CheckLib ('dmallocth', 'dmalloc_shutdown'):
452     have_libdmalloc = True
453 else:
454     have_libdmalloc = False
455     
456 libraries['dmalloc'] = conf.Finish ()
457
458 #
459
460 #
461 # Audio/MIDI library (needed for MIDI, since audio is all handled via JACK)
462
463
464 conf = Configure(env)
465
466 if conf.CheckCHeader('alsa/asoundlib.h'):
467     libraries['sysmidi'] = LibraryInfo (LIBS='asound')
468     env['SYSMIDI'] = 'ALSA Sequencer'
469     subst_dict['%MIDITAG%'] = "seq"
470     subst_dict['%MIDITYPE%'] = "alsa/sequencer"
471 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
472     # this line is needed because scons can't handle -framework in ParseConfig() yet.
473     libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
474     env['SYSMIDI'] = 'CoreMIDI'
475     subst_dict['%MIDITAG%'] = "ardour"
476     subst_dict['%MIDITYPE%'] = "coremidi"
477 else:
478     print "It appears you don't have the required MIDI libraries installed."
479     sys.exit (1)
480         
481 env = conf.Finish()
482
483 if env['SYSLIBS']:
484
485     libraries['sigc2'] = LibraryInfo()
486     libraries['sigc2'].ParseConfig('pkg-config --cflags --libs sigc++-2.0')
487     libraries['glibmm2'] = LibraryInfo()
488     libraries['glibmm2'].ParseConfig('pkg-config --cflags --libs glibmm-2.4')
489     libraries['gdkmm2'] = LibraryInfo()
490     libraries['gdkmm2'].ParseConfig ('pkg-config --cflags --libs gdkmm-2.4')
491     libraries['gtkmm2'] = LibraryInfo()
492     libraries['gtkmm2'].ParseConfig ('pkg-config --cflags --libs gtkmm-2.4')
493     libraries['atkmm'] = LibraryInfo()
494     libraries['atkmm'].ParseConfig ('pkg-config --cflags --libs atkmm-1.6')
495     libraries['pangomm'] = LibraryInfo()
496     libraries['pangomm'].ParseConfig ('pkg-config --cflags --libs pangomm-1.4')
497     libraries['libgnomecanvasmm'] = LibraryInfo()
498     libraries['libgnomecanvasmm'].ParseConfig ('pkg-config --cflags --libs libgnomecanvasmm-2.6')
499
500 #    libraries['libglademm'] = LibraryInfo()
501 #    libraries['libglademm'].ParseConfig ('pkg-config --cflags --libs libglademm-2.4')
502
503 #    libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
504     libraries['soundtouch'] = LibraryInfo()
505     libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs soundtouch-1.0')
506
507     coredirs = [
508         'templates'
509     ]
510
511     subdirs = [
512         'libs/pbd3',
513         'libs/midi++2',
514         'libs/ardour'
515         ]
516
517     gtk_subdirs = [
518 #        'libs/flowcanvas',
519         'libs/gtkmm2ext',
520         'gtk2_ardour'
521         ]
522
523 else:
524     libraries['sigc2'] = LibraryInfo(LIBS='sigc++2',
525                                     LIBPATH='#libs/sigc++2',
526                                     CPPPATH='#libs/sigc++2')
527     libraries['glibmm2'] = LibraryInfo(LIBS='glibmm2',
528                                     LIBPATH='#libs/glibmm2',
529                                     CPPPATH='#libs/glibmm2')
530     libraries['pangomm'] = LibraryInfo(LIBS='pangomm',
531                                     LIBPATH='#libs/gtkmm2/pango',
532                                     CPPPATH='#libs/gtkmm2/pango')
533     libraries['atkmm'] = LibraryInfo(LIBS='atkmm',
534                                      LIBPATH='#libs/gtkmm2/atk',
535                                      CPPPATH='#libs/gtkmm2/atk')
536     libraries['gdkmm2'] = LibraryInfo(LIBS='gdkmm2',
537                                       LIBPATH='#libs/gtkmm2/gdk',
538                                       CPPPATH='#libs/gtkmm2/gdk')
539     libraries['gtkmm2'] = LibraryInfo(LIBS='gtkmm2',
540                                      LIBPATH="#libs/gtkmm2/gtk",
541                                      CPPPATH='#libs/gtkmm2/gtk/')
542     libraries['libgnomecanvasmm'] = LibraryInfo(LIBS='libgnomecanvasmm',
543                                                 LIBPATH='#libs/libgnomecanvasmm',
544                                                 CPPPATH='#libs/libgnomecanvasmm')
545
546     libraries['soundtouch'] = LibraryInfo(LIBS='soundtouch',
547                                           LIBPATH='#libs/soundtouch',
548                                           CPPPATH=['#libs', '#libs/soundtouch'])
549     libraries['sndfile'] = LibraryInfo(LIBS='libsndfile',
550                                     LIBPATH='#libs/libsndfile',
551                                     CPPPATH='#libs/libsndfile')
552 #    libraries['libglademm'] = LibraryInfo(LIBS='libglademm',
553 #                                          LIBPATH='#libs/libglademm',
554 #                                          CPPPATH='#libs/libglademm')
555
556     coredirs = [
557         'libs/soundtouch',
558         'templates'
559     ]
560
561     subdirs = [
562 #           'libs/cassowary',
563         'libs/sigc++2',
564         'libs/libsndfile',
565         'libs/pbd3',
566         'libs/midi++2',
567         'libs/ardour'
568         ]
569
570     gtk_subdirs = [
571         'libs/glibmm2',
572         'libs/gtkmm2/pango',
573         'libs/gtkmm2/atk',
574         'libs/gtkmm2/gdk',
575         'libs/gtkmm2/gtk',
576         'libs/libgnomecanvasmm',
577 #       'libs/flowcanvas',
578     'libs/gtkmm2ext',
579     'gtk2_ardour'
580         ]
581
582 #
583 # always build the LGPL control protocol lib, since we link against it ourselves
584 # ditto for generic MIDI
585 #
586
587 surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi' ]
588
589 if env['SURFACES']:
590     if have_libusb:
591         surface_subdirs += [ 'libs/surfaces/tranzport' ]
592     if os.access ('libs/surfaces/sony9pin', os.F_OK):
593         surface_subdirs += [ 'libs/surfaces/sony9pin' ]
594     
595 opts.Save('scache.conf', env)
596 Help(opts.GenerateHelpText(env))
597
598 if os.environ.has_key('PATH'):
599     env.Append(PATH = os.environ['PATH'])
600
601 if os.environ.has_key('PKG_CONFIG_PATH'):
602     env.Append(PKG_CONFIG_PATH = os.environ['PKG_CONFIG_PATH'])
603
604 if os.environ.has_key('CC'):
605     env['CC'] = os.environ['CC']
606
607 if os.environ.has_key('CXX'):
608     env['CXX'] = os.environ['CXX']
609
610 if os.environ.has_key('DISTCC_HOSTS'):
611     env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
612     env['ENV']['HOME'] = os.environ['HOME']
613     
614 final_prefix = '$PREFIX'
615 install_prefix = '$DESTDIR/$PREFIX'
616
617 subst_dict['INSTALL_PREFIX'] = install_prefix;
618
619 if env['PREFIX'] == '/usr':
620     final_config_prefix = '/etc'
621 else:
622     final_config_prefix = env['PREFIX'] + '/etc'
623
624 config_prefix = '$DESTDIR' + final_config_prefix
625
626
627 # SCons should really do this for us
628
629 conf = Configure (env)
630
631 have_cxx = conf.TryAction (Action (env['CXX'] + ' --version'))
632 if have_cxx[0] != 1:
633     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
634     exit (1)
635 else:
636     print "Congratulations, you have a functioning C++ compiler."
637     
638 env = conf.Finish()
639
640 #
641 # Compiler flags and other system-dependent stuff
642 #
643
644 opt_flags = []
645 debug_flags = [ '-g' ]
646
647 # guess at the platform, used to define compiler flags
648
649 config_guess = os.popen("tools/config.guess").read()[:-1]
650
651 config_cpu = 0
652 config_arch = 1
653 config_kernel = 2
654 config_os = 3
655 config = config_guess.split ("-")
656
657 print "system triple: " + config_guess
658
659 # Autodetect
660 if env['DIST_TARGET'] == 'auto':
661     if config[config_arch] == 'apple':
662         # The [.] matches to the dot after the major version, "." would match any character
663         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
664             env['DIST_TARGET'] = 'panther'
665         else:
666             env['DIST_TARGET'] = 'tiger'
667     else:
668         if re.search ("x86_64", config[config_cpu]) != None:
669             env['DIST_TARGET'] = 'x86_64'
670         elif re.search("i[0-5]86", config[config_cpu]) != None:
671             env['DIST_TARGET'] = 'i386'
672         elif re.search("powerpc", config[config_cpu]) != None:
673             env['DIST_TARGET'] = 'powerpc'
674         else:
675             env['DIST_TARGET'] = 'i686'
676     print "\n*******************************"
677     print "detected DIST_TARGET = " + env['DIST_TARGET']
678     print "*******************************\n"
679
680
681 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
682     #
683     # Apple/PowerPC optimization options
684     #
685     # -mcpu=7450 does not reliably work with gcc 3.*
686     #
687     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
688         if config[config_arch] == 'apple':
689             opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
690         else:
691             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"]) 
692     else:
693         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
694     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
695
696 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':
697
698     build_host_supports_sse = 0
699     
700     debug_flags.append ("-DARCH_X86")
701     opt_flags.append ("-DARCH_X86")
702
703     if config[config_kernel] == 'linux' :
704
705         if env['DIST_TARGET'] != 'i386': 
706
707             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
708             x86_flags = flag_line.split (": ")[1:][0].split (' ')
709
710             if "mmx" in x86_flags:
711                 opt_flags.append ("-mmmx")
712             if "sse" in x86_flags:
713                 build_host_supports_sse = 1
714             if "3dnow" in x86_flags:
715                 opt_flags.append ("-m3dnow")
716
717             if config[config_cpu] == "i586":
718                 opt_flags.append ("-march=i586")
719             elif config[config_cpu] == "i686":
720                 opt_flags.append ("-march=i686")
721
722     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
723         opt_flags.extend (["-msse", "-mfpmath=sse"])
724         debug_flags.extend (["-msse", "-mfpmath=sse"])
725 # end of processor-specific section
726
727 # optimization section
728 if env['FPU_OPTIMIZATION']:
729     if env['DIST_TARGET'] == 'tiger':
730         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
731         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
732         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
733     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
734         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
735         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
736         if env['DIST_TARGET'] == 'x86_64':
737             opt_flags.append ("-DUSE_X86_64_ASM")
738             debug_flags.append ("-DUSE_X86_64_ASM")
739         if build_host_supports_sse != 1:
740             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)"
741 # end optimization section
742
743 #
744 # save off guessed arch element in an env
745 #
746 env.Append(CONFIG_ARCH=config[config_arch])
747
748
749 #
750 # ARCH="..." overrides all 
751 #
752
753 if env['ARCH'] != '':
754     opt_flags = env['ARCH'].split()
755
756 #
757 # prepend boiler plate optimization flags
758 #
759
760 opt_flags[:0] = [
761     "-O3",
762     "-fomit-frame-pointer",
763     "-ffast-math",
764     "-fstrength-reduce"
765     ]
766
767 if env['DEBUG'] == 1:
768     env.Append(CCFLAGS=" ".join (debug_flags))
769 else:
770     env.Append(CCFLAGS=" ".join (opt_flags))
771
772 env.Append(CCFLAGS="-Wall")
773
774 if env['VST']:
775     env.Append(CCFLAGS="-DVST_SUPPORT")
776
777 if env['LIBLO']:
778     env.Append(CCFLAGS="-DHAVE_LIBLO")
779
780 #
781 # everybody needs this
782 #
783
784 env.Merge ([ libraries['core'] ])
785
786 #
787 # i18n support 
788 #
789
790 conf = Configure (env)
791
792 if env['NLS']:
793     print 'Checking for internationalization support ...'
794     have_gettext = conf.TryAction(Action('xgettext --version'))
795     if have_gettext[0] != 1:
796         print 'This system is not configured for internationalized applications (no xgettext command). An english-only version will be built\n'
797         env['NLS'] = 0
798         
799     if conf.CheckCHeader('libintl.h') == None:
800         print 'This system is not configured for internationalized applications (no libintl.h). An english-only version will be built\n'
801         env['NLS'] = 0
802
803
804 env = conf.Finish()
805
806 if env['NLS'] == 1:
807     env.Append(CCFLAGS="-DENABLE_NLS")
808
809
810 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n version subst_dict')
811
812 #
813 # the configuration file may be system dependent
814 #
815
816 conf = env.Configure ()
817
818 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
819     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
820     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
821 else:
822     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
823     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
824
825 # posix_memalign available
826 if not conf.CheckFunc('posix_memalign'):
827     print 'Did not find posix_memalign(), using malloc'
828     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
829
830
831 env = conf.Finish()
832
833 rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
834
835 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
836 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.rc'))
837
838 Default (rcbuild)
839
840 # source tarball
841
842 Precious (env['DISTTREE'])
843
844 #
845 # note the special "cleanfirst" source name. this triggers removal
846 # of the existing disttree
847 #
848
849 env.Distribute (env['DISTTREE'],
850                 [ 'SConstruct',
851                   'COPYING', 'PACKAGER_README', 'README',
852                   'ardour.rc.in',
853                   'ardour_system.rc',
854                   'tools/config.guess'
855                   ] +
856                 glob.glob ('DOCUMENTATION/AUTHORS*') +
857                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
858                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
859                 glob.glob ('DOCUMENTATION/BUILD*') +
860                 glob.glob ('DOCUMENTATION/FAQ*') +
861                 glob.glob ('DOCUMENTATION/README*')
862                 )
863                 
864 srcdist = env.Tarball(env['TARBALL'], env['DISTTREE'])
865 env.Alias ('srctar', srcdist)
866 #
867 # don't leave the distree around 
868 #
869 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
870 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
871
872 #
873 # the subdirs
874
875
876 for subdir in coredirs:
877     SConscript (subdir + '/SConscript')
878
879 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
880     for subdir in sublistdir:
881         SConscript (subdir + '/SConscript')
882             
883 # cleanup
884 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
885