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