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