f129793dd6299cac1eacf85ac7e4d9a86ecd39c6
[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 ardour_version = '2.0beta10'
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', 1),
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 = ardour_version,
80                    TARBALL='ardour-' + ardour_version + '.tar.bz2',
81                    DISTFILES = [ ],
82                    DISTTREE  = '#ardour-' + ardour_version,
83                    DISTCHECKDIR = '#ardour-' + 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 = "LANG= "
238     cmd += "svn info "
239     cmd += path
240     cmd += " | awk '/^Revision:/ { print $2}'"
241     return commands.getoutput (cmd)
242
243 def create_stored_revision (target = None, source = None, env = None):
244     if os.path.exists('.svn'):    
245         rev = fetch_svn_revision ('.');
246         try:
247             text  = "#ifndef __ardour_svn_revision_h__\n"
248             text += "#define __ardour_svn_revision_h__\n"
249             text += "static const char* ardour_svn_revision = \"" + rev + "\";\n";
250             text += "#endif\n"
251             print '============> writing svn revision info to svn_revision.h\n'
252             o = file ('svn_revision.h', 'w')
253             o.write (text)
254             o.close ()
255         except IOError:
256             print "Could not open svn_revision.h for writing\n"
257             sys.exit (-1)
258     else:
259         print "You cannot use \"scons revision\" on without using a checked out"
260         print "copy of the Ardour source code repository"
261         sys.exit (-1)
262
263 #
264 # A generic builder for version.cc files
265 #
266 # note: requires that DOMAIN, MAJOR, MINOR, MICRO are set in the construction environment
267 # note: assumes one source files, the header that declares the version variables
268 #
269
270 def version_builder (target, source, env):
271
272     text  = "int " + env['DOMAIN'] + "_major_version = " + str (env['MAJOR']) + ";\n"
273     text += "int " + env['DOMAIN'] + "_minor_version = " + str (env['MINOR']) + ";\n"
274     text += "int " + env['DOMAIN'] + "_micro_version = " + str (env['MICRO']) + ";\n"
275     
276     try:
277         o = file (target[0].get_path(), 'w')
278         o.write (text)
279         o.close ()
280     except IOError:
281         print "Could not open", target[0].get_path(), " for writing\n"
282         sys.exit (-1)
283
284     text  = "#ifndef __" + env['DOMAIN'] + "_version_h__\n"
285     text += "#define __" + env['DOMAIN'] + "_version_h__\n"
286     text += "extern const char* " + env['DOMAIN'] + "_revision;\n"
287     text += "extern int " + env['DOMAIN'] + "_major_version;\n"
288     text += "extern int " + env['DOMAIN'] + "_minor_version;\n"
289     text += "extern int " + env['DOMAIN'] + "_micro_version;\n"
290     text += "#endif /* __" + env['DOMAIN'] + "_version_h__ */\n"
291     
292     try:
293         o = file (target[1].get_path(), 'w')
294         o.write (text)
295         o.close ()
296     except IOError:
297         print "Could not open", target[1].get_path(), " for writing\n"
298         sys.exit (-1)
299         
300     return None
301
302 version_bld = Builder (action = version_builder)
303 env.Append (BUILDERS = {'VersionBuild' : version_bld})
304
305 #
306 # a builder that makes a hard link from the 'source' executable to a name with
307 # a "build ID" based on the most recent CVS activity that might be reasonably
308 # related to version activity. this relies on the idea that the SConscript
309 # file that builds the executable is updated with new version info and committed
310 # to the source code repository whenever things change.
311 #
312
313 def versioned_builder(target,source,env):
314     w, r = os.popen2( "svn info | awk '/^Revision:/ { print $2}'")
315     
316     last_revision = r.readline().strip()
317     w.close()
318     r.close()
319     if last_revision == "":
320         print "No SVN info found - versioned executable cannot be built"
321         return -1
322     
323     print "The current build ID is " + last_revision
324     
325     tagged_executable = source[0].get_path() + '-' + last_revision
326     
327     if os.path.exists (tagged_executable):
328         print "Replacing existing executable with the same build tag."
329         os.unlink (tagged_executable)
330     
331     return os.link (source[0].get_path(), tagged_executable)
332
333 verbuild = Builder (action = versioned_builder)
334 env.Append (BUILDERS = {'VersionedExecutable' : verbuild})
335
336 #
337 # source tar file builder
338 #
339
340 def distcopy (target, source, env):
341     treedir = str (target[0])
342     
343     try:
344         os.mkdir (treedir)
345     except OSError, (errnum, strerror):
346         if errnum != errno.EEXIST:
347             print 'mkdir ', treedir, ':', strerror
348     
349     cmd = 'tar cf - '
350     #
351     # we don't know what characters might be in the file names
352     # so quote them all before passing them to the shell
353     #
354     all_files = ([ str(s) for s in source ])
355     cmd += " ".join ([ "'%s'" % quoted for quoted in all_files])
356     cmd += ' | (cd ' + treedir + ' && tar xf -)'
357     p = os.popen (cmd)
358     return p.close ()
359
360 def tarballer (target, source, env):
361     cmd = 'tar -jcf ' + str (target[0]) +  ' ' + str(source[0]) + "  --exclude '*~'"
362     print 'running ', cmd, ' ... '
363     p = os.popen (cmd)
364     return p.close ()
365
366 dist_bld = Builder (action = distcopy,
367                     target_factory = SCons.Node.FS.default_fs.Entry,
368                     source_factory = SCons.Node.FS.default_fs.Entry,
369                     multi = 1)
370
371 tarball_bld = Builder (action = tarballer,
372                        target_factory = SCons.Node.FS.default_fs.Entry,
373                        source_factory = SCons.Node.FS.default_fs.Entry)
374
375 env.Append (BUILDERS = {'Distribute' : dist_bld})
376 env.Append (BUILDERS = {'Tarball' : tarball_bld})
377
378 #
379 # Make sure they know what they are doing
380 #
381
382 if env['VST']:
383     sys.stdout.write ("Are you building Ardour for personal use (rather than distribution to others)? [no]: ")
384     answer = sys.stdin.readline ()
385     answer = answer.rstrip().strip()
386     if answer != "yes" and answer != "y":
387         print 'You cannot build Ardour with VST support for distribution to others.\nIt is a violation of several different licenses. Build with VST=false.'
388         sys.exit (-1);
389     else:
390         print "OK, VST support will be enabled"
391
392
393 #######################
394 # Dependency Checking #
395 #######################
396
397 deps = \
398 {
399         'glib-2.0'             : '2.10.1',
400         'gthread-2.0'          : '2.10.1',
401         'gtk+-2.0'             : '2.8.1',
402         'libxml-2.0'           : '2.6.0',
403         'samplerate'           : '0.1.0',
404         'raptor'               : '1.4.2',
405         'lrdf'                 : '0.4.0',
406         'jack'                 : '0.101.1',
407         'libgnomecanvas-2.0'   : '2.0'
408 }
409
410 def DependenciesRequiredMessage():
411         print 'You do not have the necessary dependencies required to build ardour'
412         print 'Please consult http://ardour.org/building for more information'
413
414 def CheckPKGConfig(context, version):
415      context.Message( 'Checking for pkg-config version >= %s... ' %version )
416      ret = context.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
417      context.Result( ret )
418      return ret
419
420 def CheckPKGVersion(context, name, version):
421      context.Message( 'Checking for %s... ' % name )
422      ret = context.TryAction('pkg-config --atleast-version=%s %s' %(version,name) )[0]
423      context.Result( ret )
424      return ret
425
426 conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig,
427                                        'CheckPKGVersion' : CheckPKGVersion })
428
429 # I think a more recent version is needed on win32
430 min_pkg_config_version = '0.8.0'
431
432 if not conf.CheckPKGConfig(min_pkg_config_version):
433      print 'pkg-config >= %s not found.' % min_pkg_config_version
434      Exit(1)
435
436 for pkg, version in deps.iteritems():
437         if not conf.CheckPKGVersion( pkg, version ):
438                 print '%s >= %s not found.' %(pkg, version)
439                 DependenciesRequiredMessage()
440                 Exit(1)
441
442 env = conf.Finish()
443
444 # ----------------------------------------------------------------------
445 # Construction environment setup
446 # ----------------------------------------------------------------------
447
448 libraries = { }
449
450 libraries['core'] = LibraryInfo (CCFLAGS = '-Ilibs')
451
452 #libraries['sndfile'] = LibraryInfo()
453 #libraries['sndfile'].ParseConfig('pkg-config --cflags --libs sndfile')
454
455 libraries['lrdf'] = LibraryInfo()
456 libraries['lrdf'].ParseConfig('pkg-config --cflags --libs lrdf')
457
458 libraries['raptor'] = LibraryInfo()
459 libraries['raptor'].ParseConfig('pkg-config --cflags --libs raptor')
460
461 libraries['samplerate'] = LibraryInfo()
462 libraries['samplerate'].ParseConfig('pkg-config --cflags --libs samplerate')
463
464 if env['FFT_ANALYSIS']:
465         libraries['fftw3f'] = LibraryInfo()
466         libraries['fftw3f'].ParseConfig('pkg-config --cflags --libs fftw3f')
467         #
468         # Check for fftw3 header as well as the library
469         conf = Configure (libraries['fftw3f'])
470         if conf.CheckHeader ('fftw3.h') == False:
471                 print "FFT Analysis cannot be compiled without the FFTW3 headers, which don't seem to be installed"
472                 sys.exit (1)
473         libraries['fftw3f'] = conf.Finish();
474
475 libraries['jack'] = LibraryInfo()
476 libraries['jack'].ParseConfig('pkg-config --cflags --libs jack')
477
478 libraries['xml'] = LibraryInfo()
479 libraries['xml'].ParseConfig('pkg-config --cflags --libs libxml-2.0')
480
481 libraries['xslt'] = LibraryInfo()
482 libraries['xslt'].ParseConfig('pkg-config --cflags --libs libxslt')
483
484 libraries['glib2'] = LibraryInfo()
485 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs glib-2.0')
486 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gobject-2.0')
487 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gmodule-2.0')
488 libraries['glib2'].ParseConfig ('pkg-config --cflags --libs gthread-2.0')
489
490 libraries['gtk2'] = LibraryInfo()
491 libraries['gtk2'].ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
492
493 libraries['pango'] = LibraryInfo()
494 libraries['pango'].ParseConfig ('pkg-config --cflags --libs pango')
495
496 libraries['libgnomecanvas2'] = LibraryInfo()
497 libraries['libgnomecanvas2'].ParseConfig ('pkg-config --cflags --libs libgnomecanvas-2.0')
498
499 #libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
500
501 # The Ardour Control Protocol Library
502
503 libraries['ardour_cp'] = LibraryInfo (LIBS='ardour_cp', LIBPATH='#libs/surfaces/control_protocol',
504                                       CPPPATH='#libs/surfaces/control_protocol')
505
506 # The Ardour backend/engine
507
508 libraries['ardour'] = LibraryInfo (LIBS='ardour', LIBPATH='#libs/ardour', CPPPATH='#libs/ardour')
509 libraries['midi++2'] = LibraryInfo (LIBS='midi++', LIBPATH='#libs/midi++2', CPPPATH='#libs/midi++2')
510 libraries['pbd']    = LibraryInfo (LIBS='pbd', LIBPATH='#libs/pbd', CPPPATH='#libs/pbd')
511 libraries['gtkmm2ext'] = LibraryInfo (LIBS='gtkmm2ext', LIBPATH='#libs/gtkmm2ext', CPPPATH='#libs/gtkmm2ext')
512
513
514 # SCons should really do this for us
515
516 conf = Configure (env)
517
518 have_cxx = conf.TryAction (Action (str(env['CXX']) + ' --version'))
519 if have_cxx[0] != 1:
520     print "This system has no functional C++ compiler. You cannot build Ardour from source without one."
521     sys.exit (1)
522 else:
523     print "Congratulations, you have a functioning C++ compiler."
524
525 env = conf.Finish()
526
527
528 #
529 # Compiler flags and other system-dependent stuff
530 #
531
532 opt_flags = []
533 debug_flags = [ '-g' ]
534
535 # guess at the platform, used to define compiler flags
536
537 config_guess = os.popen("tools/config.guess").read()[:-1]
538
539 config_cpu = 0
540 config_arch = 1
541 config_kernel = 2
542 config_os = 3
543 config = config_guess.split ("-")
544
545 print "system triple: " + config_guess
546
547 # Autodetect
548 if env['DIST_TARGET'] == 'auto':
549     if config[config_arch] == 'apple':
550         # The [.] matches to the dot after the major version, "." would match any character
551         if re.search ("darwin[0-7][.]", config[config_kernel]) != None:
552             env['DIST_TARGET'] = 'panther'
553         else:
554             env['DIST_TARGET'] = 'tiger'
555     else:
556         if re.search ("x86_64", config[config_cpu]) != None:
557             env['DIST_TARGET'] = 'x86_64'
558         elif re.search("i[0-5]86", config[config_cpu]) != None:
559             env['DIST_TARGET'] = 'i386'
560         elif re.search("powerpc", config[config_cpu]) != None:
561             env['DIST_TARGET'] = 'powerpc'
562         else:
563             env['DIST_TARGET'] = 'i686'
564     print "\n*******************************"
565     print "detected DIST_TARGET = " + env['DIST_TARGET']
566     print "*******************************\n"
567
568
569 if config[config_cpu] == 'powerpc' and env['DIST_TARGET'] != 'none':
570     #
571     # Apple/PowerPC optimization options
572     #
573     # -mcpu=7450 does not reliably work with gcc 3.*
574     #
575     if env['DIST_TARGET'] == 'panther' or env['DIST_TARGET'] == 'tiger':
576         if config[config_arch] == 'apple':
577             ## opt_flags.extend ([ "-mcpu=7450", "-faltivec"])
578             # to support g3s but still have some optimization for above
579             opt_flags.extend ([ "-mcpu=G3", "-mtune=7450"])
580         else:
581             opt_flags.extend ([ "-mcpu=7400", "-maltivec", "-mabi=altivec"])
582     else:
583         opt_flags.extend([ "-mcpu=750", "-mmultiple" ])
584     opt_flags.extend (["-mhard-float", "-mpowerpc-gfxopt"])
585     opt_flags.extend (["-Os"])
586
587 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':
588     
589     build_host_supports_sse = 0
590     
591     debug_flags.append ("-DARCH_X86")
592     opt_flags.append ("-DARCH_X86")
593     
594     if config[config_kernel] == 'linux' :
595         
596         if env['DIST_TARGET'] != 'i386':
597             
598             flag_line = os.popen ("cat /proc/cpuinfo | grep '^flags'").read()[:-1]
599             x86_flags = flag_line.split (": ")[1:][0].split (' ')
600             
601             if "mmx" in x86_flags:
602                 opt_flags.append ("-mmmx")
603             if "sse" in x86_flags:
604                 build_host_supports_sse = 1
605             if "3dnow" in x86_flags:
606                 opt_flags.append ("-m3dnow")
607             
608             if config[config_cpu] == "i586":
609                 opt_flags.append ("-march=i586")
610             elif config[config_cpu] == "i686":
611                 opt_flags.append ("-march=i686")
612     
613     if ((env['DIST_TARGET'] == 'i686') or (env['DIST_TARGET'] == 'x86_64')) and build_host_supports_sse:
614         opt_flags.extend (["-msse", "-mfpmath=sse"])
615         debug_flags.extend (["-msse", "-mfpmath=sse"])
616 # end of processor-specific section
617
618 # optimization section
619 if env['FPU_OPTIMIZATION']:
620     if env['DIST_TARGET'] == 'tiger':
621         opt_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
622         debug_flags.append ("-DBUILD_VECLIB_OPTIMIZATIONS")
623         libraries['core'].Append(LINKFLAGS= '-framework Accelerate')
624     elif env['DIST_TARGET'] == 'i686' or env['DIST_TARGET'] == 'x86_64':
625         opt_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
626         debug_flags.append ("-DBUILD_SSE_OPTIMIZATIONS")
627         if env['DIST_TARGET'] == 'x86_64':
628             opt_flags.append ("-DUSE_X86_64_ASM")
629             debug_flags.append ("-DUSE_X86_64_ASM")
630         if build_host_supports_sse != 1:
631             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)"
632 # end optimization section
633
634 # handle x86/x86_64 libdir properly
635
636 if env['DIST_TARGET'] == 'x86_64':
637     env['LIBDIR']='lib64'
638 else:
639     env['LIBDIR']='lib'
640
641 #
642 # save off guessed arch element in an env
643 #
644 env.Append(CONFIG_ARCH=config[config_arch])
645
646
647 #
648 # ARCH="..." overrides all
649 #
650
651 if env['ARCH'] != '':
652     opt_flags = env['ARCH'].split()
653
654 #
655 # prepend boiler plate optimization flags
656 #
657
658 opt_flags[:0] = [
659     "-O3",
660     "-fomit-frame-pointer",
661     "-ffast-math",
662     "-fstrength-reduce"
663     ]
664
665 if env['DEBUG'] == 1:
666     env.Append(CCFLAGS=" ".join (debug_flags))
667 else:
668     env.Append(CCFLAGS=" ".join (opt_flags))
669
670 #
671 # warnings flags
672 #
673
674 env.Append(CCFLAGS="-Wall")
675 env.Append(CXXFLAGS="-Woverloaded-virtual")
676
677 if env['EXTRA_WARN']:
678     env.Append(CCFLAGS="-Wextra -pedantic")
679     env.Append(CXXFLAGS="-ansi")
680
681 if env['LIBLO']:
682     env.Append(CCFLAGS="-DHAVE_LIBLO")
683
684
685 #
686 # fix scons nitpickiness on APPLE
687 #
688
689
690 def prep_libcheck(topenv, libinfo):
691     if topenv['DIST_TARGET'] == 'panther' or topenv['DIST_TARGET'] == 'tiger':
692         libinfo.Append(CCFLAGS="-I/opt/local/include", LINKFLAGS="-L/opt/local/lib")
693
694 prep_libcheck(env, env)
695
696 #
697 # Check for libusb
698
699 libraries['usb'] = LibraryInfo ()
700 prep_libcheck(env, libraries['usb'])
701
702 conf = Configure (libraries['usb'])
703 if conf.CheckLib ('usb', 'usb_interrupt_write'):
704     have_libusb = True
705 else:
706     have_libusb = False
707
708 libraries['usb'] = conf.Finish ()
709
710 #
711 # Check for FLAC
712
713 libraries['flac'] = LibraryInfo ()
714 prep_libcheck(env, libraries['flac'])
715 libraries['flac'].Append(CCFLAGS="-I/usr/local/include", LINKFLAGS="-L/usr/local/lib")
716
717 conf = Configure (libraries['flac'])
718 conf.CheckLib ('FLAC', 'FLAC__stream_decoder_new', language='CXX')
719 libraries['flac'] = conf.Finish ()
720
721 # or if that fails...
722 #libraries['flac']    = LibraryInfo (LIBS='FLAC')
723
724 # boost (we don't link against boost, just use some header files)
725
726 libraries['boost'] = LibraryInfo ()
727 prep_libcheck(env, libraries['boost'])
728 libraries['boost'].Append(CCFLAGS="-I/usr/local/include", LINKFLAGS="-L/usr/local/lib")
729 conf = Configure (libraries['boost'])
730 if conf.CheckHeader ('boost/shared_ptr.hpp', language='CXX') == False:
731         print "Boost header files do not appear to be installed."
732         sys.exit (1)
733     
734 libraries['boost'] = conf.Finish ()
735
736 #
737 # Check for liblo
738
739 if env['LIBLO']:
740     libraries['lo'] = LibraryInfo ()
741     prep_libcheck(env, libraries['lo'])
742
743     conf = Configure (libraries['lo'])
744     if conf.CheckLib ('lo', 'lo_server_new') == False:
745         print "liblo does not appear to be installed."
746         sys.exit (1)
747     
748     libraries['lo'] = conf.Finish ()
749
750 #
751 # Check for dmalloc
752
753 libraries['dmalloc'] = LibraryInfo ()
754 prep_libcheck(env, libraries['dmalloc'])
755
756 #
757 # look for the threaded version
758 #
759
760 conf = Configure (libraries['dmalloc'])
761 if conf.CheckLib ('dmallocth', 'dmalloc_shutdown'):
762     have_libdmalloc = True
763 else:
764     have_libdmalloc = False
765
766 libraries['dmalloc'] = conf.Finish ()
767
768 #
769 # Audio/MIDI library (needed for MIDI, since audio is all handled via JACK)
770 #
771
772 conf = Configure(env)
773 if conf.CheckCHeader('jack/midiport.h'):
774     libraries['sysmidi'] = LibraryInfo (LIBS='jack')
775     env['SYSMIDI'] = 'JACK MIDI'
776     subst_dict['%MIDITAG%'] = "control"
777     subst_dict['%MIDITYPE%'] = "jack"
778     print "Using JACK MIDI"
779 elif conf.CheckCHeader('alsa/asoundlib.h'):
780     libraries['sysmidi'] = LibraryInfo (LIBS='asound')
781     env['SYSMIDI'] = 'ALSA Sequencer'
782     subst_dict['%MIDITAG%'] = "seq"
783     subst_dict['%MIDITYPE%'] = "alsa/sequencer"
784     print "Using ALSA MIDI"
785 elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
786     # this line is needed because scons can't handle -framework in ParseConfig() yet.
787     libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
788     env['SYSMIDI'] = 'CoreMIDI'
789     subst_dict['%MIDITAG%'] = "ardour"
790     subst_dict['%MIDITYPE%'] = "coremidi"
791     print "Using CoreMIDI"
792 else:
793     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."
794     sys.exit (1)
795
796 env = conf.Finish()
797
798 if env['SYSLIBS']:
799
800     syslibdeps = \
801     {
802         'sigc++-2.0'           : '2.0',
803         'gtkmm-2.4'            : '2.8',
804         'libgnomecanvasmm-2.6' : '2.12.0'
805     }
806
807     conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig,
808                     'CheckPKGVersion' : CheckPKGVersion })
809
810     for pkg, version in syslibdeps.iteritems():
811         if not conf.CheckPKGVersion( pkg, version ):
812             print '%s >= %s not found.' %(pkg, version)
813             DependenciesRequiredMessage()
814             Exit(1)
815         
816     env = conf.Finish()
817     
818     libraries['sigc2'] = LibraryInfo()
819     libraries['sigc2'].ParseConfig('pkg-config --cflags --libs sigc++-2.0')
820     libraries['glibmm2'] = LibraryInfo()
821     libraries['glibmm2'].ParseConfig('pkg-config --cflags --libs glibmm-2.4')
822     libraries['gdkmm2'] = LibraryInfo()
823     libraries['gdkmm2'].ParseConfig ('pkg-config --cflags --libs gdkmm-2.4')
824     libraries['gtkmm2'] = LibraryInfo()
825     libraries['gtkmm2'].ParseConfig ('pkg-config --cflags --libs gtkmm-2.4')
826     libraries['atkmm'] = LibraryInfo()
827     libraries['atkmm'].ParseConfig ('pkg-config --cflags --libs atkmm-1.6')
828     libraries['pangomm'] = LibraryInfo()
829     libraries['pangomm'].ParseConfig ('pkg-config --cflags --libs pangomm-1.4')
830     libraries['libgnomecanvasmm'] = LibraryInfo()
831     libraries['libgnomecanvasmm'].ParseConfig ('pkg-config --cflags --libs libgnomecanvasmm-2.6')
832
833 #
834 # cannot use system one for the time being
835 #
836     
837     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
838                                     LIBPATH='#libs/libsndfile',
839                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
840
841 #    libraries['libglademm'] = LibraryInfo()
842 #    libraries['libglademm'].ParseConfig ('pkg-config --cflags --libs libglademm-2.4')
843
844 #    libraries['flowcanvas'] = LibraryInfo(LIBS='flowcanvas', LIBPATH='#/libs/flowcanvas', CPPPATH='#libs/flowcanvas')
845     libraries['soundtouch'] = LibraryInfo()
846     libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs libSoundTouch')
847     # Comment the previous line and uncomment this for Debian:
848         #libraries['soundtouch'].ParseConfig ('pkg-config --cflags --libs libSoundTouch')
849
850     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
851                                             LIBPATH='#libs/appleutility',
852                                             CPPPATH='#libs/appleutility')
853     
854     coredirs = [
855         'templates'
856     ]
857     
858     subdirs = [
859         'libs/libsndfile',
860         'libs/pbd',
861         'libs/midi++2',
862         'libs/ardour',
863     # these are unconditionally included but have
864     # tests internally to avoid compilation etc
865     # if VST is not set
866         'libs/fst',
867         'vst',
868     # this is unconditionally included but has
869     # tests internally to avoid compilation etc
870     # if COREAUDIO is not set
871         'libs/appleutility'
872         ]
873     
874     gtk_subdirs = [
875 #        'libs/flowcanvas',
876         'libs/gtkmm2ext',
877         'gtk2_ardour',
878         'libs/clearlooks'
879         ]
880
881 else:
882     libraries['sigc2'] = LibraryInfo(LIBS='sigc++2',
883                                     LIBPATH='#libs/sigc++2',
884                                     CPPPATH='#libs/sigc++2')
885     libraries['glibmm2'] = LibraryInfo(LIBS='glibmm2',
886                                     LIBPATH='#libs/glibmm2',
887                                     CPPPATH='#libs/glibmm2')
888     libraries['pangomm'] = LibraryInfo(LIBS='pangomm',
889                                     LIBPATH='#libs/gtkmm2/pango',
890                                     CPPPATH='#libs/gtkmm2/pango')
891     libraries['atkmm'] = LibraryInfo(LIBS='atkmm',
892                                      LIBPATH='#libs/gtkmm2/atk',
893                                      CPPPATH='#libs/gtkmm2/atk')
894     libraries['gdkmm2'] = LibraryInfo(LIBS='gdkmm2',
895                                       LIBPATH='#libs/gtkmm2/gdk',
896                                       CPPPATH='#libs/gtkmm2/gdk')
897     libraries['gtkmm2'] = LibraryInfo(LIBS='gtkmm2',
898                                      LIBPATH="#libs/gtkmm2/gtk",
899                                      CPPPATH='#libs/gtkmm2/gtk/')
900     libraries['libgnomecanvasmm'] = LibraryInfo(LIBS='libgnomecanvasmm',
901                                                 LIBPATH='#libs/libgnomecanvasmm',
902                                                 CPPPATH='#libs/libgnomecanvasmm')
903     
904     libraries['soundtouch'] = LibraryInfo(LIBS='soundtouch',
905                                           LIBPATH='#libs/soundtouch',
906                                           CPPPATH=['#libs', '#libs/soundtouch'])
907     libraries['sndfile-ardour'] = LibraryInfo(LIBS='libsndfile-ardour',
908                                     LIBPATH='#libs/libsndfile',
909                                     CPPPATH=['#libs/libsndfile', '#libs/libsndfile/src'])
910 #    libraries['libglademm'] = LibraryInfo(LIBS='libglademm',
911 #                                          LIBPATH='#libs/libglademm',
912 #                                          CPPPATH='#libs/libglademm')
913     libraries['appleutility'] = LibraryInfo(LIBS='libappleutility',
914                                             LIBPATH='#libs/appleutility',
915                                             CPPPATH='#libs/appleutility')
916
917     coredirs = [
918         'libs/soundtouch',
919         'templates'
920     ]
921     
922     subdirs = [
923         'libs/sigc++2',
924         'libs/libsndfile',
925         'libs/pbd',
926         'libs/midi++2',
927         'libs/ardour',
928     # these are unconditionally included but have
929     # tests internally to avoid compilation etc
930     # if VST is not set
931         'libs/fst',
932         'vst',
933     # this is unconditionally included but has
934     # tests internally to avoid compilation etc
935     # if COREAUDIO is not set
936         'libs/appleutility'
937         ]
938     
939     gtk_subdirs = [
940         'libs/glibmm2',
941         'libs/gtkmm2/pango',
942         'libs/gtkmm2/atk',
943         'libs/gtkmm2/gdk',
944         'libs/gtkmm2/gtk',
945         'libs/libgnomecanvasmm',
946 #       'libs/flowcanvas',
947         'libs/gtkmm2ext',
948         'gtk2_ardour',
949         'libs/clearlooks'
950         ]
951
952 #
953 # * always build the LGPL control protocol lib, since we link against it from libardour
954 # * ditto for generic MIDI
955 # * tranzport checks whether it should build internally, but we need here so that
956 #   its included in the tarball
957 #
958
959 surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi', 'libs/surfaces/tranzport' ]
960
961 if env['SURFACES']:
962     if have_libusb:
963         env['TRANZPORT'] = 'yes'
964     if os.access ('libs/surfaces/sony9pin', os.F_OK):
965         surface_subdirs += [ 'libs/surfaces/sony9pin' ]
966
967 opts.Save('scache.conf', env)
968 Help(opts.GenerateHelpText(env))
969
970 if os.environ.has_key('PATH'):
971     env.Append(PATH = os.environ['PATH'])
972
973 if os.environ.has_key('PKG_CONFIG_PATH'):
974     env.Append(PKG_CONFIG_PATH = os.environ['PKG_CONFIG_PATH'])
975
976 if os.environ.has_key('CC'):
977     env['CC'] = os.environ['CC']
978
979 if os.environ.has_key('CXX'):
980     env['CXX'] = os.environ['CXX']
981
982 if os.environ.has_key('DISTCC_HOSTS'):
983     env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS']
984     env['ENV']['HOME'] = os.environ['HOME']
985
986 final_prefix = '$PREFIX'
987
988 if env['DESTDIR'] :
989     install_prefix = '$DESTDIR/$PREFIX'
990 else:
991     install_prefix = env['PREFIX']
992
993 subst_dict['%INSTALL_PREFIX%'] = install_prefix;
994 subst_dict['%FINAL_PREFIX%'] = final_prefix;
995 subst_dict['%PREFIX%'] = final_prefix;
996
997 if env['PREFIX'] == '/usr':
998     final_config_prefix = '/etc'
999 else:
1000     final_config_prefix = env['PREFIX'] + '/etc'
1001
1002 config_prefix = '$DESTDIR' + final_config_prefix
1003
1004 # For colorgcc
1005 if os.environ.has_key('PATH'):
1006         env['PATH'] = os.environ['PATH']
1007 if os.environ.has_key('TERM'):
1008         env['TERM'] = os.environ['TERM']
1009 if os.environ.has_key('HOME'):
1010         env['HOME'] = os.environ['HOME']
1011
1012 #
1013 # everybody needs this
1014 #
1015
1016 env.Merge ([ libraries['core'] ])
1017
1018
1019 #
1020 # i18n support
1021 #
1022
1023 conf = Configure (env)
1024 if env['NLS']:
1025     nls_error = 'This system is not configured for internationalized applications.  An english-only version will be built:'
1026     print 'Checking for internationalization support ...'
1027     have_gettext = conf.TryAction(Action('xgettext --version'))
1028     if have_gettext[0] != 1:
1029         nls_error += ' No xgettext command.'
1030         env['NLS'] = 0
1031     else:
1032         print "Found xgettext"
1033     
1034     have_msgmerge = conf.TryAction(Action('msgmerge --version'))
1035     if have_msgmerge[0] != 1:
1036         nls_error += ' No msgmerge command.'
1037         env['NLS'] = 0
1038     else:
1039         print "Found msgmerge"
1040     
1041     if not conf.CheckCHeader('libintl.h'):
1042         nls_error += ' No libintl.h.'
1043         env['NLS'] = 0
1044         
1045     if env['NLS'] == 0:
1046         print nls_error
1047     else:
1048         print "International version will be built."
1049 env = conf.Finish()
1050
1051 if env['NLS'] == 1:
1052     env.Append(CCFLAGS="-DENABLE_NLS")
1053
1054 Export('env install_prefix final_prefix config_prefix final_config_prefix libraries i18n ardour_version subst_dict')
1055
1056 #
1057 # the configuration file may be system dependent
1058 #
1059
1060 conf = env.Configure ()
1061
1062 if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Versions/A/Headers/CoreAudio.h'):
1063     subst_dict['%JACK_INPUT%'] = "coreaudio:Built-in Audio:in"
1064     subst_dict['%JACK_OUTPUT%'] = "coreaudio:Built-in Audio:out"
1065 else:
1066     subst_dict['%JACK_INPUT%'] = "alsa_pcm:playback_"
1067     subst_dict['%JACK_OUTPUT%'] = "alsa_pcm:capture_"
1068
1069 # posix_memalign available
1070 if not conf.CheckFunc('posix_memalign'):
1071     print 'Did not find posix_memalign(), using malloc'
1072     env.Append(CCFLAGS='-DNO_POSIX_MEMALIGN')
1073
1074
1075 env = conf.Finish()
1076
1077 rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
1078
1079 the_revision = env.Command ('frobnicatory_decoy', [], create_stored_revision)
1080
1081 env.Alias('revision', the_revision)
1082 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour_system.rc'))
1083 env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour2'), 'ardour.rc'))
1084
1085 Default (rcbuild)
1086
1087 # source tarball
1088
1089 Precious (env['DISTTREE'])
1090
1091 env.Distribute (env['DISTTREE'],
1092                [ 'SConstruct', 'svn_revision.h',
1093                   'COPYING', 'PACKAGER_README', 'README',
1094                   'ardour.rc.in',
1095                   'ardour_system.rc',
1096                   'tools/config.guess',
1097                   'icons/icon/ardour_icon_mac_mask.png',
1098                   'icons/icon/ardour_icon_mac.png',
1099                   'icons/icon/ardour_icon_tango_16px_blue.png',
1100                   'icons/icon/ardour_icon_tango_16px_red.png',
1101                   'icons/icon/ardour_icon_tango_22px_blue.png',
1102                   'icons/icon/ardour_icon_tango_22px_red.png',
1103                   'icons/icon/ardour_icon_tango_32px_blue.png',
1104                   'icons/icon/ardour_icon_tango_32px_red.png',
1105                   'icons/icon/ardour_icon_tango_48px_blue.png',
1106                   'icons/icon/ardour_icon_tango_48px_red.png'
1107                   ] +
1108                 glob.glob ('DOCUMENTATION/AUTHORS*') +
1109                 glob.glob ('DOCUMENTATION/CONTRIBUTORS*') +
1110                 glob.glob ('DOCUMENTATION/TRANSLATORS*') +
1111                 glob.glob ('DOCUMENTATION/BUILD*') +
1112                 glob.glob ('DOCUMENTATION/FAQ*') +
1113                 glob.glob ('DOCUMENTATION/README*')
1114                 )
1115
1116 srcdist = env.Tarball(env['TARBALL'], [ env['DISTTREE'], the_revision ])
1117 env.Alias ('srctar', srcdist)
1118
1119 #
1120 # don't leave the distree around
1121 #
1122
1123 env.AddPreAction (env['DISTTREE'], Action ('rm -rf ' + str (File (env['DISTTREE']))))
1124 env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE']))))
1125
1126 #
1127 # the subdirs
1128 #
1129
1130 for subdir in coredirs:
1131     SConscript (subdir + '/SConscript')
1132
1133 for sublistdir in [ subdirs, gtk_subdirs, surface_subdirs ]:
1134     for subdir in sublistdir:
1135         SConscript (subdir + '/SConscript')
1136
1137 # cleanup
1138 env.Clean ('scrub', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log'])
1139