* scm/define-grobs.scm: switch on new-slur by default.
[lilypond.git] / SConstruct
blobce0c1244398409a2593a1ee41d57587de8f7aa3a
1 # -*-python-*-
3 '''
4 Experimental scons (www.scons.org) building.
6 Usage
8 scons TARGET
10 build from source directory ./TARGET (not recursive)
12 Configure, build
14 scons [config] # configure
15 scons # build all
17 Run from build tree
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
24 #optionally, if you do not use custom.py below
25 #export LILYPONDPREFIX=$run/share/lilypond
27 lilypond-bin input/simple
29 Other targets
30 scons mf-essential # build minimal mf stuff
32 scons doc # build web doc
33 scons config # reconfigure
34 scons install # install
35 scons -c # clean
36 scons -h # help
38 scons / # build *everything* (including installation)
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
44 Debugging
45 scons --debug=dtree
46 scons --debug=explain
47 scons verbose=1
49 Optional custom.py
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')
59 '''
62 # TODO:
63 # * install doc
65 # * more program configure tests (mfont, ...?)
67 # * split doc target: doc input examples mutopia?
69 # * more fine-grained config.hh -- move lilypondprefix to version.hh?
70 # - config.hh: changes after system upgrades, affects all files
71 # - version.hh: prefix, version etc? affects few
73 # - what about GUILE_*_VERSION, seems to be the major culprit,
74 # for config.hh dependency escalation. Is the lily-guile.hh
75 # workaround necessary at all for GUILE > 1.5?
77 # * grep FIXME $(find . -name 'S*t')
80 import re
81 import glob
82 import os
83 import string
84 import sys
85 import stat
86 import shutil
88 # duh, we need 0.95.1
89 EnsureSConsVersion (0, 95)
91 usage = r'''Usage:
92 scons [KEY=VALUE].. [TARGET|DIR]..
94 TARGETS: clean, config, doc, dist, install, mf-essential, po-update,
95 realclean, release, tar, TAGS
97 '''
100 config_cache = 'scons.cache'
102 config_vars = [
103 'BASH',
104 'CCFLAGS',
105 'CPPPATH',
106 'CPPDEFINES',
107 'CXXFLAGS',
108 'DEFINES',
109 'LIBS',
110 'LINKFLAGS',
111 'METAFONT',
112 'PERL',
113 'PYTHON',
116 # Put your favourite stuff in custom.py
117 opts = Options ([config_cache, 'custom.py'], ARGUMENTS)
118 opts.Add ('prefix', 'Install prefix', '/usr/')
119 opts.Add ('out', 'Output directory', 'out-scons')
120 opts.Add ('build', 'Build directory', '.')
121 opts.Add ('DESTDIR', 'DESTDIR prepended to prefix', '')
122 opts.AddOptions (
123 BoolOption ('warnings', 'compile with -Wall and similiar',
125 BoolOption ('debugging', 'compile with debugging symbols',
127 BoolOption ('optimising', 'compile with optimising',
129 BoolOption ('shared', 'build shared libraries',
131 BoolOption ('static', 'build static libraries',
133 BoolOption ('gui', 'build with GNOME backend (EXPERIMENTAL)',
135 BoolOption ('verbose', 'run commands with verbose flag',
137 BoolOption ('checksums', 'use checksums instead of timestamps',
141 srcdir = Dir ('.').srcnode ().abspath
142 #ugh
143 sys.path.append (os.path.join (srcdir, 'stepmake', 'bin'))
144 import packagepython
145 package = packagepython.Package (srcdir)
146 version = packagepython.version_tuple_to_str (package.version)
148 ENV = { 'PATH' : os.environ['PATH'] }
149 for key in ['LD_LIBRARY_PATH', 'GUILE_LOAD_PATH', 'PKG_CONFIG_PATH']:
150 if os.environ.has_key (key):
151 ENV[key] = os.environ[key]
153 env = Environment (
154 ENV = ENV,
156 BASH = '/bin/bash',
157 PERL = '/usr/bin/perl',
158 PYTHON = '/usr/bin/python',
159 SH = '/bin/sh',
161 MAKEINFO = 'LANG= makeinfo',
162 MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
164 PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
165 'usr/pkg/gnome/lib'),
166 os.path.join (os.environ['HOME'],
167 'usr/pkg/pango/lib')],
168 GZIP='-9v',
169 MFMODE = 'ljfour',
170 TOPLEVEL_VERSION = version,
173 # Add all config_vars to opts, so that they will be read and saved
174 # together with the other configure options.
175 map (lambda x: opts.AddOptions ((x,)), config_vars)
177 Help (usage + opts.GenerateHelpText (env))
179 opts.Update (env)
181 # Using content checksums prevents rebuilds after [re]configure if
182 # config.hh has not changed.
183 if env['checksums']:
184 SetOption ('max_drift', 0)
185 TargetSignatures ("content")
187 absbuild = Dir (env['build']).abspath
188 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
189 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
192 config_hh = os.path.join (outdir, 'config.hh')
193 version_hh = os.path.join (outdir, 'version.hh')
195 env.Alias ('config', config_cache)
198 CacheDir (os.path.join (outdir, 'build-cache'))
200 # No need to set $LILYPONDPREFIX to run lily, but cannot install...
201 if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
202 env['prefix'] = run_prefix
204 prefix = env['prefix']
205 bindir = os.path.join (prefix, 'bin')
206 sharedir = os.path.join (prefix, 'share')
207 libdir = os.path.join (prefix, 'lib')
208 localedir = os.path.join (sharedir, 'locale')
209 sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
210 sharedir_package = os.path.join (sharedir, package.name)
211 sharedir_package_version = os.path.join (sharedir_package, version)
212 lilypondprefix = sharedir_package_version
214 # junkme
215 env.Append (
216 absbuild = absbuild,
217 srcdir = srcdir,
221 def list_sort (lst):
222 sorted = lst
223 sorted.sort ()
224 return sorted
227 def configure (target, source, env):
228 vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
229 def get_version (program):
230 command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
231 pipe = os.popen (command)
232 output = pipe.read ()
233 if pipe.close ():
234 return None
235 v = re.sub (vre, '\\1', output)
236 return string.split (v, '.')
238 def test_program (lst, program, minimal, description, package):
239 sys.stdout.write ('Checking %s version... ' % program)
240 actual = get_version (program)
241 if not actual:
242 print 'not found'
243 lst.append ((description, package, minimal, program,
244 'not installed'))
245 return
246 sys.stdout.write (string.join (actual, '.'))
247 sys.stdout.write ('\n')
248 if actual < string.split (minimal, '.'):
249 lst.append ((description, package, minimal, program,
250 string.join (actual, '.')))
252 for i in ['bash', 'perl', 'python', 'sh']:
253 sys.stdout.write ('Checking for %s... ' % i)
254 c = WhereIs (i)
255 key = string.upper (i)
256 if c:
257 env[key] = c
258 sys.stdout.write (c)
259 else:
260 sys.stdout.write ('not found: %s (using: %s)' \
261 % (c, env[key]))
262 # Hmm? abort?
263 sys.stdout.write ('\n')
265 required = []
266 test_program (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
267 test_program (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
268 test_program (required, 'python', '2.1', 'Python (www.python.org)', 'python')
269 test_program (required, 'guile-config', '1.6', 'GUILE development',
270 'libguile-dev or guile-devel')
271 # Do not use bison 1.50 and 1.75.
272 test_program (required, 'bison', '1.25', 'Bison -- parser generator',
273 'bison')
274 test_program (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
277 optional = []
278 test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
279 test_program (optional, 'guile', '1.6', 'GUILE scheme',
280 'libguile-dev or guile-devel')
281 test_program (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
282 'mftrace')
283 test_program (optional, 'perl', '4.0',
284 'Perl practical efficient readonly language', 'perl')
285 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
287 def CheckYYCurrentBuffer (context):
288 context.Message ('Checking for yy_current_buffer... ')
289 ret = conf.TryCompile ("""using namespace std;
290 #include <FlexLexer.h>
291 class yy_flex_lexer: public yyFlexLexer
293 public:
294 yy_flex_lexer ()
296 yy_current_buffer = 0;
298 };""", '.cc')
299 context.Result (ret)
300 return ret
302 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
303 : CheckYYCurrentBuffer })
305 defines = {
306 'DIRSEP' : "'%s'" % os.sep,
307 'PATHSEP' : "'%s'" % os.pathsep,
308 'TOPLEVEL_VERSION' : '"' + version + '"',
309 'PACKAGE': '"' + package.name + '"',
310 'DATADIR' : '"' + sharedir + '"',
311 'LILYPOND_DATADIR' : '"' + sharedir_package + '"',
312 'LOCAL_LILYPOND_DATADIR' : '"' + sharedir_package_version + '"',
313 'LOCALEDIR' : '"' + localedir + '"',
315 conf.env.Append (DEFINES = defines)
317 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
318 PYTHON_INCLUDE = os.popen (command).read ()
319 env.Append (CPPPATH = PYTHON_INCLUDE)
321 headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
322 for i in headers:
323 if conf.CheckCHeader (i):
324 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
325 conf.env['DEFINES'][key] = 1
327 ccheaders = ('sstream',)
328 for i in ccheaders:
329 if conf.CheckCXXHeader (i):
330 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
331 conf.env['DEFINES'][key] = 1
333 functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
334 for i in functions:
335 if 0 or conf.CheckFunc (i):
336 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
337 conf.env['DEFINES'][key] = 1
339 if conf.CheckYYCurrentBuffer ():
340 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
342 if conf.CheckLib ('dl'):
343 pass
345 if conf.CheckLib ('kpathsea'):
346 conf.env['DEFINES']['KPATHSEA'] = 1
348 # huh?
349 if conf.CheckLib ('kpathsea', 'kpse_find_file'):
350 conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
351 if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
352 conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
354 #this could happen after flower...
355 env.ParseConfig ('guile-config compile')
357 #this could happen only for compiling pango-*
358 if env['gui']:
359 env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
360 env.ParseConfig ('pkg-config --cflags --libs pango')
361 if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
362 conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
364 if conf.CheckLib ('pango-1.0',
365 'pango_fc_font_map_add_decoder_find_func'):
366 conf.env['DEFINES']['HAVE_PANGO_CVS'] = '1'
367 conf.env['DEFINES']['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
369 if required:
370 print
371 print '********************************'
372 print 'Please install required packages'
373 for i in required:
374 print '%s: %s-%s or newer (found: %s %s)' % i
375 Exit (1)
377 if optional:
378 print
379 print '*************************************'
380 print 'Consider installing optional packages'
381 for i in optional:
382 print '%s: %s-%s or newer (found: %s %s)' % i
384 return conf.Finish ()
386 def config_header (target, source, env):
387 config = open (str (target[0]), 'w')
388 for i in list_sort (env['DEFINES'].keys ()):
389 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
390 config.close ()
391 env.Command (config_hh, config_cache, config_header)
393 # hmm?
394 def xuniquify (lst):
395 n = []
396 for i in lst:
397 if not i in n:
398 n.append (i)
399 lst = n
400 return lst
402 def uniquify (lst):
403 d = {}
404 n = len (lst)
405 i = 0
406 while i < n:
407 if not d.has_key (lst[i]):
408 d[lst[i]] = 1
409 i += 1
410 else:
411 del lst[i]
412 n -= 1
413 return lst
415 def uniquify_config_vars (env):
416 for i in config_vars:
417 if env.has_key (i) and type (env[i]) == type ([]):
418 env[i] = uniquify (env[i])
420 def save_config_cache (env):
421 ## FIXME: Is this smart, using option cache for saving
422 ## config.cache? I cannot seem to find the official method.
423 uniquify_config_vars (env)
424 opts.Save (config_cache, env)
426 if 'config' in COMMAND_LINE_TARGETS:
427 sys.stdout.write ('\n')
428 sys.stdout.write ('LilyPond configured')
429 sys.stdout.write ('\n')
430 sys.stdout.write ('now run')
431 sys.stdout.write ('\n')
432 sys.stdout.write (' scons [TARGET|DIR]...')
433 sys.stdout.write ('\n')
434 Exit (0)
435 elif not env['checksums']:
436 # When using timestams, config.hh is NEW. The next
437 # build triggers recompilation of everything. Exiting
438 # here makes SCons use the actual timestamp for config.hh
439 # and prevents recompiling everything the next run.
440 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
441 sys.stdout.write ('Running %s ... ' % command)
442 sys.stdout.write ('\n')
443 s = os.system (command)
444 Exit (s)
447 if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
448 os.unlink (config_cache)
449 # WTF?
450 # scons: *** Calling Configure from Builders is not supported.
451 # env.Command (config_cache, None, configure)
452 if not os.path.exists (config_cache) \
453 or (os.stat ('SConstruct')[stat.ST_MTIME]
454 > os.stat (config_cache)[stat.ST_MTIME]):
455 env = configure (None, None, env)
456 save_config_cache (env)
457 elif env['checksums']:
458 # just save everything
459 save_config_cache (env)
461 #urg how does #/ subst work?
462 Export ('env')
463 SConscript ('buildscripts/builder.py')
465 env.PrependENVPath ('PATH',
466 os.path.join (env['absbuild'], env['out'], 'usr/bin'))
468 if os.environ.has_key ('TEXMF'):
469 env.Append (ENV = {'TEXMF' : os.environ['TEXMF']})
470 env.Append (ENV = {'TEXMF' : '{$LILYPONDPREFIX,' \
471 + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}' })
475 BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
476 BUILD_LILYPOND = '${set__x}$PYTHON $srcdir/scripts/lilypond.py${__verbose}'
477 BUILD_LILYPOND_BIN = '$absbuild/$out/lilypond-bin ${__verbose}'
478 BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py --verbose'
481 # post-option environment-update
482 env.Append (
483 bindir = bindir,
484 sharedir = sharedir,
485 lilypond_datadir = sharedir_package,
486 localedir = localedir,
487 local_lilypond_datadir = sharedir_package_version,
488 lilypondprefix = lilypondprefix,
489 sharedir_package = sharedir_package,
490 sharedir_doc_package = sharedir_doc_package,
491 sharedir_package_version = sharedir_package_version,
493 LILYPOND = BUILD_LILYPOND,
494 ABC2LY = BUILD_ABC2LY,
495 LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
496 LILYPOND_BOOK_FORMAT = 'texi-html',
497 MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
499 TEXI2DVI_PAPERSIZE = '@afourpaper',
500 TEXI2DVI_FLAGS = [ '-t $TEXI2DVI_PAPERSIZE'],
501 DVIPS_PAPERSIZE = 'a4',
502 DVIPS_FLAGS = ['-t $DVIPS_PAPERSIZE',
503 '-u+lilypond.map',
504 '-u+ec-mftrace.map'],
505 PSPDF_FLAGS = ['-sPAPERSIZE=$DVIPS_PAPERSIZE'],
508 if env['debugging']:
509 env.Append (CCFLAGS = ['-g', '-pipe'])
510 if env['optimising']:
511 env.Append (CCFLAGS = '-O2')
512 env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
513 if env['warnings']:
514 env.Append (CCFLAGS = ['-W', '-Wall'])
515 env.Append (CXXFLAGS = ['-Wconversion'])
517 # ugr,huh?
518 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
520 if env['verbose']:
521 env['__verbose'] = ' --verbose'
522 env['set__x'] = 'set -x;'
525 ## Explicit target and dependencies
527 if 'clean' in COMMAND_LINE_TARGETS:
528 # ugh: prevent reconfigure instead of clean
529 os.system ('touch %s' % config_cache)
531 command = sys.argv[0] + ' -c .'
532 sys.stdout.write ('Running %s ... ' % command)
533 sys.stdout.write ('\n')
534 s = os.system (command)
535 if os.path.exists (config_cache):
536 os.unlink (config_cache)
537 Exit (s)
539 if 'realclean' in COMMAND_LINE_TARGETS:
540 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
541 sys.stdout.write ('Running %s ... ' % command)
542 sys.stdout.write ('\n')
543 s = os.system (command)
544 if os.path.exists (config_cache):
545 os.unlink (config_cache)
546 Exit (s)
548 # Declare SConscript phonies
549 env.Alias ('minimal', config_cache)
550 env.Alias ('mf-essential', config_cache)
552 env.Alias ('minimal', ['lily', 'mf-essential'])
553 env.Alias ('all', ['minimal', 'mf', '.'])
554 # Do we want the doc/web separation?
555 env.Alias ('doc',
556 ['Documentation',
557 'Documentation/user',
558 'Documentation/topdocs',
559 'Documentation/bibliography',
560 'input'])
562 # Without target arguments, do minimal build
563 if not COMMAND_LINE_TARGETS:
564 env.Default (['minimal'])
566 # GNU Make rerouting compat:
567 env.Alias ('web', 'doc')
570 env.Command (version_hh, '#/VERSION',
571 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
573 # post-config environment update
574 env.Append (
575 run_prefix = run_prefix,
576 LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond'),
578 LIBPATH = [os.path.join (absbuild, 'flower', env['out']),],
579 ##CPPPATH = [outdir, '#',], # do not read auto*'s header
580 CPPPATH = [outdir, ],
581 LILYPOND_PATH = ['.', '$srcdir/input',
582 '$srcdir/input/regression',
583 '$srcdir/input/test',
584 '$srcdir/input/tutorial',
585 '$srcdir/Documentation/user',
586 '$absbuild/mf/$out',
587 # os.path.join (absbuild, 'Documentation',
588 # env['out']),
589 # os.path.join (absbuild, 'Documentation/user',
590 # env['out']),
592 MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
593 '$absbuild/Documentation/user/$out'],
596 def symlink_tree (target, source, env):
597 def mkdirs (dir):
598 def mkdir (dir):
599 if not dir:
600 os.chdir (os.sep)
601 return
602 if not os.path.isdir (dir):
603 if os.path.exists (dir):
604 os.unlink (dir)
605 os.mkdir (dir)
606 os.chdir (dir)
607 map (mkdir, string.split (dir, os.sep))
608 def symlink (src, dst):
609 os.chdir (absbuild)
610 dir = os.path.dirname (dst)
611 mkdirs (dir)
612 if src[0] == '#':
613 frm = os.path.join (srcdir, src[1:])
614 else:
615 depth = len (string.split (dir, '/'))
616 if src.find ('@') > -1:
617 frm = os.path.join ('../' * depth,
618 string.replace (src, '@',
619 env['out']))
620 else:
621 frm = os.path.join ('../' * depth, src,
622 env['out'])
623 if src[-1] == '/':
624 frm = os.path.join (frm, os.path.basename (dst))
625 if env['verbose']:
626 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
627 os.symlink (frm, os.path.basename (dst))
628 shutil.rmtree (run_prefix)
629 prefix = os.path.join (env['out'], 'usr')
630 map (lambda x: symlink (x[0], os.path.join (prefix, x[1])),
631 # ^# := source dir
632 # @ := out
633 # /$ := add dst file_name
634 (('python', 'lib/lilypond/python'),
635 ('lily/', 'bin/lilypond-bin'),
636 ('scripts/', 'bin/lilypond'),
637 ('scripts/', 'bin/lilypond-book'),
638 ('mf', 'share/lilypond/dvips'),
639 ('#ps', 'share/lilypond/tex/music-drawing-routines.ps'),
640 ('mf', 'share/lilypond/afm'),
641 ('mf', 'share/lilypond/tfm'),
642 ('#mf', 'share/lilypond/fonts/mf'),
643 ('mf', 'share/lilypond/fonts/afm'),
644 ('mf', 'share/lilypond/fonts/tfm'),
645 ('mf', 'share/lilypond/fonts/type1'),
646 ('#tex', 'share/lilypond/tex/source'),
647 ('mf', 'share/lilypond/tex/generate'),
648 ('#ly', 'share/lilypond/ly'),
649 ('#scm', 'share/lilypond/scm'),
650 ('#ps', 'share/lilypond/ps'),
651 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
652 ('elisp', 'share/lilypond/elisp')))
653 os.chdir (srcdir)
655 if env['debugging']:
656 stamp = os.path.join (run_prefix, 'stamp')
657 env.Command (stamp, 'SConstruct', [symlink_tree, 'touch $TARGET'])
658 env.Depends ('lily', stamp)
660 #### dist, tar
661 def plus (a, b):
662 a + b
664 def cvs_entry_is_dir (line):
665 return line[0] == 'D' and line[-2] == '/'
667 def cvs_entry_is_file (line):
668 return line[0] == '/' and line[-2] == '/'
670 def cvs_dirs (dir):
671 ENTRIES = os.path.join (dir, 'CVS/Entries')
672 if not os.path.exists (ENTRIES):
673 return []
674 entries = open (ENTRIES).readlines ()
675 dir_entries = filter (cvs_entry_is_dir, entries)
676 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
677 dir_entries)
678 return dirs + map (cvs_dirs, dirs)
680 def cvs_files (dir):
681 ENTRIES = os.path.join (dir, 'CVS/Entries')
682 entries = open (ENTRIES).readlines ()
683 file_entries = filter (cvs_entry_is_file, entries)
684 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
685 return map (lambda x: os.path.join (dir, x), files)
687 def flatten (tree, lst):
688 if type (tree) == type ([]):
689 for i in tree:
690 if type (i) == type ([]):
691 flatten (i, lst)
692 else:
693 lst.append (i)
694 return lst
696 subdirs = flatten (cvs_dirs ('.'), [])
697 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
698 foo = map (lambda x: env.TXT (x + '.txt',
699 os.path.join ('Documentation/topdocs', x)),
700 readme_files)
701 txt_files = map (lambda x: x + '.txt', readme_files)
702 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
703 tar_base = package.name + '-' + version
704 tar_name = tar_base + '.tar.gz'
705 ball_prefix = os.path.join (outdir, tar_base)
706 tar_ball = os.path.join (outdir, tar_name)
708 dist_files = src_files + txt_files
709 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
710 map (lambda x: env.Depends (tar_ball, x), ball_files)
711 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
712 'ln $SOURCE $TARGET'), dist_files)
713 tar = env.Command (tar_ball, src_files,
714 ['rm -f $$(find $TARGET.dir -name .sconsign)',
715 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
716 env.Alias ('tar', tar)
718 dist_ball = os.path.join (package.release_dir, tar_name)
719 env.Command (dist_ball, tar_ball,
720 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
721 + 'ln $SOURCE $TARGET')
722 env.Depends ('dist', dist_ball)
723 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
724 patch = env.PATCH (patch_name, tar_ball)
725 env.Depends (patch_name, dist_ball)
726 env.Alias ('release', patch)
728 #### web
729 web_base = os.path.join (outdir, 'web')
730 web_ball = web_base + '.tar.gz'
731 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
732 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
733 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"')
734 env['web_path'] = web_path
735 web_list = os.path.join (outdir, 'weblist')
736 # compatible make heritits
737 # fixme: generate in $outdir is cwd/builddir
738 env.Command (web_list,
739 ## this is correct, but takes > 5min if you have a peder :-)
740 ##'doc',
741 '#/VERSION',
742 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
743 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
744 # uhg?
745 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
746 'cd $absbuild && find Documentation input $web_path \
747 > $TARGET',
748 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
749 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
750 # UGHR? all .html cruft in cwd goes into the web ball?
751 'cd $absbuild && ls *.html >> $TARGET',])
752 env.Command (web_ball, web_list,
753 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
754 env.Alias ('web', web_ball)
755 env.Alias ('roll-web', web_ball)
757 #### tags
758 env.Append (
759 ETAGSFLAGS = ["""--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\1/'""",
760 """--regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\1/'"""])
761 # filter-out some files?
762 env.Command ('TAGS', src_files, 'etags $ETAGSFLAGS $SOURCES')
765 # Note: SConscripts are only needed in directories where something needs
766 # to be done, building or installing
767 for d in subdirs:
768 if os.path.exists (os.path.join (d, 'SConscript')):
769 b = os.path.join (env['build'], d, env['out'])
770 # Support clean sourcetree build (--srcdir build)
771 # and ./out build.
772 if os.path.abspath (b) != os.path.abspath (d):
773 env.BuildDir (b, d, duplicate = 0)
774 SConscript (os.path.join (b, 'SConscript'))