Committed filthy mess of a working copy solely for moving between machines.
[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 #import pickle
15
16 SConsignFile()
17 EnsureSConsVersion(0, 96)
18
19 version = '2.0alpha2'
20
21 subst_dict = { }
22
23 #
24 # Command-line options
25 #
26
27 opts = Options('scache.conf')
28 opts.AddOptions(
29   ('ARCH', 'Set architecture-specific compilation flags by hand (all flags as 1 argument)',''),
30     BoolOption('SYSLIBS', 'USE AT YOUR OWN RISK: CANCELS ALL SUPPORT FROM ARDOUR AUTHORS: Use existing system versions of various libraries instead of internal ones', 0),
31     BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 0),
32     PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'),
33     BoolOption('NLS', 'Set to turn on i18n support', 1),
34     PathOption('PREFIX', 'Set the install "prefix"', '/usr/local'),
35     BoolOption('VST', 'Compile with support for VST', 0),
36     BoolOption('VERSIONED', 'Add version information to ardour/gtk executable name inside the build directory', 0),
37     EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'none' ), ignorecase=2),
38     BoolOption('FPU_OPTIMIZATION', 'Build runtime checked assembler code', 1),
39     BoolOption('FFT_ANALYSIS', 'Include FFT analysis window', 0),
40     BoolOption('SURFACES', 'Build support for control surfaces', 0),
41     BoolOption('DMALLOC', 'Compile and link using the dmalloc library', 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
386 libraries['gtk2'] = LibraryInfo()
387 libraries['gtk2'].ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
388
389 libraries['pango'] = LibraryInfo()
390 libraries['pango'].ParseConfig ('pkg-config --cflags --libs pango')
391
392 libraries['libgnomecanvas2'] = LibraryInfo()
393 libraries['libgnomecanvas2'].ParseConfig ('pkg-config --cflags --libs libgnomecanvas-2.0')
394
395 #libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
396
397 # The Ardour Control Protocol Library
398
399 libraries['ardour_cp'] = LibraryInfo (LIBS='ardour_cp', LIBPATH='#libs/surfaces/control_protocol',
400                                       CPPPATH='#libs/surfaces/control_protocol')
401
402 # The Ardour backend/engine
403
404 libraries['ardour'] = LibraryInfo (LIBS='ardour', LIBPATH='#libs/ardour', CPPPATH='#libs/ardour')
405 libraries['midi++2'] = LibraryInfo (LIBS='midi++', LIBPATH='#libs/midi++2', CPPPATH='#libs/midi++2')
406 libraries['pbd3']    = LibraryInfo (LIBS='pbd', LIBPATH='#libs/pbd3', CPPPATH='#libs/pbd3')
407 libraries['gtkmm2ext'] = LibraryInfo (LIBS='gtkmm2ext', LIBPATH='#libs/gtkmm2ext', CPPPATH='#libs/gtkmm2ext')
408 #libraries['cassowary'] = LibraryInfo(LIBS='cassowary', LIBPATH='#libs/cassowary', CPPPATH='#libs/cassowary')
409
410 libraries['fst'] = LibraryInfo()
411 if env['VST']:
412     libraries['fst'].ParseConfig('pkg-config --cflags --libs libfst')
413
414 #
415 # Check for libusb
416
417 libraries['usb'] = LibraryInfo ()
418
419 conf = Configure (libraries['usb'])
420 if conf.CheckLib ('usb', 'usb_interrupt_write'):
421     have_libusb = True
422 else:
423     have_libusb = False
424     
425 libraries['usb'] = conf.Finish ()
426
427 #
428 # Check for liblo
429
430 libraries['lo'] = LibraryInfo ()
431
432 conf = Configure (libraries['lo'])
433 if conf.CheckLib ('lo', 'lo_server_new') == False:
434     print "liblo does not appear to be installed."
435     exit (0)
436     
437 libraries['lo'] = conf.Finish ()
438
439 #
440 # Check for dmalloc
441
442 libraries['dmalloc'] = LibraryInfo ()
443
444 #
445 # look for the threaded version
446 #
447
448 conf = Configure (libraries['dmalloc'])
449 if conf.CheckLib ('dmallocth', 'dmalloc_shutdown'):
450     have_libdmalloc = True
451 else:
452     have_libdmalloc = False
453     
454 libraries['dmalloc'] = conf.Finish ()
455
456 #
457
458 #
459 # Audio/MIDI library (needed for MIDI, since audio is all handled via JACK)
460
461
462 conf = Configure(env)
463
464 if conf.CheckCHeader('jack/midiport.h'):
465     libraries['sysmidi'] = LibraryInfo (LIBS='jack')
466     env['SYSMIDI'] = 'JACK MIDI'
467     subst_dict['%MIDITAG%'] = "control"
468     subst_dict['%MIDITYPE%'] = "jack"
469 elif conf.CheckCHeader('alsa/asoundlib.h'):
470     libraries['sysmidi'] = LibraryInfo (LIBS='asound')
471     env['SYSMIDI'] = 'ALSA Sequencer'
472     subst_dict['%MIDITAG%'] = "seq"
473     subst_dict['%MIDITYPE%'] = "alsa/sequencer"
474 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
475     # this line is needed because scons can't handle -framework in ParseConfig() yet.
476     libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
477     env['SYSMIDI'] = 'CoreMIDI'
478     subst_dict['%MIDITAG%'] = "ardour"
479     subst_dict['%MIDITYPE%'] = "coremidi"
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 libSoundTouch')
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['libglademm'] = LibraryInfo(LIBS='libglademm',
550 #                                          LIBPATH='#libs/libglademm',
551 #                                          CPPPATH='#libs/libglademm')
552
553     coredirs = [
554         'libs/soundtouch',
555         'templates'
556     ]
557
558     subdirs = [
559 #           'libs/cassowary',
560         'libs/sigc++2',
561         'libs/pbd3',
562         'libs/midi++2',
563         'libs/ardour'
564         ]
565
566     gtk_subdirs = [
567         'libs/glibmm2',
568         'libs/gtkmm2/pango',
569         'libs/gtkmm2/atk',
570         'libs/gtkmm2/gdk',
571         'libs/gtkmm2/gtk',
572         'libs/libgnomecanvasmm',
573 #       'libs/flowcanvas',
574     'libs/gtkmm2ext',
575     'gtk2_ardour'
576         ]
577
578 #
579 # always build the LGPL control protocol lib, since we link against it ourselves
580 # ditto for generic MIDI
581 #
582
583 surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi' ]
584
585 if env['SURFACES']:
586     if have_libusb:
587         surface_subdirs += [ 'libs/surfaces/tranzport' ]
588     if os.access ('libs/surfaces/sony9pin', os.F_OK):
589         surface_subdirs += [ 'libs/surfaces/sony9pin' ]
590     
591 opts.Save('scache.conf', env)
592 Help(opts.GenerateHelpText(env))
593
594 if os.environ.has_key('PATH'):
595     env.Append(PATH = os.environ['PATH'])
596
597 if os.environ.has_key('TERM'):
598     env.Append(PATH = os.environ['TERM'])
599
600 if os.environ.has_key('HOME'):
601     env.Append(HOME = os.environ['HOME'])
602
603 if os.environ.has_key('PKG_CONFIG_PATH'):
604     env.Append(PKG_CONFIG_PATH = os.environ['PKG_CONFIG_PATH'])
605
606 if os.environ.has_key('CC'):
607     env['CC'] = os.environ['CC']
608
609 if os.environ.has_key('CXX'):
610     env['CXX'] = os.environ['CXX']
611
612 if os.environ.has_key('DISTCC_HOSTS'):
613     env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
614     env['ENV']['HOME'] = os.environ['HOME']
615     
616 final_prefix = '$PREFIX'
617 install_prefix = '$DESTDIR/$PREFIX'
618
619 subst_dict['INSTALL_PREFIX'] = install_prefix;
620
621 if env['PREFIX'] == '/usr':
622     final_config_prefix = '/etc'
623 else:
624     final_config_prefix = env['PREFIX'] + '/etc'
625
626 config_prefix = '$DESTDIR' + final_config_prefix
627
628
629 # SCons should really do this for us
630
631 conf = Configure (env)
632
633 have_cxx = conf.TryAction (Action (env['CXX'] + ' --version'))
634 if have_cxx[0] != 1:
635     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
636     exit (1)
637 else:
638     print "Congratulations, you have a functioning C++ compiler."
639     
640 env = conf.Finish()
641
642 #
643 # Compiler flags and other system-dependent stuff
644 #
645
646 opt_flags = []
647 debug_flags = [ '-g' ]
648
649 # guess at the platform, used to define compiler flags
650
651 config_guess = os.popen("tools/config.guess").read()[:-1]
652
653 config_cpu = 0
654 config_arch = 1
655 config_kernel = 2
656 config_os = 3
657 config = config_guess.split ("-")
658
659 print "system triple: " + config_guess
660
661 # Autodetect
662 if env['DIST_TARGET'] == 'auto':
663     if config[config_arch] == 'apple':
664         # The [.] matches to the dot after the major version, "." would match any character
665         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
666             env['DIST_TARGET'] = 'panther'
667         else:
668             env['DIST_TARGET'] = 'tiger'
669     else:
670         if re.search ("x86_64", config[config_cpu]) != None:
671             env['DIST_TARGET'] = 'x86_64'
672         elif re.search("i[0-5]86", config[config_cpu]) != None:
673             env['DIST_TARGET'] = 'i386'
674         elif re.search("powerpc", config[config_cpu]) != None:
675             env['DIST_TARGET'] = 'powerpc'
676         else:
677             env['DIST_TARGET'] = 'i686'
678     print "\n*******************************"
679     print "detected DIST_TARGET = " + env['DIST_TARGET']
680     print "*******************************\n"
681
682
683 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
684     #
685     # Apple/PowerPC optimization options
686     #
687     # -mcpu=7450 does not reliably work with gcc 3.*
688     #
689     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
690         if config[config_arch] == 'apple':
691             opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
692         else:
693             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"]) 
694     else:
695         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
696     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
697
698 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':
699
700     build_host_supports_sse = 0
701     
702     debug_flags.append ("-DARCH_X86")
703     opt_flags.append ("-DARCH_X86")
704
705     if config[config_kernel] == 'linux' :
706
707         if env['DIST_TARGET'] != 'i386': 
708
709             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
710             x86_flags = flag_line.split (": ")[1:][0].split (' ')
711
712             if "mmx" in x86_flags:
713                 opt_flags.append ("-mmmx")
714             if "sse" in x86_flags:
715                 build_host_supports_sse = 1
716             if "3dnow" in x86_flags:
717                 opt_flags.append ("-m3dnow")
718
719             if config[config_cpu] == "i586":
720                 opt_flags.append ("-march=i586")
721             elif config[config_cpu] == "i686":
722                 opt_flags.append ("-march=i686")
723
724     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
725         opt_flags.extend (["-msse", "-mfpmath=sse"])
726         debug_flags.extend (["-msse", "-mfpmath=sse"])
727 # end of processor-specific section
728
729 # optimization section
730 if env['FPU_OPTIMIZATION']:
731     if env['DIST_TARGET'] == 'tiger':
732         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
733         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
734         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
735     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
736         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
737         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
738         if env['DIST_TARGET'] == 'x86_64':
739             opt_flags.append ("-DUSE_X86_64_ASM")
740             debug_flags.append ("-DUSE_X86_64_ASM")
741         if build_host_supports_sse != 1:
742             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)"
743 # end optimization section
744
745 #
746 # ARCH="..." overrides all 
747 #
748
749 if env['ARCH'] != '':
750     opt_flags = env['ARCH'].split()
751
752 #
753 # prepend boiler plate optimization flags
754 #
755
756 opt_flags[:0] = [
757     "-O3",
758     "-fomit-frame-pointer",
759     "-ffast-math",
760     "-fstrength-reduce"
761     ]
762
763 if env['DEBUG'] == 1:
764     env.Append(CCFLAGS=" ".join (debug_flags))
765 else:
766     env.Append(CCFLAGS=" ".join (opt_flags))
767
768 env.Append(CCFLAGS="-Wall")
769
770 if env['VST']:
771     env.Append(CCFLAGS="-DVST_SUPPORT")
772
773 #
774 # everybody needs this
775 #
776
777 env.Merge ([ libraries['core'] ])
778
779 #
780 # i18n support 
781 #
782
783 conf = Configure (env)
784
785 if env['NLS']:
786     print 'Checking for internationalization support ...'
787     have_gettext = conf.TryAction(Action('xgettext --version'))
788     if have_gettext[0] != 1:
789         print 'This system is not configured for internationalized applications (no xgettext command). An english-only version will be built\n'
790         env['NLS'] = 0
791         
792     if conf.CheckCHeader('libintl.h') == None:
793         print 'This system is not configured for internationalized applications (no libintl.h). An english-only version will be built\n'
794         env['NLS'] = 0
795
796
797 env = conf.Finish()
798
799 if env['NLS'] == 1:
800     env.Append(CCFLAGS="-DENABLE_NLS")
801
802
803 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n version subst_dict')
804
805 #
806 # the configuration file may be system dependent
807 #
808
809 conf = env.Configure ()
810
811 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
812     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
813     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
814 else:
815     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
816     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
817
818 # posix_memalign available
819 if not conf.CheckFunc('posix_memalign'):
820     print 'Did not find posix_memalign(), using malloc'
821     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
822
823
824 env = conf.Finish()
825
826 rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
827
828 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
829 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.rc'))
830
831 Default (rcbuild)
832
833 # source tarball
834
835 Precious (env['DISTTREE'])
836
837 #
838 # note the special "cleanfirst" source name. this triggers removal
839 # of the existing disttree
840 #
841
842 env.Distribute (env['DISTTREE'],
843                 [ 'SConstruct',
844                   'COPYING', 'PACKAGER_README', 'README',
845                   'ardour.rc.in',
846                   'ardour_system.rc',
847                   'tools/config.guess'
848                   ] +
849                 glob.glob ('DOCUMENTATION/AUTHORS*') +
850                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
851                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
852                 glob.glob ('DOCUMENTATION/BUILD*') +
853                 glob.glob ('DOCUMENTATION/FAQ*') +
854                 glob.glob ('DOCUMENTATION/README*')
855                 )
856                 
857 srcdist = env.Tarball(env['TARBALL'], env['DISTTREE'])
858 env.Alias ('srctar', srcdist)
859 #
860 # don't leave the distree around 
861 #
862 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
863 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
864
865 #
866 # the subdirs
867
868
869 for subdir in coredirs:
870     SConscript (subdir + '/SConscript')
871
872 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
873     for subdir in sublistdir:
874         SConscript (subdir + '/SConscript')
875
876 #pickle.dump(env, open('.scons_env', 'w'), pickle.HIGHEST_PROTOCOL)
877
878 # cleanup
879 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
880