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