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