~ubuntu-branches/ubuntu/precise/lilypond/precise

« back to all changes in this revision

Viewing changes to SConstruct

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Bushnell, BSG
  • Date: 2006-12-19 10:18:12 UTC
  • mfrom: (3.1.4 feisty)
  • Revision ID: james.westby@ubuntu.com-20061219101812-7awtjkp0i393wxty
Tags: 2.8.7-3
scripts/midi2ly.py: When setting DATADIR, find Lilypond python files
in the @TOPLEVEL_VERSION@ directory, not 'current'.  Patch thanks to
Chris Lamb (chris@chris-lamb.co.uk).  (Closes: #400550)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*-python-*-
 
2
 
 
3
'''
 
4
Experimental scons (www.scons.org) building.
 
5
 
 
6
Usage
 
7
 
 
8
    scons TARGET
 
9
 
 
10
build from source directory ./TARGET (not recursive)
 
11
 
 
12
Configure, build
 
13
 
 
14
    scons [config]             # configure
 
15
    scons                      # build all
 
16
 
 
17
Run from build tree
 
18
 
 
19
    run=$(pwd)/out-scons/usr
 
20
    export LOCALE=$run/share/locale
 
21
    export TEXMF='{'$run/share/lilypond,$(kpsexpand '$TEXMF')'}'
 
22
    PATH=$run/bin:$PATH
 
23
 
 
24
    #optionally, if you do not use custom.py below
 
25
    #export LILYPONDPREFIX=$run/share/lilypond/<VERSION>
 
26
 
 
27
    lilypond input/simple
 
28
 
 
29
Other targets
 
30
    scons mf-essential         # build minimal mf stuff
 
31
 
 
32
    scons doc                  # build web doc
 
33
    scons config               # reconfigure
 
34
    scons install              # install
 
35
    scons -c                   # clean
 
36
    scons -h                   # help
 
37
 
 
38
    scons /                    # build *everything* (including installation)
 
39
 
 
40
Options  (see scons -h)
 
41
    scons build=DIR            # clean srcdir build, output below DIR
 
42
    scons out=DIR              # write output for alterative config to DIR
 
43
 
 
44
Debugging
 
45
    scons --debug=dtree
 
46
    scons --debug=explain
 
47
    scons verbose=1
 
48
 
 
49
Optional custom.py
 
50
 
 
51
import os
 
52
out='out-scons'
 
53
optimising=0
 
54
debugging=1
 
55
gui=1
 
56
os.path.join (os.getcwd (), '=install')
 
57
prefix=os.path.join (os.environ['HOME'], 'usr', 'pkg', 'lilypond')
 
58
 
 
59
'''
 
60
 
 
61
 
 
62
# TODO:
 
63
 
 
64
#  * reality check:
 
65
#     - too many stages in Environments setup
 
66
#       (see also buildscripts/builders.py)
 
67
#     - Home-brew scons.cach configuration caching
 
68
#     - Home-brew source tarball generating -- [why] isn't that in SCons?
 
69
 
 
70
#  * usability and documentation for "./configure; make" users
 
71
 
 
72
#  * too much cruft in toplevel SConstruct
 
73
 
 
74
#  * (optional) operation without CVS directories, from tarball
 
75
 
 
76
#  * more program configure tests, actually use full executable name
 
77
 
 
78
#  * install doc
 
79
 
 
80
#  * split doc target: doc input examples mutopia?
 
81
 
 
82
#  * grep FIXME $(find . -name 'S*t')
 
83
 
 
84
#  * drop "fast"
 
85
 
 
86
import re
 
87
import glob
 
88
import os
 
89
import string
 
90
import sys
 
91
import stat
 
92
import shutil
 
93
 
 
94
# duh, we need 0.95.1
 
95
EnsureSConsVersion (0, 95)
 
96
 
 
97
usage = r'''Usage:
 
98
[ENVVAR=VALUE]... scons [OPTION=VALUE]... [TARGET|DIR]...
 
99
 
 
100
TARGETS: clean, config, doc, dist, install, mf-essential, po-update,
 
101
         realclean, release, sconsclean, tar, TAGS
 
102
 
 
103
ENVVARS: BASH, CCFLAGS, CC, CXX, LIBS, PYTHON, SH...
 
104
         (see SConstruct:config_vars)
 
105
 
 
106
OPTIONS:
 
107
'''
 
108
      
 
109
 
 
110
config_cache = 'scons.cache'
 
111
if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
 
112
        os.unlink (config_cache)
 
113
 
 
114
# All config_vars can be set as ENVVAR, eg:
 
115
#
 
116
#    CXX=g++-4.0 GS=~/usr/pkg/gs/bin/gs scons config
 
117
#
 
118
# append test_program variables automagically?
 
119
config_vars = [
 
120
        'BASH',
 
121
        'BYTEORDER',
 
122
        'CC',
 
123
        'CCFLAGS',
 
124
        'CPPPATH',
 
125
        'CPPDEFINES',
 
126
        'CXX',
 
127
        'CXXFLAGS',
 
128
        'DEFINES',
 
129
        'DVIPS',
 
130
        'FONTFORGE',
 
131
        'GCC',
 
132
        'GXX',
 
133
        'GS',
 
134
        'LIBS',
 
135
        'LINKFLAGS',
 
136
        'MF',
 
137
        'MFTRACE',
 
138
        'PERL',
 
139
        'PYTHON',
 
140
        'SH',
 
141
        ]
 
142
 
 
143
# Put your favourite stuff in custom.py
 
144
opts = Options ([config_cache, 'custom.py'], ARGUMENTS)
 
145
opts.Add ('prefix', 'Install prefix', '/usr/')
 
146
opts.Add ('out', 'Output directory', 'out-scons')
 
147
opts.Add ('build', 'Build directory', '.')
 
148
opts.Add ('DESTDIR', 'DESTDIR prepended to prefix', '')
 
149
opts.AddOptions (
 
150
        BoolOption ('warnings', 'compile with -Wall and similiar',
 
151
                   1),
 
152
        BoolOption ('debugging', 'compile with debugging symbols',
 
153
                    0),
 
154
        BoolOption ('optimising', 'compile with optimising',
 
155
                    1),
 
156
        BoolOption ('shared', 'build shared libraries',
 
157
                    0),
 
158
        BoolOption ('static', 'build static libraries',
 
159
                    1),
 
160
        BoolOption ('gui', 'build with GNOME backend (EXPERIMENTAL)',
 
161
                    1),
 
162
        BoolOption ('verbose', 'run commands with verbose flag',
 
163
                    0),
 
164
        BoolOption ('checksums', 'use checksums instead of timestamps',
 
165
                    0),
 
166
        BoolOption ('fast', 'use timestamps, implicit cache, prune CPPPATH',
 
167
                    0),
 
168
        )
 
169
 
 
170
srcdir = Dir ('.').srcnode ().abspath
 
171
#ugh
 
172
sys.path.append (os.path.join (srcdir, 'stepmake', 'bin'))
 
173
import packagepython
 
174
package = packagepython.Package (srcdir)
 
175
version = packagepython.version_tuple_to_str (package.version)
 
176
 
 
177
ENV = { 'PATH' : os.environ['PATH'] }
 
178
for key in ['LD_LIBRARY_PATH', 'GUILE_LOAD_PATH', 'PKG_CONFIG_PATH', 'TEXMF']:
 
179
        if os.environ.has_key (key):
 
180
                ENV[key] = os.environ[key]
 
181
 
 
182
env = Environment (
 
183
        ENV = ENV,
 
184
        BYTEORDER = sys.byteorder.upper (),
 
185
        CC = '$GCC',
 
186
        CXX = '$GXX',
 
187
        CPPDEFINES = '-DHAVE_CONFIG_H',
 
188
        MAKEINFO = 'LANG= makeinfo',
 
189
        MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
 
190
        
 
191
        PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
 
192
                                         'usr/pkg/gnome/lib'),
 
193
                           os.path.join (os.environ['HOME'],
 
194
                                         'usr/pkg/pango/lib')],
 
