use usescons for using scons.
[lilypond.git] / SConstruct
blobdaa773824cacad0e2ab2ee8ec6b57a76a4b24ae4
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 scrdir 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
143 #ugh
144 sys.path.append (os.path.join (srcdir, 'stepmake', 'bin'))
145 import packagepython
146 package = packagepython.Package (srcdir)
147 version = packagepython.version_tuple_to_str (package.version)
149 ENV = { 'PATH' : os.environ['PATH'] }
150 for key in ['LD_LIBRARY_PATH', 'GUILE_LOAD_PATH', 'PKG_CONFIG_PATH']:
151 if os.environ.has_key (key):
152 ENV[key] = os.environ[key]
154 env = Environment (
155 ENV = ENV,
157 BASH = '/bin/bash',
158 PERL = '/usr/bin/perl',
159 PYTHON = '/usr/bin/python',
160 SH = '/bin/sh',
162 MAKEINFO = 'LANG= makeinfo',
163 ABC2LY_PY = srcdir + '/scripts/abc2ly.py',
164 LILYPOND_BOOK = srcdir + '/scripts/lilypond-book.py',
165 LILYPOND_BOOK_FLAGS = '',
166 LILYPOND_BOOK_FORMAT = 'texi-html',
167 LILYPOND_PY = srcdir + '/scripts/lilypond.py',
168 MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
170 PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
171 'usr/pkg/gnome/lib'),
172 os.path.join (os.environ['HOME'],
173 'usr/pkg/pango/lib')],
174 GZIP='-9v',
175 MFMODE = 'ljfour',
176 TEXINFO_PAPERSIZE_OPTION = '-t @afourpaper',
177 TOPLEVEL_VERSION = version,
180 # Add all config_vars to opts, so that they will be read and saved
181 # together with the other configure options.
182 map (lambda x: opts.AddOptions ((x,)), config_vars)
184 Help (usage + opts.GenerateHelpText (env))
186 opts.Update (env)
188 # Using content checksums prevents rebuilds after [re]configure if
189 # config.hh has not changed.
190 if env['checksums']:
191 SetOption ('max_drift', 0)
192 TargetSignatures ("content")
194 absbuild = Dir (env['build']).abspath
195 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
196 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
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 # post-option environment-update
215 env.Append (
216 srcdir = srcdir,
218 bindir = bindir,
219 sharedir = sharedir,
220 lilypond_datadir = sharedir_package,
221 localedir = localedir,
222 local_lilypond_datadir = sharedir_package_version,
223 lilypondprefix = lilypondprefix,
224 sharedir_package = sharedir_package,
225 sharedir_doc_package = sharedir_doc_package,
226 sharedir_package_version = sharedir_package_version,
229 if env['debugging']:
230 env.Append (CCFLAGS = ['-g', '-pipe'])
231 if env['optimising']:
232 env.Append (CCFLAGS = '-O2')
233 env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
234 if env['warnings']:
235 env.Append (CCFLAGS = ['-W', '-Wall'])
236 env.Append (CXXFLAGS = ['-Wconversion'])
238 # ugr,huh?
239 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
241 if env['verbose']:
242 env['__verbose'] = ' --verbose'
243 env['set__x'] = 'set -x;'
245 config_hh = os.path.join (outdir, 'config.hh')
246 version_hh = os.path.join (outdir, 'version.hh')
248 env.Alias ('config', config_cache)
251 ## Explicit target and dependencies
253 if 'clean' in COMMAND_LINE_TARGETS:
254 # ugh: prevent reconfigure instead of clean
255 os.system ('touch %s' % config_cache)
257 command = sys.argv[0] + ' -c .'
258 sys.stdout.write ('Running %s ... ' % command)
259 sys.stdout.write ('\n')
260 s = os.system (command)
261 if os.path.exists (config_cache):
262 os.unlink (config_cache)
263 Exit (s)
265 if 'realclean' in COMMAND_LINE_TARGETS:
266 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
267 sys.stdout.write ('Running %s ... ' % command)
268 sys.stdout.write ('\n')
269 s = os.system (command)
270 if os.path.exists (config_cache):
271 os.unlink (config_cache)
272 Exit (s)
274 # Declare SConscript phonies
275 env.Alias ('minimal', config_cache)
276 env.Alias ('mf-essential', config_cache)
278 env.Alias ('minimal', ['lily', 'mf-essential'])
279 env.Alias ('all', ['minimal', 'mf', '.'])
280 # Do we want the doc/web separation?
281 env.Alias ('doc',
282 ['Documentation',
283 'Documentation/user',
284 'Documentation/topdocs',
285 'Documentation/bibliography',
286 'input'])
288 # Without target arguments, do minimal build
289 if not COMMAND_LINE_TARGETS:
290 env.Default (['minimal'])
292 # GNU Make rerouting compat:
293 env.Alias ('web', 'doc')
295 def list_sort (lst):
296 sorted = lst
297 sorted.sort ()
298 return sorted
300 def configure (target, source, env):
301 vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
302 def get_version (program):
303 command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
304 pipe = os.popen (command)
305 output = pipe.read ()
306 if pipe.close ():
307 return None
308 v = re.sub (vre, '\\1', output)
309 return string.split (v, '.')
311 def test_program (lst, program, minimal, description, package):
312 sys.stdout.write ('Checking %s version... ' % program)
313 actual = get_version (program)
314 if not actual:
315 print 'not found'
316 lst.append ((description, package, minimal, program,
317 'not installed'))
318 return
319 sys.stdout.write (string.join (actual, '.'))
320 sys.stdout.write ('\n')
321 if actual < string.split (minimal, '.'):
322 lst.append ((description, package, minimal, program,
323 string.join (actual, '.')))
325 for i in ['bash', 'perl', 'python', 'sh']:
326 sys.stdout.write ('Checking for %s... ' % i)
327 c = WhereIs (i)
328 key = string.upper (i)
329 if c:
330 env[key] = c
331 sys.stdout.write (c)
332 else:
333 sys.stdout.write ('not found: %s (using: %s)' \
334 % (c, env[key]))
335 # Hmm? abort?
336 sys.stdout.write ('\n')
338 required = []
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, 'python', '2.1', 'Python (www.python.org)', 'python')
342 test_program (required, 'guile-config', '1.6', 'GUILE development',
343 'libguile-dev or guile-devel')
344 # Do not use bison 1.50 and 1.75.
345 test_program (required, 'bison', '1.25', 'Bison -- parser generator',
346 'bison')
347 test_program (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
350 optional = []
351 test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
352 test_program (optional, 'guile', '1.6', 'GUILE scheme',
353 'libguile-dev or guile-devel')
354 test_program (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
355 'mftrace')
356 test_program (optional, 'perl', '4.0',
357 'Perl practical efficient readonly language', 'perl')
358 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
360 def CheckYYCurrentBuffer (context):
361 context.Message ('Checking for yy_current_buffer... ')
362 ret = conf.TryCompile ("""using namespace std;
363 #include <FlexLexer.h>
364 class yy_flex_lexer: public yyFlexLexer
366 public:
367 yy_flex_lexer ()
369 yy_current_buffer = 0;
371 };""", '.cc')
372 context.Result (ret)
373 return ret
375 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
376 : CheckYYCurrentBuffer })
378 defines = {
379 'DIRSEP' : "'%s'" % os.sep,
380 'PATHSEP' : "'%s'" % os.pathsep,
381 'TOPLEVEL_VERSION' : '"' + version + '"',
382 'PACKAGE': '"' + package.name + '"',
383 'DATADIR' : '"' + sharedir + '"',
384 'LILYPOND_DATADIR' : '"' + sharedir_package + '"',
385 'LOCAL_LILYPOND_DATADIR' : '"' + sharedir_package_version + '"',
386 'LOCALEDIR' : '"' + localedir + '"',
388 conf.env.Append (DEFINES = defines)
390 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
391 PYTHON_INCLUDE = os.popen (command).read ()
392 env.Append (CPPPATH = PYTHON_INCLUDE)
394 headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
395 for i in headers:
396 if conf.CheckCHeader (i):
397 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
398 conf.env['DEFINES'][key] = 1
400 ccheaders = ('sstream',)
401 for i in ccheaders:
402 if conf.CheckCXXHeader (i):
403 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
404 conf.env['DEFINES'][key] = 1
406 functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
407 for i in functions:
408 if 0 or conf.CheckFunc (i):
409 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
410 conf.env['DEFINES'][key] = 1
412 if conf.CheckYYCurrentBuffer ():
413 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
415 if conf.CheckLib ('dl'):
416 pass
418 if conf.CheckLib ('kpathsea'):
419 conf.env['DEFINES']['KPATHSEA'] = 1
421 # huh?
422 if conf.CheckLib ('kpathsea', 'kpse_find_file'):
423 conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
424 if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
425 conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
427 #this could happen after flower...
428 env.ParseConfig ('guile-config compile')
430 #this could happen only for compiling pango-*
431 if env['gui']:
432 env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
433 env.ParseConfig ('pkg-config --cflags --libs pango')
434 if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
435 conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
437 if conf.CheckLib ('pango-1.0',
438 'pango_fc_font_map_add_decoder_find_func'):
439 conf.env['DEFINES']['HAVE_PANGO_CVS'] = '1'
440 conf.env['DEFINES']['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
442 if required:
443 print
444 print '********************************'
445 print 'Please install required packages'
446 for i in required:
447 print '%s: %s-%s or newer (found: %s %s)' % i
448 Exit (1)
450 if optional:
451 print
452 print '*************************************'
453 print 'Consider installing optional packages'
454 for i in optional:
455 print '%s: %s-%s or newer (found: %s %s)' % i
457 return conf.Finish ()
459 def config_header (target, source, env):
460 config = open (str (target[0]), 'w')
461 for i in list_sort (env['DEFINES'].keys ()):
462 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
463 config.close ()
464 env.Command (config_hh, config_cache, config_header)
466 # hmm?
467 def xuniquify (lst):
468 n = []
469 for i in lst:
470 if not i in n:
471 n.append (i)
472 lst = n
473 return lst
475 def uniquify (lst):
476 d = {}
477 n = len (lst)
478 i = 0
479 while i < n:
480 if not d.has_key (lst[i]):
481 d[lst[i]] = 1
482 i += 1
483 else:
484 del lst[i]
485 n -= 1
486 return lst
488 def uniquify_config_vars (env):
489 for i in config_vars:
490 if env.has_key (i) and type (env[i]) == type ([]):
491 env[i] = uniquify (env[i])
493 def save_config_cache (env):
494 ## FIXME: Is this smart, using option cache for saving
495 ## config.cache? I cannot seem to find the official method.
496 uniquify_config_vars (env)
497 opts.Save (config_cache, env)
499 if 'config' in COMMAND_LINE_TARGETS:
500 sys.stdout.write ('\n')
501 sys.stdout.write ('LilyPond configured')
502 sys.stdout.write ('\n')
503 sys.stdout.write ('now run')
504 sys.stdout.write ('\n')
505 sys.stdout.write (' scons [TARGET|DIR]...')
506 sys.stdout.write ('\n')
507 Exit (0)
508 elif not env['checksums']:
509 # When using timestams, config.hh is NEW. The next
510 # build triggers recompilation of everything. Exiting
511 # here makes SCons use the actual timestamp for config.hh
512 # and prevents recompiling everything the next run.
513 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
514 sys.stdout.write ('Running %s ... ' % command)
515 sys.stdout.write ('\n')
516 s = os.system (command)
517 Exit (s)
520 if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
521 os.unlink (config_cache)
522 # WTF?
523 # scons: *** Calling Configure from Builders is not supported.
524 # env.Command (config_cache, None, configure)
525 if not os.path.exists (config_cache) \
526 or (os.stat ('SConstruct')[stat.ST_MTIME]
527 > os.stat (config_cache)[stat.ST_MTIME]):
528 env = configure (None, None, env)
529 save_config_cache (env)
530 elif env['checksums']:
531 # just save everything
532 save_config_cache (env)
534 env.Command (version_hh, '#/VERSION',
535 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
537 # post-config environment update
538 env.Append (
539 absbuild = absbuild,
540 run_prefix = run_prefix,
541 LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond'),
543 LIBPATH = [os.path.join (absbuild, 'flower', env['out']),],
544 ##CPPPATH = [outdir, '#',], # do not read auto*'s header
545 CPPPATH = [outdir, ],
546 LILYPOND_BIN = os.path.join (absbuild, 'lily', env['out'],
547 'lilypond-bin'),
548 LILYPOND_BOOK_PATH = ['.', '#/input', '#/input/regression',
549 '#/input/test', '#/input/tutorial',
550 os.path.join (absbuild, 'mf', env['out']),
551 '#/Documentation/user',
552 os.path.join (absbuild, 'Documentation',
553 env['out']),
554 os.path.join (absbuild, 'Documentation/user',
555 env['out']),
557 MAKEINFO_PATH = ['.', '#/Documentation/user',
558 os.path.join (absbuild, 'Documentation/user',
559 env['out'])],
562 Export ('env')
563 SConscript ('buildscripts/builder.py')
566 def symlink_tree (target, source, env):
567 def mkdirs (dir):
568 def mkdir (dir):
569 if not dir:
570 os.chdir (os.sep)
571 return
572 if not os.path.isdir (dir):
573 if os.path.exists (dir):
574 os.unlink (dir)
575 os.mkdir (dir)
576 os.chdir (dir)
577 map (mkdir, string.split (dir, os.sep))
578 def symlink (src, dst):
579 os.chdir (absbuild)
580 dir = os.path.dirname (dst)
581 mkdirs (dir)
582 if src[0] == '#':
583 frm = os.path.join (srcdir, src[1:])
584 else:
585 depth = len (string.split (dir, '/'))
586 if src.find ('@') > -1:
587 frm = os.path.join ('../' * depth,
588 string.replace (src, '@',
589 env['out']))
590 else:
591 frm = os.path.join ('../' * depth, src,
592 env['out'])
593 if src[-1] == '/':
594 frm = os.path.join (frm, os.path.basename (dst))
595 if env['verbose']:
596 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
597 os.symlink (frm, os.path.basename (dst))
598 shutil.rmtree (run_prefix)
599 prefix = os.path.join (env['out'], 'usr')
600 map (lambda x: symlink (x[0], os.path.join (prefix, x[1])),
601 # ^# := source dir
602 # @ := out
603 # /$ := add dst file_name
604 (('python', 'lib/lilypond/python'),
605 ('lily/', 'bin/lilypond-bin'),
606 ('scripts/', 'bin/lilypond'),
607 ('scripts/', 'bin/lilypond-book'),
608 ('mf', 'share/lilypond/dvips'),
609 ('#ps', 'share/lilypond/tex/music-drawing-routines.ps'),
610 ('mf', 'share/lilypond/afm'),
611 ('mf', 'share/lilypond/tfm'),
612 ('#mf', 'share/lilypond/fonts/mf'),
613 ('mf', 'share/lilypond/fonts/afm'),
614 ('mf', 'share/lilypond/fonts/tfm'),
615 ('mf', 'share/lilypond/fonts/type1'),
616 ('#tex', 'share/lilypond/tex/source'),
617 ('mf', 'share/lilypond/tex/generate'),
618 ('#ly', 'share/lilypond/ly'),
619 ('#scm', 'share/lilypond/scm'),
620 ('#ps', 'share/lilypond/ps'),
621 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
622 ('elisp', 'share/lilypond/elisp')))
623 os.chdir (srcdir)
625 if env['debugging']:
626 stamp = os.path.join (run_prefix, 'stamp')
627 env.Command (stamp, 'SConstruct', [symlink_tree, 'touch $TARGET'])
628 env.Depends ('lily', stamp)
630 #### dist, tar
631 def plus (a, b):
632 a + b
634 def cvs_entry_is_dir (line):
635 return line[0] == 'D' and line[-2] == '/'
637 def cvs_entry_is_file (line):
638 return line[0] == '/' and line[-2] == '/'
640 def cvs_dirs (dir):
641 ENTRIES = os.path.join (dir, 'CVS/Entries')
642 if not os.path.exists (ENTRIES):
643 return []
644 entries = open (ENTRIES).readlines ()
645 dir_entries = filter (cvs_entry_is_dir, entries)
646 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
647 dir_entries)
648 return dirs + map (cvs_dirs, dirs)
650 def cvs_files (dir):
651 ENTRIES = os.path.join (dir, 'CVS/Entries')
652 entries = open (ENTRIES).readlines ()
653 file_entries = filter (cvs_entry_is_file, entries)
654 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
655 return map (lambda x: os.path.join (dir, x), files)
657 def flatten (tree, lst):
658 if type (tree) == type ([]):
659 for i in tree:
660 if type (i) == type ([]):
661 flatten (i, lst)
662 else:
663 lst.append (i)
664 return lst
666 subdirs = flatten (cvs_dirs ('.'), [])
667 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
668 foo = map (lambda x: env.TXT (x + '.txt',
669 os.path.join ('Documentation/topdocs', x)),
670 readme_files)
671 txt_files = map (lambda x: x + '.txt', readme_files)
672 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
673 tar_base = package.name + '-' + version
674 tar_name = tar_base + '.tar.gz'
675 ball_prefix = os.path.join (outdir, tar_base)
676 tar_ball = os.path.join (outdir, tar_name)
678 dist_files = src_files + txt_files
679 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
680 map (lambda x: env.Depends (tar_ball, x), ball_files)
681 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
682 'ln $SOURCE $TARGET'), dist_files)
683 tar = env.Command (tar_ball, src_files,
684 ['rm -f $$(find $TARGET.dir -name .sconsign)',
685 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
686 env.Alias ('tar', tar)
688 dist_ball = os.path.join (package.release_dir, tar_name)
689 env.Command (dist_ball, tar_ball,
690 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
691 + 'ln $SOURCE $TARGET')
692 env.Depends ('dist', dist_ball)
693 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
694 patch = env.PATCH (patch_name, tar_ball)
695 env.Depends (patch_name, dist_ball)
696 env.Alias ('release', patch)
698 #### web
699 web_base = os.path.join (outdir, 'web')
700 web_ball = web_base + '.tar.gz'
701 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
702 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
703 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"')
704 env['web_path'] = web_path
705 web_list = os.path.join (outdir, 'weblist')
706 # compatible make heritits
707 # fixme: generate in $outdir is cwd/builddir
708 env.Command (web_list,
709 ## this is correct, but takes > 5min if you have a peder :-)
710 ##'doc',
711 '#/VERSION',
712 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
713 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
714 # uhg?
715 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
716 'cd $absbuild && find Documentation input $web_path \
717 > $TARGET',
718 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
719 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
720 # UGHR? all .html cruft in cwd goes into the web ball?
721 'cd $absbuild && ls *.html >> $TARGET',])
722 env.Command (web_ball, web_list,
723 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
724 env.Alias ('web', web_ball)
725 env.Alias ('roll-web', web_ball)
727 #### tags
728 env.Append (
729 ETAGSFLAGS = ["""--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\1/'""",
730 """--regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\1/'"""])
731 # filter-out some files?
732 env.Command ('TAGS', src_files, 'etags $ETAGSFLAGS $SOURCES')
735 # Note: SConscripts are only needed in directories where something needs
736 # to be done, building or installing
737 for d in subdirs:
738 if os.path.exists (os.path.join (d, 'SConscript')):
739 b = os.path.join (env['build'], d, env['out'])
740 # Support clean sourcetree build (--srcdir build)
741 # and ./out build.
742 if os.path.abspath (b) != os.path.abspath (d):
743 env.BuildDir (b, d, duplicate = 0)
744 SConscript (os.path.join (b, 'SConscript'))