4 Experimental scons (www.scons.org) building.
10 build from source directory ./TARGET (not recursive)
14 scons [config] # configure
19 run=$(pwd)/out-scons/usr
20 export LOCALE=$run/share/locale
21 export TEXMF='{'$run/share/lilypond,$(kpsexpand '$TEXMF')'}'
24 #optionally, if you do not use custom.py below
25 #export LILYPONDPREFIX=$run/share/lilypond
27 lilypond-bin input/simple
30 scons mf-essential # build minimal mf stuff
32 scons doc # build web doc
33 scons config # reconfigure
34 scons install # install
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
56 os.path.join (os.getcwd (), '=install')
57 prefix=os.path.join (os.environ['HOME'], 'usr', 'pkg', 'lilypond')
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')
89 EnsureSConsVersion (0, 95)
92 scons [KEY=VALUE].. [TARGET|DIR]..
94 TARGETS: clean, config, doc, dist, install, mf-essential, po-update,
95 realclean, release, tar, TAGS
100 config_cache = 'scons.cache'
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', '')
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 sys.path.append (os.path.join (srcdir, 'stepmake', 'bin'))
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]
157 PERL = '/usr/bin/perl',
158 PYTHON = '/usr/bin/python',
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')],
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))
181 # Using content checksums prevents rebuilds after [re]configure if
182 # config.hh has not changed.
184 SetOption ('max_drift', 0)
185 TargetSignatures ("content")
187 # build web in out-www, so that scons is a drop-in replacement for make
188 # we can revise the entire web building when web is built with scons.
190 # Hmm: scons: *** maximum recursion limit exceeded
191 if 0 and 'web' in COMMAND_LINE_TARGETS:
192 web_kluts = 'out-scons' #env['out']
193 env['out'] = 'out-www'
195 absbuild = Dir (env['build']).abspath
196 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
197 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
200 config_hh = os.path.join (outdir, 'config.hh')
201 version_hh = os.path.join (outdir, 'version.hh')
203 env.Alias ('config', config_cache)
206 CacheDir (os.path.join (outdir, 'build-cache'))
208 # No need to set $LILYPONDPREFIX to run lily, but cannot install...
209 if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
210 env['prefix'] = run_prefix
212 prefix = env['prefix']
213 bindir = os.path.join (prefix, 'bin')
214 sharedir = os.path.join (prefix, 'share')
215 libdir = os.path.join (prefix, 'lib')
216 localedir = os.path.join (sharedir, 'locale')
217 sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
218 sharedir_package = os.path.join (sharedir, package.name)
219 sharedir_package_version = os.path.join (sharedir_package, version)
220 lilypondprefix = sharedir_package_version
235 def configure (target, source, env):
236 vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
237 def get_version (program):
238 command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
239 pipe = os.popen (command)
240 output = pipe.read ()
243 v = re.sub (vre, '\\1', output)
244 return string.split (v, '.')
246 def test_program (lst, program, minimal, description, package):
247 sys.stdout.write ('Checking %s version... ' % program)
248 actual = get_version (program)
251 lst.append ((description, package, minimal, program,
254 sys.stdout.write (string.join (actual, '.'))
255 sys.stdout.write ('\n')
256 if actual < string.split (minimal, '.'):
257 lst.append ((description, package, minimal, program,
258 string.join (actual, '.')))
260 for i in ['bash', 'perl', 'python', 'sh']:
261 sys.stdout.write ('Checking for %s... ' % i)
263 key = string.upper (i)
268 sys.stdout.write ('not found: %s (using: %s)' \
271 sys.stdout.write ('\n')
274 test_program (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
275 test_program (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
276 test_program (required, 'python', '2.1', 'Python (www.python.org)', 'python')
277 test_program (required, 'guile-config', '1.6', 'GUILE development',
278 'libguile-dev or guile-devel')
279 # Do not use bison 1.50 and 1.75.
280 test_program (required, 'bison', '1.25', 'Bison -- parser generator',
282 test_program (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
286 test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
287 test_program (optional, 'guile', '1.6', 'GUILE scheme',
288 'libguile-dev or guile-devel')
289 test_program (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
291 test_program (optional, 'perl', '4.0',
292 'Perl practical efficient readonly language', 'perl')
293 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
295 def CheckYYCurrentBuffer (context):
296 context.Message ('Checking for yy_current_buffer... ')
297 ret = conf.TryCompile ("""using namespace std;
298 #include <FlexLexer.h>
299 class yy_flex_lexer: public yyFlexLexer
304 yy_current_buffer = 0;
310 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
311 : CheckYYCurrentBuffer })
314 'DIRSEP' : "'%s'" % os.sep,
315 'PATHSEP' : "'%s'" % os.pathsep,
316 'TOPLEVEL_VERSION' : '"' + version + '"',
317 'PACKAGE': '"' + package.name + '"',
318 'DATADIR' : '"' + sharedir + '"',
319 'LILYPOND_DATADIR' : '"' + sharedir_package + '"',
320 'LOCAL_LILYPOND_DATADIR' : '"' + sharedir_package_version + '"',
321 'LOCALEDIR' : '"' + localedir + '"',
323 conf.env.Append (DEFINES = defines)
325 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
326 PYTHON_INCLUDE = os.popen (command).read ()
327 env.Append (CPPPATH = PYTHON_INCLUDE)
329 headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
331 if conf.CheckCHeader (i):
332 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
333 conf.env['DEFINES'][key] = 1
335 ccheaders = ('sstream',)
337 if conf.CheckCXXHeader (i):
338 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
339 conf.env['DEFINES'][key] = 1
341 functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
343 if 0 or conf.CheckFunc (i):
344 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
345 conf.env['DEFINES'][key] = 1
347 if conf.CheckYYCurrentBuffer ():
348 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
350 if conf.CheckLib ('dl'):
353 if conf.CheckLib ('kpathsea'):
354 conf.env['DEFINES']['KPATHSEA'] = 1
357 if conf.CheckLib ('kpathsea', 'kpse_find_file'):
358 conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
359 if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
360 conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
362 #this could happen after flower...
363 env.ParseConfig ('guile-config compile')
365 #this could happen only for compiling pango-*
367 env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
368 env.ParseConfig ('pkg-config --cflags --libs pango')
369 if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
370 conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
372 if conf.CheckLib ('pango-1.0',
373 'pango_fc_font_map_add_decoder_find_func'):
374 conf.env['DEFINES']['HAVE_PANGO_CVS'] = '1'
375 conf.env['DEFINES']['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
379 print '********************************'
380 print 'Please install required packages'
382 print '%s: %s-%s or newer (found: %s %s)' % i
387 print '*************************************'
388 print 'Consider installing optional packages'
390 print '%s: %s-%s or newer (found: %s %s)' % i
392 return conf.Finish ()
394 def config_header (target, source, env):
395 config = open (str (target[0]), 'w')
396 for i in list_sort (env['DEFINES'].keys ()):
397 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
399 env.Command (config_hh, config_cache, config_header)
415 if not d.has_key (lst[i]):
423 def uniquify_config_vars (env):
424 for i in config_vars:
425 if env.has_key (i) and type (env[i]) == type ([]):
426 env[i] = uniquify (env[i])
428 def save_config_cache (env):
429 ## FIXME: Is this smart, using option cache for saving
430 ## config.cache? I cannot seem to find the official method.
431 uniquify_config_vars (env)
432 opts.Save (config_cache, env)
434 if 'config' in COMMAND_LINE_TARGETS:
435 sys.stdout.write ('\n')
436 sys.stdout.write ('LilyPond configured')
437 sys.stdout.write ('\n')
438 sys.stdout.write ('now run')
439 sys.stdout.write ('\n')
440 sys.stdout.write (' scons [TARGET|DIR]...')
441 sys.stdout.write ('\n')
443 elif not env['checksums']:
444 # When using timestams, config.hh is NEW. The next
445 # build triggers recompilation of everything. Exiting
446 # here makes SCons use the actual timestamp for config.hh
447 # and prevents recompiling everything the next run.
448 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
449 sys.stdout.write ('Running %s ... ' % command)
450 sys.stdout.write ('\n')
451 s = os.system (command)
455 if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
456 os.unlink (config_cache)
458 # scons: *** Calling Configure from Builders is not supported.
459 # env.Command (config_cache, None, configure)
460 if not os.path.exists (config_cache) \
461 or (os.stat ('SConstruct')[stat.ST_MTIME]
462 > os.stat (config_cache)[stat.ST_MTIME]):
463 env = configure (None, None, env)
464 save_config_cache (env)
465 elif env['checksums']:
466 # just save everything
467 save_config_cache (env)
469 #urg how does #/ subst work?
471 SConscript ('buildscripts/builder.py')
473 env.PrependENVPath ('PATH',
474 os.path.join (env['absbuild'], env['out'], 'usr/bin'))
476 if os.environ.has_key ('TEXMF'):
477 env.Append (ENV = {'TEXMF' : os.environ['TEXMF']})
479 'TEXMF' : '{$LILYPONDPREFIX,' \
480 + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}',
481 'LILYPONDPREFIX' : os.path.join (run_prefix, 'share/lilypond'),
484 BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
485 BUILD_LILYPOND = '${set__x}$PYTHON $srcdir/scripts/lilypond.py${__verbose}'
486 BUILD_LILYPOND_BIN = '$absbuild/$out/lilypond-bin ${__verbose}'
487 BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py --verbose'
490 # post-option environment-update
494 lilypond_datadir = sharedir_package,
495 localedir = localedir,
496 local_lilypond_datadir = sharedir_package_version,
497 lilypondprefix = lilypondprefix,
498 sharedir_package = sharedir_package,
499 sharedir_doc_package = sharedir_doc_package,
500 sharedir_package_version = sharedir_package_version,
502 LILYPOND = BUILD_LILYPOND,
503 ABC2LY = BUILD_ABC2LY,
504 LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
505 LILYPOND_BOOK_FORMAT = 'texi-html',
506 MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
508 TEXI2DVI_PAPERSIZE = '@afourpaper',
509 TEXI2DVI_FLAGS = [ '-t $TEXI2DVI_PAPERSIZE'],
510 DVIPS_PAPERSIZE = 'a4',
511 DVIPS_FLAGS = ['-t $DVIPS_PAPERSIZE',
513 '-u+ec-mftrace.map'],
514 PSPDF_FLAGS = ['-sPAPERSIZE=$DVIPS_PAPERSIZE'],
518 env.Append (CCFLAGS = ['-g', '-pipe'])
519 if env['optimising']:
520 env.Append (CCFLAGS = '-O2')
521 env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
523 env.Append (CCFLAGS = ['-W', '-Wall'])
524 env.Append (CXXFLAGS = ['-Wconversion'])
527 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
530 env['__verbose'] = ' --verbose'
531 env['set__x'] = 'set -x;'
534 ## Explicit target and dependencies
536 if 'clean' in COMMAND_LINE_TARGETS:
537 # ugh: prevent reconfigure instead of clean
538 os.system ('touch %s' % config_cache)
540 command = sys.argv[0] + ' -c .'
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)
548 if 'realclean' in COMMAND_LINE_TARGETS:
549 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
550 sys.stdout.write ('Running %s ... ' % command)
551 sys.stdout.write ('\n')
552 s = os.system (command)
553 if os.path.exists (config_cache):
554 os.unlink (config_cache)
557 # Declare SConscript phonies
558 env.Alias ('minimal', config_cache)
559 env.Alias ('mf-essential', config_cache)
561 env.Alias ('minimal', ['lily', 'mf-essential'])
562 env.Alias ('all', ['minimal', 'mf', '.'])
563 # Do we want the doc/web separation?
566 'Documentation/user',
567 'Documentation/topdocs',
568 'Documentation/bibliography',
571 # Without target arguments, do minimal build
572 if not COMMAND_LINE_TARGETS:
573 env.Default (['minimal'])
575 # GNU Make rerouting compat:
576 env.Alias ('web', 'doc')
579 env.Command (version_hh, '#/VERSION',
580 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
582 # post-config environment update
584 run_prefix = run_prefix,
585 LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond'),
587 LIBPATH = [os.path.join (absbuild, 'flower', env['out']),],
588 ##CPPPATH = [outdir, '#',], # do not read auto*'s header
589 CPPPATH = [outdir, ],
590 LILYPOND_PATH = ['.', '$srcdir/input',
591 '$srcdir/input/regression',
592 '$srcdir/input/test',
593 '$srcdir/input/tutorial',
594 '$srcdir/Documentation/user',
596 # os.path.join (absbuild, 'Documentation',
598 # os.path.join (absbuild, 'Documentation/user',
601 MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
602 '$absbuild/Documentation/user/$out'],
605 def symlink_tree (target, source, env):
611 if not os.path.isdir (dir):
612 if os.path.exists (dir):
616 map (mkdir, string.split (dir, os.sep))
617 def symlink (src, dst):
619 dir = os.path.dirname (dst)
622 frm = os.path.join (srcdir, src[1:])
624 depth = len (string.split (dir, '/'))
625 if src.find ('@') > -1:
626 frm = os.path.join ('../' * depth,
627 string.replace (src, '@',
630 frm = os.path.join ('../' * depth, src,
633 frm = os.path.join (frm, os.path.basename (dst))
635 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
636 os.symlink (frm, os.path.basename (dst))
637 shutil.rmtree (run_prefix)
638 prefix = os.path.join (env['out'], 'usr')
639 map (lambda x: symlink (x[0], os.path.join (prefix, x[1])),
642 # /$ := add dst file_name
643 (('python', 'lib/lilypond/python'),
644 ('lily/', 'bin/lilypond-bin'),
645 ('scripts/', 'bin/lilypond'),
646 ('scripts/', 'bin/lilypond-book'),
647 ('mf', 'share/lilypond/dvips'),
648 ('#ps', 'share/lilypond/tex/music-drawing-routines.ps'),
649 ('mf', 'share/lilypond/afm'),
650 ('mf', 'share/lilypond/tfm'),
651 ('#mf', 'share/lilypond/fonts/mf'),
652 ('mf', 'share/lilypond/fonts/afm'),
653 ('mf', 'share/lilypond/fonts/tfm'),
654 ('mf', 'share/lilypond/fonts/type1'),
655 ('#tex', 'share/lilypond/tex/source'),
656 ('mf', 'share/lilypond/tex/generate'),
657 ('#ly', 'share/lilypond/ly'),
658 ('#scm', 'share/lilypond/scm'),
659 ('#ps', 'share/lilypond/ps'),
660 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
661 ('elisp', 'share/lilypond/elisp')))
665 stamp = os.path.join (run_prefix, 'stamp')
666 env.Command (stamp, 'SConstruct', [symlink_tree, 'touch $TARGET'])
667 env.Depends ('lily', stamp)
673 def cvs_entry_is_dir (line):
674 return line[0] == 'D' and line[-2] == '/'
676 def cvs_entry_is_file (line):
677 return line[0] == '/' and line[-2] == '/'
680 ENTRIES = os.path.join (dir, 'CVS/Entries')
681 if not os.path.exists (ENTRIES):
683 entries = open (ENTRIES).readlines ()
684 dir_entries = filter (cvs_entry_is_dir, entries)
685 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
687 return dirs + map (cvs_dirs, dirs)
690 ENTRIES = os.path.join (dir, 'CVS/Entries')
691 entries = open (ENTRIES).readlines ()
692 file_entries = filter (cvs_entry_is_file, entries)
693 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
694 return map (lambda x: os.path.join (dir, x), files)
696 def flatten (tree, lst):
697 if type (tree) == type ([]):
699 if type (i) == type ([]):
705 subdirs = flatten (cvs_dirs ('.'), [])
706 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
707 foo = map (lambda x: env.TXT (x + '.txt',
708 os.path.join ('Documentation/topdocs', x)),
710 txt_files = map (lambda x: x + '.txt', readme_files)
711 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
712 tar_base = package.name + '-' + version
713 tar_name = tar_base + '.tar.gz'
714 ball_prefix = os.path.join (outdir, tar_base)
715 tar_ball = os.path.join (outdir, tar_name)
717 dist_files = src_files + txt_files
718 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
719 map (lambda x: env.Depends (tar_ball, x), ball_files)
720 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
721 'ln $SOURCE $TARGET'), dist_files)
722 tar = env.Command (tar_ball, src_files,
723 ['rm -f $$(find $TARGET.dir -name .sconsign)',
724 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
725 env.Alias ('tar', tar)
727 dist_ball = os.path.join (package.release_dir, tar_name)
728 env.Command (dist_ball, tar_ball,
729 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
730 + 'ln $SOURCE $TARGET')
731 env.Depends ('dist', dist_ball)
732 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
733 patch = env.PATCH (patch_name, tar_ball)
734 env.Depends (patch_name, dist_ball)
735 env.Alias ('release', patch)
738 web_base = os.path.join (outdir, 'web')
739 web_ball = web_base + '.tar.gz'
740 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
741 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
742 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"')
743 env['web_path'] = web_path
744 web_list = os.path.join (outdir, 'weblist')
745 # compatible make heritits
746 # fixme: generate in $outdir is cwd/builddir
747 env.Command (web_list,
748 ## this is correct, but takes > 5min if you have a peder :-)
751 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
752 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
754 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
755 'cd $absbuild && find Documentation input $web_path \
757 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
758 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
759 # UGHR? all .html cruft in cwd goes into the web ball?
760 'cd $absbuild && ls *.html >> $TARGET',])
761 env.Command (web_ball, web_list,
762 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
763 env.Alias ('web', web_ball)
764 env.Alias ('roll-web', web_ball)
768 ETAGSFLAGS = ["""--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\1/'""",
769 """--regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\1/'"""])
770 # filter-out some files?
771 env.Command ('TAGS', src_files, 'etags $ETAGSFLAGS $SOURCES')
774 # Note: SConscripts are only needed in directories where something needs
775 # to be done, building or installing
777 if os.path.exists (os.path.join (d, 'SConscript')):
778 b = os.path.join (env['build'], d, env['out'])
779 # Support clean sourcetree build (--srcdir build)
781 if os.path.abspath (b) != os.path.abspath (d):
782 env.BuildDir (b, d, duplicate = 0)
785 env.Repository (os.path.join (env['build'], d,
787 SConscript (os.path.join (b, 'SConscript'))