195
        GZIP='-9v',
 
196
        MFMODE = 'ljfour',
 
197
        TOPLEVEL_VERSION = version,
 
198
        )
 
199
 
 
200
Help (usage + opts.GenerateHelpText (env))
 
201
 
 
202
# Add all config_vars to opts, so that they will be read and saved
 
203
# together with the other configure options.
 
204
map (lambda x: opts.AddOptions ((x,)), config_vars)
 
205
opts.Update (env)
 
206
 
 
207
for key in config_vars:
 
208
        if os.environ.has_key (key):
 
209
                env[key] = os.environ[key]
 
210
 
 
211
if env['fast']:
 
212
        # Usability switch (Anthony Roach).
 
213
        # See http://www.scons.org/cgi-bin/wiki/GoFastButton
 
214
        # First do: scons realclean .
 
215
        env['checksums'] = 0
 
216
        SetOption ('max_drift', 1)
 
217
        SetOption ('implicit_cache', 1)
 
218
elif env['checksums']:
 
219
        # Always use checksums (makes more sense than timestamps).
 
220
        SetOption ('max_drift', 0)
 
221
        # Using *content* checksums prevents rebuilds after
 
222
        # [re]configure if config.hh has not changed.  Too bad that it
 
223
        # is unusably slow.
 
224
        TargetSignatures ('content')
 
225
 
 
226
absbuild = Dir (env['build']).abspath
 
227
outdir = os.path.join (Dir (env['build']).abspath, env['out'])
 
228
run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
 
229
 
 
230
 
 
231
config_hh = os.path.join (outdir, 'config.hh')
 
232
version_hh = os.path.join (outdir, 'version.hh')
 
233
 
 
234
env.Alias ('config', config_cache)
 
235
 
 
236
cachedir = os.path.join (outdir, 'build-cache')
 
237
 
 
238
if not os.path.exists (cachedir):
 
239
        os.makedirs (cachedir)
 
240
 
 
241
CacheDir (cachedir)
 
242
 
 
243
# No need to set $LILYPONDPREFIX to run lily, but cannot install...
 
244
if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
 
245
        env['prefix'] = run_prefix
 
246
 
 
247
prefix = env['prefix']
 
248
bindir = os.path.join (prefix, 'bin')
 
249
sharedir = os.path.join (prefix, 'share')
 
250
libdir = os.path.join (prefix, 'lib')
 
251
libdir_package = os.path.join (libdir, package.name)
 
252
lidbir_package_version = os.path.join (libdir_package, version)
 
253
localedir = os.path.join (sharedir, 'locale')
 
254
sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
 
255
sharedir_package = os.path.join (sharedir, package.name)
 
256
sharedir_package_version = os.path.join (sharedir_package, version)
 
257
lilypondprefix = sharedir_package_version
 
258
 
 
259
# junkme
 
260
env.Append (
 
261
        absbuild = absbuild,
 
262
        srcdir = srcdir,
 
263
        )
 
264
 
 
265
 
 
266
def list_sort (lst):
 
267
        sorted = lst
 
268
        sorted.sort ()
 
269
        return sorted
 
270
 
 
271
 
 
272
def configure (target, source, env):
 
273
        vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9]([.0-9]*[0-9])*).*$',
 
274
                          re.DOTALL)
 
275
        def get_version (program):
 
276
                command = '(pkg-config --modversion %(program)s || %(program)s --version || %(program)s -V) 2>&1' % vars ()
 
277
                pipe = os.popen (command)
 
278
                output = pipe.read ()
 
279
                if pipe.close ():
 
