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