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