280
                        return None
 
281
                v = re.sub (vre, '\\1', output)
 
282
                if v[-1] == '\n':
 
283
                        v = v[:-1]
 
284
                return string.split (v, '.')
 
285
 
 
286
        def test_version (lst, full_name, minimal, description, package):
 
287
                program = os.path.basename (full_name)
 
288
                sys.stdout.write ('Checking %s version... ' % program)
 
289
                actual = get_version (program)
 
290
                if not actual:
 
291
                        print 'not found'
 
292
                        lst.append ((description, package, minimal, program,
 
293
                                     'not installed'))
 
294
                        return 0
 
295
                print string.join (actual, '.')
 
296
                if map (string.atoi, actual) \
 
297
                   < map (string.atoi, string.split (minimal, '.')):
 
298
                        lst.append ((description, package, minimal, program,
 
299
                                     string.join (actual, '.')))
 
300
                        return 0
 
301
                return 1
 
302
 
 
303
        def test_program (lst, program, minimal, description, package):
 
304
                key = program.upper ()
 
305
                if key.find ('+-'):
 
306
                        key = re.sub ('\+', 'X', key)
 
307
                        key = re.sub ('-', '_', key)
 
308
                sys.stdout.write ('Checking for %s ... ' % program)
 
309
                if env.has_key (key):
 
310
                        f = env[key]
 
311
                        sys.stdout.write ('(cached) ')
 
312
                else:
 
313
                        f = WhereIs (program)
 
314
                        env[key] = f
 
315
                if not f:
 
316
                        print 'not found'
 
317
                        lst.append ((description, package, minimal, program,
 
318
                                     'not installed'))
 
319
                        return 0
 
320
                print f
 
321
                return test_version (lst, program, minimal, description, package)
 
322
 
 
323
        def test_lib (lst, program, minimal, description, package):
 
324
                # FIXME: test for Debian or RPM (or -foo?) based dists
 
325
                # to guess (or get correct!: apt-cache search?)
 
326
                # package name.
 
327
                #if os.system ('pkg-config --atleast-version=0 freetype2'):
 
328
                # barf
 
329
                if test_version (lst, program, minimal, description,
 
330
                                 'lib%(package)s-dev or %(package)s-devel'
 
331
                                 % vars ()):
 
332
                        env.ParseConfig ('pkg-config --cflags --libs %(program)s'
 
333
                                         % vars ())
 
334
                        return 1
 
335
                return 0
 
336
 
 
337
        required = []
 
338
        test_program (required, 'bash', '2.0', 'Bash', 'bash')
 
339
        test_program (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
 
340
        test_program (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
 
341
        test_program (required, 'guile-config', '1.6', 'GUILE development',
 
342
                        'libguile-dev or guile-devel')
 
343
        test_program (required, 'mf', '0.0', 'Metafont', 'tetex-bin')
 
344
        test_program (required, 'mftrace', '1.1.9',
 
345
                      'mftrace (http://xs4all.nl/~hanwen/mftrace)', 'mftrace')
 
346
        test_program (required, 'potrace', '0.0', 'Potrace', 'potrace')
 
347
        test_program (required, 'python', '2.1', 'Python (www.python.org)',
 
348
                      'python')
 
349
        test_program (required, 'sh', '0.0', 'Bourne shell', 'sh')
 
350
 
 
351
        optional = []
 
352
        # Do not use bison 1.50 and 1.75.
 
353
        #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
 
354
        test_program (optional, 'bison', '1.25', 'Bison -- parser generator',
 
355
                        'bison')
 
356
        test_program (optional, 'dvips', '0.0', 'Dvips', 'tetex-bin')
 
357
        test_program (optional, 'fontforge', '0.0.20041224', 'FontForge',
 
358
                      'fontforge')
 
359
        test_program (optional, 'flex', '0.0', 'Flex -- lexer generator',
 
360
                      'flex')
 
361
        test_program (optional, 'guile', '1.6', 'GUILE scheme', 'guile')
 
362
        test_program (optional, 'gs', '8.14',
 
363
                      'Ghostscript PostScript interpreter',
 
364
                      'gs or gs-afpl or gs-esp or gs-gpl')
 
365
        test_program (optional, 'mftrace', '1.1.0', 'Metafont tracing Type1',
 
366
                        'mftrace')
 
367
        test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
 
368
        test_program (optional, 'perl', '4.0',
 
369
                      'Perl practical efficient readonly language', 'perl')
 
370
        #test_program (optional, 'ps2pdf', '0.0', 'Ps2pdf', 'gs')
 
371
 
 
372
        def CheckYYCurrentBuffer (context):
 
373
                context.Message ('Checking for yy_current_buffer... ')
 
374
                ret = conf.TryCompile ("""using namespace std;
 
375
                #include <FlexLexer.h>
 
376
                class yy_flex_lexer: public yyFlexLexer
 
377
                {
 
378
                public:
 
379
                yy_flex_lexer ()
 
380
                {
 
381
                yy_current_buffer = 0;
 
382
                }
 
383
                };""", '.cc')
 
384
                context.Result (ret)
 
385
                return ret
 
386
 
 
387
        def CheckLibkpathseaSo (context):
 
388
                saveCFLAGS = []
 
389
                if context.env.has_key ('CFLAGS'):
 
390
                        saveCFLAGS = context.env['CFLAGS']
 
391
                CFLAGS_shared_no_debugging = filter (lambda x: x != '-g',
 
392
                                                     saveCFLAGS)\
 
393
                                                     + ['-shared']
 
394
                # FIXME: how does this work, with scons
 
395
                context.env.Replace (CFLAGS = CFLAGS_shared_no_debugging)
 
396
                #context.env.Replace (CFLAGS = '')
 
397
                #context.env.Append (CFLAGS = ['-shared'])
 
398
                context.Message ('Checking for libkpathsea... ')
 
399
                ret = conf.TryLink ('''#include <kpathsea/kpathsea.h>
 
400
                int main ()
 
401
                {
 
402
                kpse_var_expand ("\$TEXMF");
 
403
                return 0;
 
404
                }
 
405
                ''', '.c')
 
406
                context.env.Replace (CFLAGS = saveCFLAGS)
 
407
                # FIXME: this prints 'ok' already
 
408
                context.Result (ret)
 
409
                if not ret:
 
410
                        return 0
 
411
                
 
412
                sys.stdout.write ('Checking for libkpathsea.so... ')
 
413
                testfile = str (context.sconf.lastTarget)
 
414
                shared_size = os.path.getsize (testfile)
 
415
                ret = shared_size < 40000
 
416
                if ret:
 
417
                        print 'ok'
 
418
                else:
 
419
                        print 'no'
 
420
                return ret
 
421
 
 
422
        conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
 
423
                                                : CheckYYCurrentBuffer,
 
424
                                                'CheckLibkpathseaSo'
 
425
                                                : CheckLibkpathseaSo })
 
