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