new svn_revision.h build system, plus no more SMPTE, just Timecode
[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 import string
12 import commands
13 from sets import Set
14 import SCons.Node.FS
15
16 SConsignFile()
17 EnsureSConsVersion(0, 96)
18
19 version = '2.0beta8'
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('AUDIOUNITS', 'Compile with Apple\'s AudioUnit library. (experimental)', 0),
31     BoolOption('COREAUDIO', 'Compile with Apple\'s CoreAudio library', 0),
32     BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 0),
33     PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'),
34     EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'none' ), ignorecase=2),
35     BoolOption('DMALLOC', 'Compile and link using the dmalloc library', 0),
36     BoolOption('EXTRA_WARN', 'Compile with -Wextra, -ansi, and -pedantic.  Might break compilation.  For pedants', 0),
37     BoolOption('FFT_ANALYSIS', 'Include FFT analysis window', 0),
38     BoolOption('FPU_OPTIMIZATION', 'Build runtime checked assembler code', 1),
39     BoolOption('LIBLO', 'Compile with support for liblo library', 1),
40     BoolOption('NLS', 'Set to turn on i18n support', 1),
41     PathOption('PREFIX', 'Set the install "prefix"', '/usr/local'),
42     BoolOption('SURFACES', 'Build support for control surfaces', 0),
43     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),
44     BoolOption('VERSIONED', 'Add revision information to ardour/gtk executable name inside the build directory', 0),
45     BoolOption('VST', 'Compile with support for VST', 0)
46 )
47
48 #----------------------------------------------------------------------
49 # a handy helper that provides a way to merge compile/link information
50 # from multiple different "environments"
51 #----------------------------------------------------------------------
52 #
53 class LibraryInfo(Environment):
54     def __init__(self,*args,**kw):
55         Environment.__init__ (self,*args,**kw)
56     
57     def Merge (self,others):
58         for other in others:
59             self.Append (LIBS = other.get ('LIBS',[]))
60             self.Append (LIBPATH = other.get ('LIBPATH', []))
61             self.Append (CPPPATH = other.get('CPPPATH', []))
62             self.Append (LINKFLAGS = other.get('LINKFLAGS', []))
63         self.Replace(LIBPATH = list(Set(self.get('LIBPATH', []))))
64         self.Replace(CPPPATH = list(Set(self.get('CPPPATH',[]))))
65         #doing LINKFLAGS breaks -framework
66         #doing LIBS break link order dependency
67     
68     def ENV_update(self, src_ENV):
69         for k in src_ENV.keys():
70             if k in self['ENV'].keys() and k in [ 'PATH', 'LD_LIBRARY_PATH',
71                                                   'LIB', 'INCLUDE' ]:
72                 self['ENV'][k]=SCons.Util.AppendPath(self['ENV'][k], src_ENV[k])
73             else:
74                 self['ENV'][k]=src_ENV[k]
75
76 env = LibraryInfo (options = opts,
77                    CPPPATH = [ '.' ],
78                    VERSION = version,
79                    TARBALL='ardour-' + version + '.tar.bz2',
80                    DISTFILES = [ ],
81                    DISTTREE  = '#ardour-' + version,
82                    DISTCHECKDIR = '#ardour-' + version + '/check'
83                    )
84
85 env.ENV_update(os.environ)
86
87 #----------------------------------------------------------------------
88 # Builders
89 #----------------------------------------------------------------------
90
91 # Handy subst-in-file builder
92 #
93
94 def do_subst_in_file(targetfile, sourcefile, dict):
95     """Replace all instances of the keys of dict with their values.
96     For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'},
97     then all instances of %VERSION% in the file will be replaced with 1.2345 etc.
98     """
99     try:
100         f = open(sourcefile, 'rb')
101         contents = f.read()
102         f.close()
103     except:
104         raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile
105     for (k,v) in dict.items():
106         contents = re.sub(k, v, contents)
107     try:
108         f = open(targetfile, 'wb')
109         f.write(contents)
110         f.close()
111     except:
112         raise SCons.Errors.UserError, "Can't write target file %s"%targetfile
113     return 0 # success
114
115 def subst_in_file(target, source, env):
116     if not env.has_key('SUBST_DICT'):
117         raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set."
118     d = dict(env['SUBST_DICT']) # copy it
119     for (k,v) in d.items():
120         if callable(v):
121             d[k] = env.subst(v())
122         elif SCons.Util.is_String(v):
123             d[k]=env.subst(v)
124         else:
125             raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))
126     for (t,s) in zip(target, source):
127         return do_subst_in_file(str(t), str(s), d)
128
129 def subst_in_file_string(target, source, env):
130     """This is what gets printed on the console."""
131     return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t))
132                       for (t,s) in zip(target, source)])
133
134 def subst_emitter(target, source, env):
135     """Add dependency from substituted SUBST_DICT to target.
136     Returns original target, source tuple unchanged.
137     """
138     d = env['SUBST_DICT'].copy() # copy it
139     for (k,v) in d.items():
140         if callable(v):
141             d[k] = env.subst(v())
142         elif SCons.Util.is_String(v):
143             d[k]=env.subst(v)
144     Depends(target, SCons.Node.Python.Value(d))
145     # Depends(target, source) # this doesn't help the install-sapphire-linux.sh problem
146     return target, source
147
148 subst_action = Action (subst_in_file, subst_in_file_string)
149 env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter)
150
151 #
152 # internationalization
153 #
154
155 # po_builder: builder function to copy po files to the parent directory while updating them
156 #
157 # first source:  .po file
158 # second source: .pot file
159 #
160
161 def po_builder(target,source,env):
162     os.spawnvp (os.P_WAIT, 'cp', ['cp', str(source[0]), str(target[0])])
163     args = [ 'msgmerge',
164              '--update',
165              str(target[0]),
166              str(source[1])
167              ]
168     print 'Updating ' + str(target[0])
169     return os.spawnvp (os.P_WAIT, 'msgmerge', args)
170
171 po_bld = Builder (action = po_builder)
172 env.Append(BUILDERS = {'PoBuild' : po_bld})
173
174 # mo_builder: builder function for (binary) message catalogs (.mo)
175 #
176 # first source:  .po file
177 #
178
179 def mo_builder(target,source,env):
180     args = [ 'msgfmt',
181              '-c',
182              '-o',
183              target[0].get_path(),
184              source[0].get_path()
185              ]
186     return os.spawnvp (os.P_WAIT, 'msgfmt', args)
187
188 mo_bld = Builder (action = mo_builder)
189 env.Append(BUILDERS = {'MoBuild' : mo_bld})
190
191 # pot_builder: builder function for message templates (.pot)
192 #
193 # source: list of C/C++ etc. files to extract messages from
194 #
195
196 def pot_builder(target,source,env):
197     args = [ 'xgettext',
198              '--keyword=_',
199              '--keyword=N_',
200              '--from-code=UTF-8',
201              '-o', target[0].get_path(),
202              "--default-domain=" + env['PACKAGE'],
203              '--copyright-holder="Paul Davis"' ]
204     args += [ src.get_path() for src in source ]
205     
206     return os.spawnvp (os.P_WAIT, 'xgettext', args)
207
208 pot_bld = Builder (action = pot_builder)
209 env.Append(BUILDERS = {'PotBuild' : pot_bld})
210
211 #
212 # utility function, not a builder
213 #
214
215 def i18n (buildenv, sources, installenv):
216     domain = buildenv['PACKAGE']
217     potfile = buildenv['POTFILE']
218     
219     installenv.Alias ('potupdate', buildenv.PotBuild (potfile, sources))
220     
221     p_oze = [ os.path.basename (po) for po in glob.glob ('po/*.po') ]
222     languages = [ po.replace ('.po', '') for po in p_oze ]
223     
224     for po_file in p_oze:
225         buildenv.PoBuild(po_file, ['po/'+po_file, potfile])
226         mo_file = po_file.replace (".po", ".mo")
227         installenv.Alias ('install', buildenv.MoBuild (mo_file, po_file))
228     
229     for lang in languages:
230         modir = (os.path.join (install_prefix, 'share/locale/' + lang + '/LC_MESSAGES/'))
231         moname = domain + '.mo'
232         installenv.Alias('install', installenv.InstallAs (os.path.join (modir, moname), lang + '.mo'))
233
234
235 def fetch_svn_revision (path):
236     cmd = "svn info "
237     cmd += path
238     cmd += " | awk '/^Revision:/ { print $2}'"
239     return commands.getoutput (cmd)
240
241 def recreate_stored_revision(target = None, source = None, env = None):
242     os.unlink ('svn_revision.h')
243     print "===========> Forcing recreation of svn_revision.h"
244     create_stored_revision ()
245     
246 def create_stored_revision(target = None, source = None, env = None):
247     if os.path.exists('.svn'):    
248         rev = fetch_svn_revision ('.');
249         try:
250             text  = "#ifndef __ardour_svn_revision_h__\n"
251             text += "#define __ardour_svn_revision_h__\n"
252             text += "static const char* ardour_svn_revision = \"" + rev + "\";\n";
253             text += "#endif\n"
254             print '============> writing svn revision info to svn_revision.h\n'
255             o = file ('svn_revision.h', 'w')
256             o.write (text)
257             o.close ()
258         except IOError:
259             print "Could not open svn_revision.h for writing\n"
260             sys.exit (-1)
261     else:
262         if os.path.exists ('svn_revision.h') == False:
263             print "\n\nYou are missing svn_revision.h, which should have been included."
264             print "This is caused either by a packaging error, "
265             print "     or a configuration error with your system."
266             print "Please report this issue to the ardour-dev mailing list."
267             print "(See http://ardour.org/support for details)\n\n"
268             sys.exit (-1)
269
270 #
271 # if it exists, do not remove it
272 #
273
274 Precious('svn_revision.h')
275     
276 #
277 # A generic builder for version.cc files
278 #
279 # note: requires that DOMAIN, MAJOR, MINOR, MICRO are set in the construction environment
280 # note: assumes one source files, the header that declares the version variables
281 #
282
283 def version_builder (target, source, env):
284
285     text  = "int " + env['DOMAIN'] + "_major_version = " + str (env['MAJOR']) + ";\n"
286     text += "int " + env['DOMAIN'] + "_minor_version = " + str (env['MINOR']) + ";\n"
287     text += "int " + env['DOMAIN'] + "_micro_version = " + str (env['MICRO']) + ";\n"
288     
289     try:
290         o = file (target[0].get_path(), 'w')
291         o.write (text)
292         o.close ()
293     except IOError:
294         print "Could not open", target[0].get_path(), " for writing\n"
295         sys.exit (-1)
296
297     text  = "#ifndef __" + env['DOMAIN'] + "_version_h__\n"
298     text += "#define __" + env['DOMAIN'] + "_version_h__\n"
299     text += "extern const char* " + env['DOMAIN'] + "_revision;\n"
300     text += "extern int " + env['DOMAIN'] + "_major_version;\n"
301     text += "extern int " + env['DOMAIN'] + "_minor_version;\n"
302     text += "extern int " + env['DOMAIN'] + "_micro_version;\n"
303     text += "#endif /* __" + env['DOMAIN'] + "_version_h__ */\n"
304     
305     try:
306         o = file (target[1].get_path(), 'w')
307         o.write (text)
308         o.close ()
309     except IOError:
310         print "Could not open", target[1].get_path(), " for writing\n"
311         sys.exit (-1)
312         
313     return None
314
315 version_bld = Builder (action = version_builder)
316 env.Append (BUILDERS = {'VersionBuild' : version_bld})
317
318 #
319 # a builder that makes a hard link from the 'source' executable to a name with
320 # a "build ID" based on the most recent CVS activity that might be reasonably
321 # related to version activity. this relies on the idea that the SConscript
322 # file that builds the executable is updated with new version info and committed
323 # to the source code repository whenever things change.
324 #
325
326 def versioned_builder(target,source,env):
327     w, r = os.popen2( "svn info | awk '/^Revision:/ { print $2}'")
328     
329     last_revision = r.readline().strip()
330     w.close()
331     r.close()
332     if last_revision == "":
333         print "No SVN info found - versioned executable cannot be built"
334         return -1
335     
336     print "The current build ID is " + last_revision
337     
338     tagged_executable = source[0].get_path() + '-' + last_revision
339     
340     if os.path.exists (tagged_executable):
341         print "Replacing existing executable with the same build tag."
342         os.unlink (tagged_executable)
343     
344     return os.link (source[0].get_path(), tagged_executable)
345
346 verbuild = Builder (action = versioned_builder)
347 env.Append (BUILDERS = {'VersionedExecutable' : verbuild})
348
349 #
350 # source tar file builder
351 #
352
353 def distcopy (target, source, env):
354     treedir = str (target[0])
355     
356     try:
357         os.mkdir (treedir)
358     except OSError, (errnum, strerror):
359         if errnum != errno.EEXIST:
360             print 'mkdir ', treedir, ':', strerror
361     
362     cmd = 'tar cf - '
363     #
364     # we don't know what characters might be in the file names
365     # so quote them all before passing them to the shell
366     #
367     all_files = ([ str(s) for s in source ])
368     cmd += " ".join ([ "'%s'" % quoted for quoted in all_files])
369     cmd += ' | (cd ' + treedir + ' && tar xf -)'
370     p = os.popen (cmd)
371     return p.close ()
372
373 def tarballer (target, source, env):
374     cmd = 'tar -jcf ' + str (target[0]) +  ' ' + str(source[0]) + "  --exclude '*~'"
375     print 'running ', cmd, ' ... '
376     p = os.popen (cmd)
377     return p.close ()
378
379 dist_bld = Builder (action = distcopy,
380                     target_factory = SCons.Node.FS.default_fs.Entry,
381                     source_factory = SCons.Node.FS.default_fs.Entry,
382                     multi = 1)
383
384 tarball_bld = Builder (action = tarballer,
385                        target_factory = SCons.Node.FS.default_fs.Entry,
386                        source_factory = SCons.Node.FS.default_fs.Entry)
387
388 env.Append (BUILDERS = {'Distribute' : dist_bld})
389 env.Append (BUILDERS = {'Tarball' : tarball_bld})
390
391 #
392 # Make sure they know what they are doing
393 #
394
395 if env['VST']:
396     sys.stdout.write ("Are you building Ardour for personal use (rather than distributiont to others)? [no]: ")
397     answer = sys.stdin.readline ()
398     answer = answer.rstrip().strip()
399     if answer != "yes" and answer != "y":
400         print 'You cannot build Ardour with VST support for distribution to others.\nIt is a violation of several different licenses. Build with VST=false.'
401         sys.exit (-1);
402     else:
403         print "OK, VST support will be enabled"
404
405
406 # ----------------------------------------------------------------------
407 # Construction environment setup
408 # ----------------------------------------------------------------------
409
410 libraries = { }
411
412 libraries['core'] = LibraryInfo (CCFLAGS = '-Ilibs')
413
414 #libraries['sndfile'] = LibraryInfo()
415 #libraries['sndfile'].ParseConfig('pkg-config --cflags --libs sndfile')
416
417 libraries['lrdf'] = LibraryInfo()
418 libraries['lrdf'].ParseConfig('pkg-config --cflags --libs lrdf')
419
420 libraries['raptor'] = LibraryInfo()
421 libraries['raptor'].ParseConfig('pkg-config --cflags --libs raptor')
422
423 libraries['samplerate'] = LibraryInfo()
424 libraries['samplerate'].ParseConfig('pkg-config --cflags --libs samplerate')
425
426 if env['FFT_ANALYSIS']:
427         libraries['fftw3f'] = LibraryInfo()
428         libraries['fftw3f'].ParseConfig('pkg-config --cflags --libs fftw3f')
429
430 libraries['jack'] = LibraryInfo()
431 libraries['jack'].ParseConfig('pkg-config --cflags --libs jack')
432
433 libraries['xml'] = LibraryInfo()
434 libraries['xml'].ParseConfig('pkg-config --cflags --libs libxml-2.0')
435
436 libraries['xslt'] = LibraryInfo()
437 libraries['xslt'].ParseConfig('pkg-config --cflags --libs libxslt')
438
439 libraries['glib2'] = LibraryInfo()
440 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs glib-2.0')
441 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gobject-2.0')
442 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gmodule-2.0')
443 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gthread-2.0')
444
445 libraries['gtk2'] = LibraryInfo()
446 libraries['gtk2'].ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
447
448 libraries['pango'] = LibraryInfo()
449 libraries['pango'].ParseConfig ('pkg-config --cflags --libs pango')
450
451 libraries['libgnomecanvas2'] = LibraryInfo()
452 libraries['libgnomecanvas2'].ParseConfig ('pkg-config --cflags --libs libgnomecanvas-2.0')
453
454 #libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
455
456 # The Ardour Control Protocol Library
457
458 libraries['ardour_cp'] = LibraryInfo (LIBS='ardour_cp', LIBPATH='#libs/surfaces/control_protocol',
459                                       CPPPATH='#libs/surfaces/control_protocol')
460
461 # The Ardour backend/engine
462
463 libraries['ardour'] = LibraryInfo (LIBS='ardour', LIBPATH='#libs/ardour', CPPPATH='#libs/ardour')
464 libraries['midi++2'] = LibraryInfo (LIBS='midi++', LIBPATH='#libs/midi++2', CPPPATH='#libs/midi++2')
465 libraries['pbd']    = LibraryInfo (LIBS='pbd', LIBPATH='#libs/pbd', CPPPATH='#libs/pbd')
466 libraries['gtkmm2ext'] = LibraryInfo (LIBS='gtkmm2ext', LIBPATH='#libs/gtkmm2ext', CPPPATH='#libs/gtkmm2ext')
467
468 #
469 # Check for libusb
470
471 libraries['usb'] = LibraryInfo ()
472
473 conf = Configure (libraries['usb'])
474 if conf.CheckLib ('usb', 'usb_interrupt_write'):
475     have_libusb = True
476 else:
477     have_libusb = False
478
479 libraries['usb'] = conf.Finish ()
480
481 #
482 # Check for FLAC
483
484 libraries['flac'] = LibraryInfo ()
485
486 conf = Configure (libraries['flac'])
487 conf.CheckLib ('FLAC', 'FLAC__stream_decoder_new', language='CXX')
488 libraries['flac'] = conf.Finish ()
489
490 # or if that fails...
491 #libraries['flac']    = LibraryInfo (LIBS='FLAC')
492
493 # boost (we don't link against boost, just use some header files)
494
495 libraries['boost'] = LibraryInfo ()
496 conf = Configure (libraries['boost'])
497 if conf.CheckHeader ('boost/shared_ptr.hpp', language='CXX') == False:
498         print "Boost header files do not appear to be installed."
499         sys.exit (1)
500     
501 libraries['boost'] = conf.Finish ()
502
503 #
504 # Check for liblo
505
506 if env['LIBLO']:
507     libraries['lo'] = LibraryInfo ()
508     
509     conf = Configure (libraries['lo'])
510     if conf.CheckLib ('lo', 'lo_server_new') == False:
511         print "liblo does not appear to be installed."
512         sys.exit (1)
513     
514     libraries['lo'] = conf.Finish ()
515
516 #
517 # Check for dmalloc
518
519 libraries['dmalloc'] = LibraryInfo ()
520
521 #
522 # look for the threaded version
523 #
524
525 conf = Configure (libraries['dmalloc'])
526 if conf.CheckLib ('dmallocth', 'dmalloc_shutdown'):
527     have_libdmalloc = True
528 else:
529     have_libdmalloc = False
530
531 libraries['dmalloc'] = conf.Finish ()
532
533 #
534 # Audio/MIDI library (needed for MIDI, since audio is all handled via JACK)
535 #
536
537 conf = Configure(env)
538
539 if conf.CheckCHeader('alsa/asoundlib.h'):
540     libraries['sysmidi'] = LibraryInfo (LIBS='asound')
541     env['SYSMIDI'] = 'ALSA Sequencer'
542     subst_dict['%MIDITAG%'] = "seq"
543     subst_dict['%MIDITYPE%'] = "alsa/sequencer"
544 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
545     # this line is needed because scons can't handle -framework in ParseConfig() yet.
546     libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
547     env['SYSMIDI'] = 'CoreMIDI'
548     subst_dict['%MIDITAG%'] = "ardour"
549     subst_dict['%MIDITYPE%'] = "coremidi"
550 else:
551     print "It appears you don't have the required MIDI libraries installed. For Linux this means you are missing the development package for ALSA libraries."
552     sys.exit (1)
553
554 env = conf.Finish()
555
556 if env['SYSLIBS']:
557     
558     libraries['sigc2'] = LibraryInfo()
559     libraries['sigc2'].ParseConfig('pkg-config --cflags --libs sigc++-2.0')
560     libraries['glibmm2'] = LibraryInfo()
561     libraries['glibmm2'].ParseConfig('pkg-config --cflags --libs glibmm-2.4')
562     libraries['gdkmm2'] = LibraryInfo()
563     libraries['gdkmm2'].ParseConfig ('pkg-config --cflags --libs gdkmm-2.4')
564     libraries['gtkmm2'] = LibraryInfo()
565     libraries['gtkmm2'].ParseConfig ('pkg-config --cflags --libs gtkmm-2.4')
566     libraries['atkmm'] = LibraryInfo()
567     libraries['atkmm'].ParseConfig ('pkg-config --cflags --libs atkmm-1.6')
568     libraries['pangomm'] = LibraryInfo()
569     libraries['pangomm'].ParseConfig ('pkg-config --cflags --libs pangomm-1.4')
570     libraries['libgnomecanvasmm'] = LibraryInfo()
571     libraries['libgnomecanvasmm'].ParseConfig ('pkg-config --cflags --libs libgnomecanvasmm-2.6')
572
573 #
574 # cannot use system one for the time being
575 #
576     
577     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
578                                     LIBPATH='#libs/libsndfile',
579                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
580
581 #    libraries['libglademm'] = LibraryInfo()
582 #    libraries['libglademm'].ParseConfig ('pkg-config --cflags --libs libglademm-2.4')
583
584 #    libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
585     libraries['soundtouch'] = LibraryInfo()
586     libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs soundtouch-1.0')
587
588     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
589                                             LIBPATH='#libs/appleutility',
590                                             CPPPATH='#libs/appleutility')
591     
592     coredirs = [
593         'templates'
594     ]
595     
596     subdirs = [
597         'libs/libsndfile',
598         'libs/pbd',
599         'libs/midi++2',
600         'libs/ardour',
601     # these are unconditionally included but have
602     # tests internally to avoid compilation etc
603     # if VST is not set
604         'libs/fst',
605         'vst',
606     # this is unconditionally included but has
607     # tests internally to avoid compilation etc
608     # if COREAUDIO is not set
609         'libs/appleutility'
610         ]
611     
612     gtk_subdirs = [
613 #        'libs/flowcanvas',
614         'libs/gtkmm2ext',
615         'gtk2_ardour'
616         ]
617
618 else:
619     libraries['sigc2'] = LibraryInfo(LIBS='sigc++2',
620                                     LIBPATH='#libs/sigc++2',
621                                     CPPPATH='#libs/sigc++2')
622     libraries['glibmm2'] = LibraryInfo(LIBS='glibmm2',
623                                     LIBPATH='#libs/glibmm2',
624                                     CPPPATH='#libs/glibmm2')
625     libraries['pangomm'] = LibraryInfo(LIBS='pangomm',
626                                     LIBPATH='#libs/gtkmm2/pango',
627                                     CPPPATH='#libs/gtkmm2/pango')
628     libraries['atkmm'] = LibraryInfo(LIBS='atkmm',
629                                      LIBPATH='#libs/gtkmm2/atk',
630                                      CPPPATH='#libs/gtkmm2/atk')
631     libraries['gdkmm2'] = LibraryInfo(LIBS='gdkmm2',
632                                       LIBPATH='#libs/gtkmm2/gdk',
633                                       CPPPATH='#libs/gtkmm2/gdk')
634     libraries['gtkmm2'] = LibraryInfo(LIBS='gtkmm2',
635                                      LIBPATH="#libs/gtkmm2/gtk",
636                                      CPPPATH='#libs/gtkmm2/gtk/')
637     libraries['libgnomecanvasmm'] = LibraryInfo(LIBS='libgnomecanvasmm',
638                                                 LIBPATH='#libs/libgnomecanvasmm',
639                                                 CPPPATH='#libs/libgnomecanvasmm')
640     
641     libraries['soundtouch'] = LibraryInfo(LIBS='soundtouch',
642                                           LIBPATH='#libs/soundtouch',
643                                           CPPPATH=['#libs', '#libs/soundtouch'])
644     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
645                                     LIBPATH='#libs/libsndfile',
646                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
647 #    libraries['libglademm'] = LibraryInfo(LIBS='libglademm',
648 #                                          LIBPATH='#libs/libglademm',
649 #                                          CPPPATH='#libs/libglademm')
650     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
651                                             LIBPATH='#libs/appleutility',
652                                             CPPPATH='#libs/appleutility')
653
654     coredirs = [
655         'libs/soundtouch',
656         'templates'
657     ]
658     
659     subdirs = [
660         'libs/sigc++2',
661         'libs/libsndfile',
662         'libs/pbd',
663         'libs/midi++2',
664         'libs/ardour',
665     # these are unconditionally included but have
666     # tests internally to avoid compilation etc
667     # if VST is not set
668         'libs/fst',
669         'vst',
670     # this is unconditionally included but has
671     # tests internally to avoid compilation etc
672     # if COREAUDIO is not set
673         'libs/appleutility'
674         ]
675     
676     gtk_subdirs = [
677         'libs/glibmm2',
678         'libs/gtkmm2/pango',
679         'libs/gtkmm2/atk',
680         'libs/gtkmm2/gdk',
681         'libs/gtkmm2/gtk',
682         'libs/libgnomecanvasmm',
683 #       'libs/flowcanvas',
684     'libs/gtkmm2ext',
685     'gtk2_ardour'
686         ]
687
688 #
689 # always build the LGPL control protocol lib, since we link against it ourselves
690 # ditto for generic MIDI
691 #
692
693 surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi' ]
694
695 if env['SURFACES']:
696     if have_libusb:
697         surface_subdirs += [ 'libs/surfaces/tranzport' ]
698     if os.access ('libs/surfaces/sony9pin', os.F_OK):
699         surface_subdirs += [ 'libs/surfaces/sony9pin' ]
700
701 opts.Save('scache.conf', env)
702 Help(opts.GenerateHelpText(env))
703
704 if os.environ.has_key('PATH'):
705     env.Append(PATH = os.environ['PATH'])
706
707 if os.environ.has_key('PKG_CONFIG_PATH'):
708     env.Append(PKG_CONFIG_PATH = os.environ['PKG_CONFIG_PATH'])
709
710 if os.environ.has_key('CC'):
711     env['CC'] = os.environ['CC']
712
713 if os.environ.has_key('CXX'):
714     env['CXX'] = os.environ['CXX']
715
716 if os.environ.has_key('DISTCC_HOSTS'):
717     env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
718     env['ENV']['HOME'] = os.environ['HOME']
719
720 final_prefix = '$PREFIX'
721
722 if env['DESTDIR'] :
723     install_prefix = '$DESTDIR/$PREFIX'
724 else:
725     install_prefix = env['PREFIX']
726
727 subst_dict['%INSTALL_PREFIX%'] = install_prefix;
728 subst_dict['%FINAL_PREFIX%'] = final_prefix;
729 subst_dict['%PREFIX%'] = final_prefix;
730
731 if env['PREFIX'] == '/usr':
732     final_config_prefix = '/etc'
733 else:
734     final_config_prefix = env['PREFIX'] + '/etc'
735
736 config_prefix = '$DESTDIR' + final_config_prefix
737
738 # SCons should really do this for us
739
740 conf = Configure (env)
741
742 have_cxx = conf.TryAction (Action (str(env['CXX']) + ' --version'))
743 if have_cxx[0] != 1:
744     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
745     sys.exit (1)
746 else:
747     print "Congratulations, you have a functioning C++ compiler."
748
749 env = conf.Finish()
750
751 #
752 # Compiler flags and other system-dependent stuff
753 #
754
755 opt_flags = []
756 debug_flags = [ '-g' ]
757
758 # guess at the platform, used to define compiler flags
759
760 config_guess = os.popen("tools/config.guess").read()[:-1]
761
762 config_cpu = 0
763 config_arch = 1
764 config_kernel = 2
765 config_os = 3
766 config = config_guess.split ("-")
767
768 print "system triple: " + config_guess
769
770 # Autodetect
771 if env['DIST_TARGET'] == 'auto':
772     if config[config_arch] == 'apple':
773         # The [.] matches to the dot after the major version, "." would match any character
774         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
775             env['DIST_TARGET'] = 'panther'
776         else:
777             env['DIST_TARGET'] = 'tiger'
778     else:
779         if re.search ("x86_64", config[config_cpu]) != None:
780             env['DIST_TARGET'] = 'x86_64'
781         elif re.search("i[0-5]86", config[config_cpu]) != None:
782             env['DIST_TARGET'] = 'i386'
783         elif re.search("powerpc", config[config_cpu]) != None:
784             env['DIST_TARGET'] = 'powerpc'
785         else:
786             env['DIST_TARGET'] = 'i686'
787     print "\n*******************************"
788     print "detected DIST_TARGET = " + env['DIST_TARGET']
789     print "*******************************\n"
790
791
792 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
793     #
794     # Apple/PowerPC optimization options
795     #
796     # -mcpu=7450 does not reliably work with gcc 3.*
797     #
798     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
799         if config[config_arch] == 'apple':
800             opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
801         else:
802             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"])
803     else:
804         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
805     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
806
807 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':
808     
809     build_host_supports_sse = 0
810     
811     debug_flags.append ("-DARCH_X86")
812     opt_flags.append ("-DARCH_X86")
813     
814     if config[config_kernel] == 'linux' :
815         
816         if env['DIST_TARGET'] != 'i386':
817             
818             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
819             x86_flags = flag_line.split (": ")[1:][0].split (' ')
820             
821             if "mmx" in x86_flags:
822                 opt_flags.append ("-mmmx")
823             if "sse" in x86_flags:
824                 build_host_supports_sse = 1
825             if "3dnow" in x86_flags:
826                 opt_flags.append ("-m3dnow")
827             
828             if config[config_cpu] == "i586":
829                 opt_flags.append ("-march=i586")
830             elif config[config_cpu] == "i686":
831                 opt_flags.append ("-march=i686")
832     
833     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
834         opt_flags.extend (["-msse", "-mfpmath=sse"])
835         debug_flags.extend (["-msse", "-mfpmath=sse"])
836 # end of processor-specific section
837
838 # optimization section
839 if env['FPU_OPTIMIZATION']:
840     if env['DIST_TARGET'] == 'tiger':
841         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
842         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
843         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
844     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
845         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
846         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
847         if env['DIST_TARGET'] == 'x86_64':
848             opt_flags.append ("-DUSE_X86_64_ASM")
849             debug_flags.append ("-DUSE_X86_64_ASM")
850         if build_host_supports_sse != 1:
851             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)"
852 # end optimization section
853
854 #
855 # save off guessed arch element in an env
856 #
857 env.Append(CONFIG_ARCH=config[config_arch])
858
859
860 #
861 # ARCH="..." overrides all
862 #
863
864 if env['ARCH'] != '':
865     opt_flags = env['ARCH'].split()
866
867 #
868 # prepend boiler plate optimization flags
869 #
870
871 opt_flags[:0] = [
872     "-O3",
873     "-fomit-frame-pointer",
874     "-ffast-math",
875     "-fstrength-reduce"
876     ]
877
878 if env['DEBUG'] == 1:
879     env.Append(CCFLAGS=" ".join (debug_flags))
880 else:
881     env.Append(CCFLAGS=" ".join (opt_flags))
882
883 #
884 # warnings flags
885 #
886
887 env.Append(CCFLAGS="-Wall")
888 env.Append(CXXFLAGS="-Woverloaded-virtual")
889
890 if env['EXTRA_WARN']:
891     env.Append(CCFLAGS="-Wextra -pedantic")
892     env.Append(CXXFLAGS="-ansi")
893
894 if env['LIBLO']:
895     env.Append(CCFLAGS="-DHAVE_LIBLO")
896
897 #
898 # everybody needs this
899 #
900
901 env.Merge ([ libraries['core'] ])
902
903 #
904 # fix scons nitpickiness on APPLE
905 #
906
907 if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
908     env.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib")
909
910 #
911 # i18n support
912 #
913
914 conf = Configure (env)
915 if env['NLS']:
916     nls_error = 'This system is not configured for internationalized applications.  An english-only version will be built:'
917     print 'Checking for internationalization support ...'
918     have_gettext = conf.TryAction(Action('xgettext --version'))
919     if have_gettext[0] != 1:
920         nls_error += ' No xgettext command.'
921         env['NLS'] = 0
922     else:
923         print "Found xgettext"
924     
925     have_msgmerge = conf.TryAction(Action('msgmerge --version'))
926     if have_msgmerge[0] != 1:
927         nls_error += ' No msgmerge command.'
928         env['NLS'] = 0
929     else:
930         print "Found msgmerge"
931     
932     if not conf.CheckCHeader('libintl.h'):
933         nls_error += ' No libintl.h.'
934         env['NLS'] = 0
935         
936     if env['NLS'] == 0:
937         print nls_error
938     else:
939         print "International version will be built."
940 env = conf.Finish()
941
942 if env['NLS'] == 1:
943     env.Append(CCFLAGS="-DENABLE_NLS")
944
945 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n version subst_dict')
946
947 #
948 # the configuration file may be system dependent
949 #
950
951 conf = env.Configure ()
952
953 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
954     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
955     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
956 else:
957     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
958     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
959
960 # posix_memalign available
961 if not conf.CheckFunc('posix_memalign'):
962     print 'Did not find posix_memalign(), using malloc'
963     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
964
965
966 env = conf.Finish()
967
968 rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
969
970 #
971 # making this into an Alias directly prevents scons from understanding how to build
972 # svn_revision.h
973 #
974
975 the_revision = env.Command ('svn_revision.h', [], create_stored_revision)
976
977 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
978 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.rc'))
979
980 Default (rcbuild)
981
982 # source tarball
983
984 Precious (env['DISTTREE'])
985
986 env.Distribute (env['DISTTREE'],
987                 [ 'SConstruct', 'svn_revision.h',
988                   'COPYING', 'PACKAGER_README', 'README',
989                   'ardour.rc.in',
990                   'ardour_system.rc',
991                   'tools/config.guess',
992                   'icons/icon/ardour_icon_mac_mask.png',
993                   'icons/icon/ardour_icon_mac.png',
994                   'icons/icon/ardour_icon_tango_16px_blue.png',
995                   'icons/icon/ardour_icon_tango_16px_red.png',
996                   'icons/icon/ardour_icon_tango_22px_blue.png',
997                   'icons/icon/ardour_icon_tango_22px_red.png',
998                   'icons/icon/ardour_icon_tango_32px_blue.png',
999                   'icons/icon/ardour_icon_tango_32px_red.png',
1000                   'icons/icon/ardour_icon_tango_48px_blue.png',
1001                   'icons/icon/ardour_icon_tango_48px_red.png'
1002                   ] +
1003                 glob.glob ('DOCUMENTATION/AUTHORS*') +
1004                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
1005                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
1006                 glob.glob ('DOCUMENTATION/BUILD*') +
1007                 glob.glob ('DOCUMENTATION/FAQ*') +
1008                 glob.glob ('DOCUMENTATION/README*')
1009                 )
1010
1011 srcdist = env.Tarball(env['TARBALL'], env['DISTTREE'])
1012 env.Alias ('srctar', srcdist)
1013
1014 #
1015 # don't leave the distree around
1016 #
1017
1018 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
1019 env.AddPreAction (srcdist, Action (recreate_stored_revision))
1020 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
1021
1022 #
1023 # the subdirs
1024 #
1025
1026 for subdir in coredirs:
1027     SConscript (subdir + '/SConscript')
1028
1029 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
1030     for subdir in sublistdir:
1031         SConscript (subdir + '/SConscript')
1032
1033 # cleanup
1034 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
1035