426
 
 
427
        defines = {
 
428
           'DIRSEP' : "'%s'" % os.sep,
 
429
           'PATHSEP' : "'%s'" % os.pathsep,
 
430
           'PACKAGE': '"%s"' % package.name,
 
431
           'DATADIR' : '"%s"' % sharedir,
 
432
           'PACKAGE_DATADIR' : '"%s"' % sharedir_package,
 
433
           'LOCALEDIR' : '"%s"' %localedir,
 
434
        }
 
435
        conf.env.Append (DEFINES = defines)
 
436
 
 
437
        command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
 
438
        PYTHON_INCLUDE = os.popen (command).read ()#[:-1]
 
439
        if env['fast']:
 
440
                env.Append (CCFLAGS = ['-I%s' % PYTHON_INCLUDE])
 
441
        else:
 
442
                env.Append (CPPPATH = [PYTHON_INCLUDE])
 
443
 
 
444
        headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'libio.h',
 
445
                   'Python.h')
 
446
        for i in headers:
 
447
                if conf.CheckCHeader (i):
 
448
                        key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
 
449
                        conf.env['DEFINES'][key] = 1
 
450
 
 
451
        ccheaders = ('sstream',)
 
452
        for i in ccheaders:
 
453
                if conf.CheckCXXHeader (i):
 
454
                        key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
 
455
                        conf.env['DEFINES'][key] = 1
 
