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