456
 
 
457
        functions = ('fopencookie', 'funopen',
 
458
                     'gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
 
459
        for i in functions:
 
460
                if 0 or conf.CheckFunc (i):
 
461
                        key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
 
462
                        conf.env['DEFINES'][key] = 1
 
463
 
 
464
        if conf.CheckYYCurrentBuffer ():
 
465
                conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
 
466
 
 
467
        if conf.CheckLibkpathseaSo ():
 
468
                conf.env['DEFINES']['HAVE_LIBKPATHSEA_SO'] = '1'
 
469
 
 
470
        if conf.CheckLib ('dl'):
 
471
                pass
 
472
 
 
473
        if conf.CheckLib ('kpathsea'):
 
474
                conf.env['DEFINES']['KPATHSEA'] = 1
 
475
 
 
476
        # huh? 
 
477
        if conf.CheckLib ('kpathsea', 'kpse_find_file'):
 
478
                conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
 
479
        if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
 
480
                conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
 
481
 
 
482
        if env['fast']:
 
483
                cpppath = []
 
484
                if env.has_key ('CPPPATH'):
 
485
                        cpppath = env['CPPPATH']
 
486
 
 
487
        ## FIXME: linkage, check for libguile.h and scm_boot_guile
 
488
        #this could happen after flower...
 
489
        env.ParseConfig ('guile-config compile')
 
490
 
 
491
        test_program (required, 'pkg-config', '0.9.0',
 
492
                      'pkg-config library compile manager', 'pkg-config')
 
493
        if test_lib (required, 'freetype2', '0.0',
 
494
                     'Development files for FreeType 2 font engine',
 
495
                     'freetype6'):
 
496
                conf.env['DEFINES']['HAVE_FREETYPE2'] = '1'
 
497
                
 
498
        if test_lib (required, 'pangoft2', '1.6.0',
 
499
                     'Development files for pango, with FreeType2',
 
500
                     'pango1.0'):
 
501
                conf.env['DEFINES']['HAVE_PANGO_FT2'] = '1'
 
502
                conf.env['DEFINES']['HAVE_PANGO16'] = '1'
 
503
 
 
504
        if test_lib (optional, 'fontconfig', '2.2.0',
 
505
                     'Development files for fontconfig', 'fontconfig1'):
 
506
                conf.env['DEFINES']['HAVE_FONTCONFIG'] = '1'
 
507
        
 
508
        #this could happen only for compiling pango-*
 
509
        if env['gui']:
 
510
                test_lib (required, 'gtk+-2.0', '2.4.0',
 
511
                          'Development files for GTK+', 'gtk2.0')
 
512
                if test_lib (required, 'pango', '1.6.0',
 
513
                          'Development files for pango', 'pango1.0'):
 
514
                        conf.env['DEFINES']['HAVE_PANGO16'] = '1'
 
515
                        
 
516
                if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
 
517
                        conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
 
518
        if env['fast']:
 
519
                # Using CCFLAGS = -I<system-dir> rather than CPPPATH = [
 
520
                # <system-dir>] speeds up SCons
 
521
                env['CCFLAGS'] += map (lambda x: '-I' + x,
 
522
                                       env['CPPPATH'][len (cpppath):])
 
523
                env['CPPPATH'] = cpppath
 
524
 
 
525
        if required:
 
526
                print
 
527
                print '********************************'
 
528
                print 'Please install required packages'
 
529
                for i in required:
 
530
                        print '%s:      %s-%s or newer (found: %s %s)' % i
 
531
                Exit (1)
 
532
 
 
533
        if optional:
 
534
                print
 
535
                print '*************************************'
 
536
                print 'Consider installing optional packages'
 
537
                for i in optional:
 
538
                        print '%s:      %s-%s or newer (found: %s %s)' % i
 
539
 
 
540
        return conf.Finish ()
 
541
 
 
542
def config_header (target, source, env):
 
543
        config = open (str (target[0]), 'w')
 
544
        for i in list_sort (env['DEFINES'].keys ()):
 
545
                config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
 
546
        config.close ()
 
547
env.Command (config_hh, config_cache, config_header)
 
548
 
 
549
# hmm?
 
550
def xuniquify (lst):
 
551
        n = []
 
552
        for i in lst:
 
553
                if not i in n:
 
554
                        n.append (i)
 
555
        lst = n
 
556
        return lst
 
557
 
 
558
def uniquify (lst):
 
559
        d = {}
 
560
        n = len (lst)
 
561
        i = 0
 
562
        while i < n:
 
563
                if not d.has_key (lst[i]):
 
564
                        d[lst[i]] = 1
 
565
                        i += 1
 
566
                else:
 
567
                        del lst[i]
 
568
                        n -= 1
 
569
        return lst
 
570
 
 
571
def uniquify_config_vars (env):
 
572
        for i in config_vars:
 
573
                if env.has_key (i) and type (env[i]) == type ([]):
 
574
                        env[i] = uniquify (env[i])
 
575
 
 
576
def save_config_cache (env):
 
577
        ## FIXME: Is this smart, using option cache for saving
 
578
        ## config.cache?  I cannot seem to find the official method.
 
579
        uniquify_config_vars (env)
 
580
        opts.Save (config_cache, env)
 
581
 
 
582
        if 'config' in COMMAND_LINE_TARGETS:
 
583
                sys.stdout.write ('\n')
 
584
                sys.stdout.write ('LilyPond configured')
 
585
                sys.stdout.write ('\n')
 
586
                sys.stdout.write ('Now run')
 
587
                sys.stdout.write ('\n')
 
588
                sys.stdout.write ('    scons [TARGET|DIR]...')
 
589
                sys.stdout.write ('\n')
 
590
                sys.stdout.write ('\n')
 
591
                sys.stdout.write ('Examples:')
 
592
                sys.stdout.write ('\n')
 
593
                sys.stdout.write ('    scons lily    # build lilypond')
 
594
                sys.stdout.write ('\n')
 
595
                sys.stdout.write ('    scons all     # build everything')
 
596
                sys.stdout.write ('\n')
 
597
                sys.stdout.write ('    scons doc     # build documentation')
 
598
                sys.stdout.write ('\n')
 
599
                ## TODO
 
600
                ## sys.stdout.write ('    scons prefix=/usr DESTDIR=/tmp/pkg all install')
 
601
                ## sys.stdout.write ('\n')
 
602
                Exit (0)
 
603
        elif not env['checksums']:
 
604
                # When using timestams, config.hh is NEW.  The next
 
605
                # build triggers recompilation of everything.  Exiting
 
606
                # here makes SCons use the actual timestamp for config.hh
 
607
                # and prevents recompiling everything the next run.
 
608
                command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
 
609
                sys.stdout.write ('Running %s ... ' % command)
 
610
                sys.stdout.write ('\n')
 
611
                s = os.system (command)
 
612
                Exit (s)
 
613
 
 
614
# WTF?
 
615
# scons: *** Calling Configure from Builders is not supported.
 
616
# env.Command (config_cache, None, configure)
 
617
if not os.path.exists (config_cache) \
 
618
   or (os.stat ('SConstruct')[stat.ST_MTIME]
 
619
       > os.stat (config_cache)[stat.ST_MTIME]):
 
620
        env = configure (None, None, env)
 
621
        save_config_cache (env)
 
622
elif env['checksums']:
 
623
        # just save everything
 
624
        save_config_cache (env)
 
625
 
 
626
#urg how does #/ subst work?
 
627
Export ('env')
 
628
SConscript ('buildscripts/builder.py')
 
629
 
 
630
env.PrependENVPath ('PATH',
 
631
                    os.path.join (env['absbuild'], env['out'], 'usr/bin'))
 
632
 
 
633
LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond/', version)
 
634
 
 
635
env.Append (ENV = {
 
636
        #'LILYPONDPREFIX' : os.path.join (run_prefix, 'share/lilypond/', version),
 
637
        'LILYPONDPREFIX' : LILYPONDPREFIX,
 
638
        # ugh, can't use LILYPONDPREFIX here
 
639
        #'TEXMF' : '{' + os.path.join (run_prefix, 'share/lilypond/', version)\
 
640
        #+ ',' \
 
641
        'TEXMF' : '{$LILYPONDPREFIX,'
 
642
        + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}',
 
643
        })
 
644
 
 
645
BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
 
646
BUILD_LILYPOND = '$absbuild/lily/$out/lilypond ${__verbose}'
 
647
BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py ${__verbose}'
 
648
 
 
649
 
 
650
# post-option environment-update
 
651
env.Append (
 
652
        bindir = bindir,
 
653
        sharedir = sharedir,
 
654
        lilypond_datadir = sharedir_package,
 
655
        localedir = localedir,
 
656
        local_lilypond_datadir = sharedir_package_version,
 
657
        lilypondprefix = lilypondprefix,
 
658
        sharedir_package = sharedir_package,
 
659
        sharedir_doc_package = sharedir_doc_package,
 
660
        sharedir_package_version = sharedir_package_version,
 
661
 
 
662
        # global build verbosity switch
 
663
        __verbose = ' --verbose',
 
664
        
 
665
        LILYPOND = BUILD_LILYPOND,
 
666
        ABC2LY = BUILD_ABC2LY,
 
667
        LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
 
668
        LILYPOND_BOOK_FORMAT = 'texi-html',
 
669
        MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
 
670
        # should not be necessary
 
671
        # PYTHONPATH = ['$absbuild/python/$out'],
 
672
        TEXI2DVI_PAPERSIZE = '@afourpaper',
 
673
        TEXI2DVI_FLAGS = [ '-t$TEXI2DVI_PAPERSIZE'],
 
674
        DVIPS_PAPERSIZE = 'a4',
 
675
        DVIPS_FLAGS = ['-t$DVIPS_PAPERSIZE',
 
676
                       '-u+lilypond.map',
 
677
                       '-u+ec-mftrace.map'],
 
678
        PSPDF_FLAGS = ['-sPAPERSIZE=$DVIPS_PAPERSIZE'],
 
679
        )
 
680
 
 
681
env.Append (CCFLAGS = ['-pipe', '-Wno-pmf-conversions'])
 
682
if env['debugging']:
 
683
        env.Append (CCFLAGS = ['-g'])
 
684
if env['optimising']:
 
685
        env.Append (CCFLAGS = '-O2')
 
686
        env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
 
687
if env['warnings']:
 
688
        env.Append (CCFLAGS = ['-W', '-Wall'])
 
689
        env.Append (CXXFLAGS = ['-Wconversion'])
 
690
 
 
691
# ugr,huh?
 
692
env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
 
693
# FIXME: ParseConfig ignores -L flag?
 
694
env.Append (LINKFLAGS = ['-L/usr/X11R6/lib'])
 
695
 
 
696
if env['verbose']:
 
697
        env['__verbose'] = ' --verbose'
 
698
        env['set__x'] = 'set -x;'
 
699
 
 
700
 
 
701
## Explicit target and dependencies
 
702
 
 
703
if 'clean' in COMMAND_LINE_TARGETS:
 
704
        # ugh: prevent reconfigure instead of clean
 
705
        os.system ('touch %s' % config_cache)
 
706
        
 
707
        command = sys.argv[0] + ' -c .'
 
708
        sys.stdout.write ('Running %s ... ' % command)
 
709
        sys.stdout.write ('\n')
 
710
        s = os.system (command)
 
711
        if os.path.exists (config_cache):
 
712
                os.unlink (config_cache)
 
713
        Exit (s)
 
714
 
 
715
if 'sconsclean' in COMMAND_LINE_TARGETS:
 
716
        command = 'rm -rf scons.cache $(find . -name ".scon*")'
 
717
        s = os.system (command)
 
718
        if os.path.exists (config_cache):
 
719
                os.unlink (config_cache)
 
720
        Exit (s)
 
721
        
 
722
if 'realclean' in COMMAND_LINE_TARGETS:
 
723
        command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
 
724
        sys.stdout.write ('Running %s ... ' % command)
 
725
        sys.stdout.write ('\n')
 
726
        s = os.system (command)
 
727
        if os.path.exists (config_cache):
 
728
                os.unlink (config_cache)
 
729
        Exit (s)
 
730
 
 
731
# Declare SConscript phonies 
 
732
env.Alias ('minimal', config_cache)
 
733
env.Alias ('mf-essential', config_cache)
 
734
 
 
735
env.Alias ('minimal', ['lily', 'mf-essential'])
 
736
env.Alias ('all', ['minimal', 'mf', '.'])
 
737
# Do we want the doc/web separation?
 
738
env.Alias ('doc',
 
739
           ['Documentation',
 
740
            'Documentation/user',
 
741
            'Documentation/topdocs',
 
742
            'Documentation/bibliography',
 
743
            'input'])
 
744
 
 
745
# Without target arguments, do minimal build
 
746
if not COMMAND_LINE_TARGETS:
 
747
        env.Default (['minimal'])
 
748
 
 
749
# GNU Make rerouting compat:
 
750
env.Alias ('web', 'doc')
 
751
 
 
752
 
 
753
env.Command (version_hh, '#/VERSION',
 
754
             '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
 
755
 
 
756
# post-config environment update
 
757
env.Append (
 
758
        run_prefix = run_prefix,
 
759
        LILYPONDPREFIX = LILYPONDPREFIX,
 
760
 
 
761
        # FIXME: move to lily/SConscript?
 
762
        LIBPATH = [os.path.join (absbuild, 'flower', env['out']),
 
763
                   os.path.join (absbuild, 'kpath-guile', env['out']),],
 
764
        CPPPATH = [outdir, ],
 
765
        LILYPOND_PATH = ['.',
 
766
                         '$srcdir/input',
 
767
                         '$srcdir/input/regression',
 
768
                         '$srcdir/input/test',
 
769
                         '$srcdir/input/tutorial',
 
770
                         '$srcdir/Documentation/user',
 
771
                         '$absbuild/mf/$out',
 
772
#                        os.path.join (absbuild, 'Documentation',
 
773
#                                      env['out']),
 
774
#                        os.path.join (absbuild, 'Documentation/user',
 
775
#                                      env['out']),
 
776
                         ],
 
777
        MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
 
778
                         '$absbuild/Documentation/user/$out'],
 
779
        )
 
780
 
 
781
def symlink_tree (target, source, env):
 
782
        def mkdirs (dir):
 
783
                def mkdir (dir):
 
784
                        if not dir:
 
785
                                os.chdir (os.sep)
 
786
                                return
 
787
                        if not os.path.isdir (dir):
 
788
                                if os.path.exists (dir):
 
789
                                        os.unlink (dir)
 
790
                                os.mkdir (dir)
 
791
                        os.chdir (dir)
 
792
                map (mkdir, string.split (dir, os.sep))
 
793
        def symlink (src, dst):
 
794
                os.chdir (absbuild)
 
795
                dir = os.path.dirname (dst)
 
796
                mkdirs (dir)
 
797
                if src[0] == '#':
 
798
                        frm = os.path.join (srcdir, src[1:])
 
799
                else:
 
800
                        depth = len (string.split (dir, '/'))
 
801
                        if src.find ('@') > -1:
 
802
                                frm = os.path.join ('../' * depth,
 
803
                                                    string.replace (src, '@',
 
804
                                                                    env['out']))
 
805
                        else:
 
806
                                frm = os.path.join ('../' * depth, src,
 
807
                                                    env['out'])
 
808
                if src[-1] == '/':
 
809
                        frm = os.path.join (frm, os.path.basename (dst))
 
810
                if env['verbose']:
 
811
                        print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
 
812
                os.symlink (frm, os.path.basename (dst))
 
813
        shutil.rmtree (run_prefix)
 
814
        prefix = os.path.join (env['out'], 'usr')
 
815
        map (lambda x: symlink (x[0], os.path.join (prefix,
 
816
                                                    x[1] % {'ver' : version})),
 
817
             # ^# := source dir
 
818
             # @  := out
 
819
             # /$ := add dst file_name
 
820
             (('python',     'lib/lilypond/python'),
 
821
              # ugh
 
822
              ('python',     'share/lilypond/%(ver)s/python'),
 
823
              ('lily/',      'bin/lilypond'),
 
824
              ('scripts/',   'bin/convert-ly'),
 
825
              ('scripts/',   'bin/lilypond-book'),
 
826
              ('scripts/',   'bin/ps2png'),
 
827
              ('mf',         'share/lilypond/%(ver)s/dvips/mf-out'),
 
828
              ('#ps',        'share/lilypond/%(ver)s/dvips/ps'),
 
829
              ('#ps',        'share/lilypond/%(ver)s/tex/music-drawing-routines.ps'),
 
830
              ('mf',         'share/lilypond/%(ver)s/otf'),
 
831
              ('mf',         'share/lilypond/%(ver)s/tfm'),
 
832
              ('tex',        'share/lilypond/%(ver)s/tex/enc'),
 
833
              ('#mf',        'share/lilypond/%(ver)s/fonts/mf'),
 
834
              ('mf',         'share/lilypond/%(ver)s/fonts/map'),
 
835
              ('mf',         'share/lilypond/%(ver)s/fonts/otf'),
 
836
              ('mf',         'share/lilypond/%(ver)s/fonts/tfm'),
 
837
              ('mf',         'share/lilypond/%(ver)s/fonts/type1'),
 
838
              ('#tex',       'share/lilypond/%(ver)s/tex/source'),
 
839
              ('tex',        'share/lilypond/%(ver)s/tex/tex-out'),
 
840
              ('mf',         'share/lilypond/%(ver)s/tex/mf-out'),
 
841
              ('#ly',        'share/lilypond/%(ver)s/ly'),
 
842
              ('#scm',       'share/lilypond/%(ver)s/scm'),
 
843
              ('#scripts',   'share/lilypond/%(ver)s/scripts'),
 
844
              ('#ps',        'share/lilypond/%(ver)s/ps'),
 
845
              ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
 
846
              ('elisp',      'share/lilypond/%(ver)s/elisp')))
 
847
 
 
848
        print "FIXME: BARF BARF BARF"
 
849
        os.chdir (absbuild)
 
850
        out = env['out']
 
851
        ver = version
 
852
        prefix = os.path.join (env['out'], 'usr/share/lilypond/%(ver)s/fonts'
 
853
                               % vars ())
 
854
        for ext in ('enc', 'map', 'otf', 'svg', 'tfm', 'pfa'):
 
855
                dir = os.path.join (absbuild, prefix, ext)
 
856
                os.system ('rm -f ' + dir)
 
857
                mkdirs (dir)
 
858
                os.chdir (dir)
 
859
                os.system ('ln -s ../../../../../../../mf/%(out)s/*.%(ext)s .'
 
860
                           % vars ())
 
861
        os.chdir (srcdir)
 
862
 
 
863
if 1: #env['debugging']:
 
864
        stamp = os.path.join (run_prefix, 'stamp')
 
865
        env.Command (stamp, ['#/SConstruct', '#/VERSION'],
 
866
                     [symlink_tree, 'touch $TARGET'])
 
867
        env.Depends ('lily', stamp)
 
868
        
 
869
#### dist, tar
 
870
def plus (a, b):
 
871
        a + b
 
872
 
 
873
def cvs_entry_is_dir (line):
 
874
        return line[0] == 'D' and line[-2] == '/'
 
875
 
 
876
def cvs_entry_is_file (line):
 
877
        return line[0] == '/' and line[-2] == '/'
 
878
 
 
879
def cvs_dirs (dir):
 
880
        entries = os.path.join (dir, 'CVS/Entries')
 
881
        if not os.path.exists (entries):
 
882
                return []
 
883
        entries = open (entries).readlines ()
 
884
        dir_entries = filter (cvs_entry_is_dir, entries)
 
885
        dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
 
886
                    dir_entries)
 
887
        return dirs + map (cvs_dirs, dirs)
 
888
 
 
889
def cvs_files (dir):
 
890
        entries = os.path.join (dir, 'CVS/Entries')
 
891
        if not os.path.exists (entries):
 
892
                return []
 
893
        entries = open (entries).readlines ()
 
894
        file_entries = filter (cvs_entry_is_file, entries)
 
895
        files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
 
896
        return map (lambda x: os.path.join (dir, x), files)
 
897
 
 
898
def flatten (tree, lst):
 
899
        if type (tree) == type ([]):
 
900
                for i in tree:
 
901
                        if type (i) == type ([]):
 
902
                                flatten (i, lst)
 
903
                        else:
 
904
                                lst.append (i)
 
905
        return lst
 
906
 
 
907
if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
 
908
        subdirs = flatten (cvs_dirs ('.'), [])
 
909
else:
 
910
        # ugh
 
911
        command = 'cd %(srcdir)s \
 
912
        && find . -name SConscript | sed s@/SConscript@@' % vars ()
 
913
        subdirs = string.split (os.popen (command).read ())
 
914
 
 
915
if env['fast']\
 
916
   and 'all' not in COMMAND_LINE_TARGETS\
 
917
   and 'doc' not in COMMAND_LINE_TARGETS\
 
918
   and 'web' not in COMMAND_LINE_TARGETS\
 
919
   and 'install' not in COMMAND_LINE_TARGETS\
 
920
   and 'clean' not in COMMAND_LINE_TARGETS:
 
921
        subdirs = ['lily',
 
922
                   'flower',
 
923
                   'kpath-guile',
 
924
                   'mf',
 
925
                   'python',
 
926
                   ]
 
927
 
 
928
if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
 
929
        src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
 
930
else:
 
931
        src_files = ['foobar']
 
932
 
 
933
readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
 
934
txt_files = map (lambda x: x + '.txt', readme_files)
 
935
 
 
936
 
 
937
#
 
938
# speeds up build by +- 5% 
 
939
 
940
if not env['fast']:
 
941
        foo = map (lambda x: env.TXT (x + '.txt',
 
942
                                      os.path.join ('Documentation/topdocs', x)),
 
943
                   readme_files)
 
944
        tar_base = package.name + '-' + version
 
945
        tar_name = tar_base + '.tar.gz'
 
946
        ball_prefix = os.path.join (outdir, tar_base)
 
947
        tar_ball = os.path.join (outdir, tar_name)
 
948
 
 
949
        dist_files = src_files + txt_files
 
950
        ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
 
951
        map (lambda x: env.Depends (tar_ball, x), ball_files)
 
952
        map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
 
953
                                    'ln $SOURCE $TARGET'), dist_files)
 
954
        tar = env.Command (tar_ball, src_files,
 
955
                           ['rm -f $$(find $TARGET.dir -name .sconsign)',
 
956
                            'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
 
957
        env.Alias ('tar', tar)
 
958
 
 
959
        dist_ball = os.path.join (package.release_dir, tar_name)
 
960
        env.Command (dist_ball, tar_ball,
 
961
                     'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
 
962
                     + 'ln $SOURCE $TARGET')
 
963
        env.Depends ('dist', dist_ball)
 
964
        patch_name = os.path.join (outdir, tar_base + '.diff.gz')
 
965
        patch = env.PATCH (patch_name, tar_ball)
 
966
        env.Depends (patch_name, dist_ball)
 
967
        env.Alias ('release', patch)
 
968
 
 
969
#### web
 
970
if not env['fast']:
 
971
        web_base = os.path.join (outdir, 'web')
 
972
        web_ball = web_base + '.tar.gz'
 
973
        env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
 
974
        web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
 
975
        web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"') + '-or -type l'
 
976
        env['web_path'] = web_path
 
977
        web_list = os.path.join (outdir, 'weblist')
 
978
        # compatible make heritits
 
979
        # fixme: generate in $outdir is cwd/builddir
 
980
        env.Command (web_list,
 
981
                     ## Adding 'doc' dependency is correct, but takes
 
982
                     ## > 5min extra if you have a peder :-)
 
983
                     #'doc',
 
984
                     
 
985
                     '#/VERSION',
 
986
                     ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
 
987
                      'cd $absbuild && $footify $$(find . -name "*.html" -print)',
 
988
                      'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
 
989
                      'cd $absbuild && find Documentation input $web_path \
 
990
                      > $TARGET',
 
991
                      '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
 
992
                      '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
 
993
                      'cd $absbuild && ls *.html >> $TARGET',])
 
994
        env.Command (web_ball, web_list,
 
995
                     ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
 
996
        #env.Alias ('web', web_ball)
 
997
        www_base = os.path.join (outdir, 'www')
 
998
        www_ball = www_base + '.tar.gz'
 
999
        env.Command (www_ball, web_ball,
 
1000
                     ['rm -rf $out/tmp',
 
1001
                      'mkdir -p $absbuild/$out/tmp',
 
1002
                      'tar -C $absbuild/$out/tmp -xzf $SOURCE',
 
1003
                      'cd $absbuild/$out/tmp && for i in $$(find . -name "$out"); '
 
1004
                      + ' do mv $$i $$(dirname $$i)/out-www; done',
 
1005
                      'tar -C $absbuild/$out/tmp -czf $TARGET .'])
 
1006
        env.Alias ('web', www_ball)
 
1007
 
 
1008
#### tags
 
1009
env.Append (
 
1010
        ETAGSFLAGS = """--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\\1/' \
 
1011
        --regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\\1/'""")
 
1012
code_ext = ['.cc', '.hh', '.scm', '.tcc',]
 
1013
env.Command ('TAGS', filter (lambda x: os.path.splitext (x)[1] in code_ext,
 
1014
                             src_files),
 
1015
             'etags $ETAGSFLAGS $SOURCES')
 
1016
 
 
1017
# Note: SConscripts are only needed in directories where something needs
 
1018
# to be done, building or installing
 
1019
for d in subdirs:
 
1020
        if os.path.exists (os.path.join (d, 'SConscript')):
 
1021
                b = os.path.join (env['build'], d, env['out'])
 
1022
                # Support clean sourcetree build (--srcdir build)
 
1023
                # and ./out build.
 
1024
                if os.path.abspath (b) != os.path.abspath (d):
 
1025
                        env.BuildDir (b, d, duplicate = 0)
 
1026
                SConscript (os.path.join (b, 'SConscript'))
 
1027