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/<VERSION>
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 # - 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?
70 # * usability and documentation for "./configure; make" users
72 # * too much cruft in toplevel SConstruct
74 # * (optional) operation without CVS directories, from tarball
76 # * more program configure tests, actually use full executable name
80 # * split doc target: doc input examples mutopia?
82 # * grep FIXME $(find . -name 'S*t')
95 EnsureSConsVersion (0, 96, 92)
98 [ENVVAR=VALUE]... scons [OPTION=VALUE]... [TARGET|DIR]...
100 TARGETS: clean, config, doc, dist, install, mf-essential, po-update,
101 realclean, release, sconsclean, tar, TAGS
103 ENVVARS: BASH, CCFLAGS, CC, CXX, LIBS, PYTHON, SH...
104 (see SConstruct:config_vars)
110 config_cache = 'scons.cache'
111 if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
112 os.unlink (config_cache)
114 # All config_vars can be set as ENVVAR, eg:
116 # CXX=g++-4.0 GS=~/usr/pkg/gs/bin/gs scons config
118 # append test_program variables automagically?
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', '')
150 BoolOption ('warnings', 'compile with -Wall and similiar',
152 BoolOption ('debugging', 'compile with debugging symbols',
154 BoolOption ('optimising', 'compile with optimising',
156 BoolOption ('shared', 'build shared libraries',
158 BoolOption ('static', 'build static libraries',
160 BoolOption ('gui', 'build with GNOME backend (EXPERIMENTAL)',
162 BoolOption ('verbose', 'run commands with verbose flag',
164 BoolOption ('checksums', 'use checksums instead of timestamps',
166 BoolOption ('fast', 'use timestamps, implicit cache, prune CPPPATH',
170 srcdir = Dir ('.').srcnode ().abspath
172 sys.path.append (os.path.join (srcdir, 'stepmake', 'bin'))
176 package = packagepython.Package (srcdir)
177 version = packagepython.version_tuple_to_str (package.version)
179 ENV = { 'PATH' : os.environ['PATH'] }
180 for key in ['LD_LIBRARY_PATH', 'GUILE_LOAD_PATH', 'PKG_CONFIG_PATH', 'TEXMF']:
181 if os.environ.has_key (key):
182 ENV[key] = os.environ[key]
186 BYTEORDER = sys.byteorder.upper (),
189 CPPDEFINES = '-DHAVE_CONFIG_H',
190 MAKEINFO = 'LANG= makeinfo',
191 MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
193 PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
194 'usr/pkg/gnome/lib'),
195 os.path.join (os.environ['HOME'],
196 'usr/pkg/pango/lib')],
199 TOPLEVEL_VERSION = version,
202 Help (usage + opts.GenerateHelpText (env))
204 # Add all config_vars to opts, so that they will be read and saved
205 # together with the other configure options.
206 map (lambda x: opts.AddOptions ((x,)), config_vars)
209 for key in config_vars:
210 if os.environ.has_key (key):
211 env[key] = os.environ[key]
214 # Usability switch (Anthony Roach).
215 # See http://www.scons.org/cgi-bin/wiki/GoFastButton
216 # First do: scons realclean .
218 SetOption ('max_drift', 1)
219 SetOption ('implicit_cache', 1)
220 elif env['checksums']:
221 # Always use checksums (makes more sense than timestamps).
222 SetOption ('max_drift', 0)
223 # Using *content* checksums prevents rebuilds after
224 # [re]configure if config.hh has not changed. Too bad that it
226 TargetSignatures ('content')
228 absbuild = Dir (env['build']).abspath
229 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
230 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
233 config_hh = os.path.join (outdir, 'config.hh')
234 version_hh = os.path.join (outdir, 'version.hh')
236 env.Alias ('config', config_cache)
238 cachedir = os.path.join (outdir, 'build-cache')
240 if not os.path.exists (cachedir):
241 os.makedirs (cachedir)
245 # No need to set $LILYPONDPREFIX to run lily, but cannot install...
246 if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
247 env['prefix'] = run_prefix
249 prefix = env['prefix']
250 bindir = os.path.join (prefix, 'bin')
251 sharedir = os.path.join (prefix, 'share')
252 libdir = os.path.join (prefix, 'lib')
253 libdir_package = os.path.join (libdir, package.name)
254 libdir_package_version = os.path.join (libdir_package, version)
255 localedir = os.path.join (sharedir, 'locale')
256 sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
257 sharedir_package = os.path.join (sharedir, package.name)
258 sharedir_package_version = os.path.join (sharedir_package, version)
259 lilypondprefix = sharedir_package_version
269 def symlink_tree (target, source, env):
275 if not os.path.isdir (dir):
276 if os.path.exists (dir):
280 map (mkdir, string.split (dir, os.sep))
281 def symlink (src, dst):
283 dir = os.path.dirname (dst)
286 frm = os.path.join (srcdir, src[1:])
288 depth = len (string.split (dir, '/'))
289 if src.find ('@') > -1:
290 frm = os.path.join ('../' * depth,
291 string.replace (src, '@',
294 frm = os.path.join ('../' * depth, src,
297 frm = os.path.join (frm, os.path.basename (dst))
299 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
300 os.symlink (frm, os.path.basename (dst))
301 shutil.rmtree (run_prefix)
302 prefix = os.path.join (env['out'], 'usr')
303 map (lambda x: symlink (x[0], os.path.join (prefix,
304 x[1] % {'ver' : version})),
307 # /$ := add dst file_name
308 (('python', 'lib/lilypond/python'),
310 ('python', 'share/lilypond/%(ver)s/python'),
311 ('lily/', 'bin/lilypond'),
312 ('scripts/', 'bin/convert-ly'),
313 ('scripts/', 'bin/lilypond-book'),
314 ('scripts/', 'bin/ps2png'),
315 ('mf', 'share/lilypond/%(ver)s/dvips/mf-out'),
316 ('#ps/music-drawing-routines.ps',
317 'share/lilypond/%(ver)s/tex/music-drawing-routines.ps'),
318 ('mf', 'share/lilypond/%(ver)s/otf'),
319 ('mf', 'share/lilypond/%(ver)s/tfm'),
320 ('tex', 'share/lilypond/%(ver)s/tex/enc'),
321 ('#mf', 'share/lilypond/%(ver)s/fonts/mf'),
322 ('mf', 'share/lilypond/%(ver)s/fonts/map'),
323 ('mf', 'share/lilypond/%(ver)s/fonts/otf'),
324 ('mf', 'share/lilypond/%(ver)s/fonts/tfm'),
325 ('mf', 'share/lilypond/%(ver)s/fonts/type1'),
326 ('#tex', 'share/lilypond/%(ver)s/tex/source'),
327 ('tex', 'share/lilypond/%(ver)s/tex/tex-out'),
328 ('mf', 'share/lilypond/%(ver)s/tex/mf-out'),
329 ('#ly', 'share/lilypond/%(ver)s/ly'),
330 ('#scm', 'share/lilypond/%(ver)s/scm'),
331 ('#scripts', 'share/lilypond/%(ver)s/scripts'),
332 ('#ps', 'share/lilypond/%(ver)s/ps'),
333 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
334 ('elisp', 'share/lilypond/%(ver)s/elisp')))
336 print "FIXME: BARF BARF BARF"
340 prefix = os.path.join (env['out'], 'usr/share/lilypond/%(ver)s/fonts'
342 for ext in ('enc', 'map', 'otf', 'svg', 'tfm', 'pfa'):
343 dir = os.path.join (absbuild, prefix, ext)
344 os.system ('rm -f ' + dir)
347 os.system ('ln -s ../../../../../../../mf/%(out)s/*.%(ext)s .'
351 def configure (target, source, env):
352 dre = re.compile ('\n(200[0-9]{5})')
353 vre = re.compile ('.*?\n[^-.0-9]*([0-9][0-9]*\.[0-9]([.0-9]*[0-9])*)',
355 def get_version (program):
356 command = '(pkg-config --modversion %(program)s || %(program)s --version || %(program)s -V) 2>&1' % vars ()
357 pipe = os.popen (command)
358 output = pipe.read ()
361 splits = re.sub ('^|\s', '\n', output)
362 date_hack = re.sub (dre, '\n0.0.\\1', splits)
363 m = re.match (vre, date_hack)
367 return string.split (v, '.')
369 def test_version (lst, full_name, minimal, description, package):
370 program = os.path.basename (full_name)
371 sys.stdout.write ('Checking %s version... ' % program)
372 actual = get_version (program)
375 lst.append ((description, package, minimal, program,
378 print string.join (actual, '.')
379 if map (string.atoi, actual) \
380 < map (string.atoi, string.split (minimal, '.')):
381 lst.append ((description, package, minimal, program,
382 string.join (actual, '.')))
386 def test_program (lst, program, minimal, description, package):
387 key = program.upper ()
389 key = re.sub ('\+', 'X', key)
390 key = re.sub ('-', '_', key)
391 sys.stdout.write ('Checking for %s ... ' % program)
392 if env.has_key (key):
394 sys.stdout.write ('(cached) ')
396 f = WhereIs (program)
400 lst.append ((description, package, minimal, program,
404 return test_version (lst, program, minimal, description, package)
406 def test_lib (lst, program, minimal, description, package):
407 # FIXME: test for Debian or RPM (or -foo?) based dists
408 # to guess (or get correct!: apt-cache search?)
410 #if os.system ('pkg-config --atleast-version=0 freetype2'):
412 if test_version (lst, program, minimal, description,
413 'lib%(package)s-dev or %(package)s-devel'
415 env.ParseConfig ('pkg-config --cflags --libs %(program)s'
421 test_program (required, 'bash', '2.0', 'Bash', 'bash')
422 test_program (required, 'gcc', '4.0', 'GNU C compiler', 'gcc')
423 test_program (required, 'g++', '4.0.5', 'GNU C++ compiler', 'g++')
424 test_program (required, 'guile-config', '1.8', 'GUILE development',
425 'libguile-dev or guile-devel')
426 test_program (required, 'mf', '0.0', 'Metafont', 'tetex-bin')
427 test_program (required, 'mftrace', '1.1.19',
428 'mftrace (http://xs4all.nl/~hanwen/mftrace)', 'mftrace')
429 test_program (required, 'python', '2.1', 'Python (www.python.org)',
431 # Silly, and breaks with /bin/sh == dash
432 #test_program (required, 'sh', '0.0', 'Bourne shell', 'sh')
435 # Do not use bison 1.50 and 1.75.
436 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
437 test_program (optional, 'bison', '1.25', 'Bison -- parser generator',
439 test_program (optional, 'fontforge', '0.0.20050624', 'FontForge',
441 test_program (optional, 'flex', '0.0', 'Flex -- lexer generator',
443 test_program (optional, 'guile', '1.8', 'GUILE scheme', 'guile')
444 test_program (optional, 'gs', '8.15',
445 'Ghostscript PostScript interpreter',
446 'gs or gs-afpl or gs-esp or gs-gpl')
447 test_program (optional, 'makeinfo', '4.8', 'Makeinfo tool', 'texinfo')
448 test_program (optional, 'perl', '4.0',
449 'Perl practical efficient readonly language', 'perl')
451 def CheckYYCurrentBuffer (context):
452 context.Message ('Checking for yy_current_buffer... ')
453 ret = conf.TryCompile ("""using namespace std;
454 #include <FlexLexer.h>
455 class yy_flex_lexer: public yyFlexLexer
460 yy_current_buffer = 0;
466 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
467 : CheckYYCurrentBuffer })
470 'DIRSEP' : "'%s'" % os.sep,
471 'PATHSEP' : "'%s'" % os.pathsep,
472 'PACKAGE': '"%s"' % package.name,
473 'DATADIR' : '"%s"' % sharedir,
474 'PACKAGE_DATADIR' : '"%s"' % sharedir_package,
475 'LOCALEDIR' : '"%s"' %localedir,
477 conf.env.Append (DEFINES = defines)
479 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
480 PYTHON_INCLUDE = os.popen (command).read ()#[:-1]
482 env.Append (CCFLAGS = ['-I%s' % PYTHON_INCLUDE])
484 env.Append (CPPPATH = [PYTHON_INCLUDE])
486 headers = ('assert.h', 'grp.h', 'libio.h', 'pwd.h',
487 'sys/stat.h', 'utf8/wchar.h', 'wchar.h', 'Python.h')
489 if conf.CheckCHeader (i):
490 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
491 conf.env['DEFINES'][key] = 1
493 ccheaders = ('sstream',)
495 if conf.CheckCXXHeader (i):
496 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
497 conf.env['DEFINES'][key] = 1
499 functions = ('chroot', 'fopencookie', 'funopen',
501 'mbrtowc', 'memmem', 'snprintf', 'vsnprintf', 'wcrtomb')
503 if 0 or conf.CheckFunc (i):
504 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
505 conf.env['DEFINES'][key] = 1
507 if conf.CheckYYCurrentBuffer ():
508 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
510 if conf.CheckLib ('dl'):
515 if env.has_key ('CPPPATH'):
516 cpppath = env['CPPPATH']
518 ## FIXME: linkage, check for libguile.h and scm_boot_guile
519 #this could happen after flower...
520 env.ParseConfig ('guile-config compile')
522 test_program (required, 'pkg-config', '0.9.0',
523 'pkg-config library compile manager', 'pkg-config')
524 if test_lib (required, 'freetype2', '0.0',
525 'Development files for FreeType 2 font engine',
527 conf.env['DEFINES']['HAVE_FREETYPE2'] = '1'
529 if test_lib (required, 'pangoft2', '1.6.0',
530 'Development files for pango, with FreeType2',
532 conf.env['DEFINES']['HAVE_PANGO_FT2'] = '1'
534 if test_lib (optional, 'fontconfig', '2.2.0',
535 'Development files for fontconfig', 'fontconfig1'):
536 conf.env['DEFINES']['HAVE_FONTCONFIG'] = '1'
538 #this could happen only for compiling pango-*
540 test_lib (required, 'gtk+-2.0', '2.4.0',
541 'Development files for GTK+', 'gtk2.0')
544 # Using CCFLAGS = -I<system-dir> rather than CPPPATH = [
545 # <system-dir>] speeds up SCons
546 env['CCFLAGS'] += map (lambda x: '-I' + x,
547 env['CPPPATH'][len (cpppath):])
548 env['CPPPATH'] = cpppath
552 print '********************************'
553 print 'Please install required packages'
555 print '%s: %s-%s or newer (found: %s %s)' % i
560 print '*************************************'
561 print 'Consider installing optional packages'
563 print '%s: %s-%s or newer (found: %s %s)' % i
565 return conf.Finish ()
567 def config_header (target, source, env):
568 config = open (str (target[0]), 'w')
569 for i in sorted (env['DEFINES'].keys ()):
570 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
572 env.Command (config_hh, config_cache, config_header)
588 if not d.has_key (lst[i]):
596 def uniquify_config_vars (env):
597 for i in config_vars:
598 if env.has_key (i) and type (env[i]) == type ([]):
599 env[i] = uniquify (env[i])
601 def save_config_cache (env):
602 ## FIXME: Is this smart, using option cache for saving
603 ## config.cache? I cannot seem to find the official method.
604 uniquify_config_vars (env)
605 opts.Save (config_cache, env)
607 if 'config' in COMMAND_LINE_TARGETS:
608 sys.stdout.write ('\n')
609 sys.stdout.write ('LilyPond configured')
610 sys.stdout.write ('\n')
611 sys.stdout.write ('Now run')
612 sys.stdout.write ('\n')
613 sys.stdout.write (' scons [TARGET|DIR]...')
614 sys.stdout.write ('\n')
615 sys.stdout.write ('\n')
616 sys.stdout.write ('Examples:')
617 sys.stdout.write ('\n')
618 sys.stdout.write (' scons lily # build lilypond')
619 sys.stdout.write ('\n')
620 sys.stdout.write (' scons all # build everything')
621 sys.stdout.write ('\n')
622 sys.stdout.write (' scons doc # build documentation')
623 sys.stdout.write ('\n')
625 ## sys.stdout.write (' scons prefix=/usr DESTDIR=/tmp/pkg all install')
626 ## sys.stdout.write ('\n')
628 elif not env['checksums']:
629 # When using timestams, config.hh is NEW. The next
630 # build triggers recompilation of everything. Exiting
631 # here makes SCons use the actual timestamp for config.hh
632 # and prevents recompiling everything the next run.
633 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
634 sys.stdout.write ('Running %s ... ' % command)
635 sys.stdout.write ('\n')
636 s = os.system (command)
640 # scons: *** Calling Configure from Builders is not supported.
641 # env.Command (config_cache, None, configure)
642 if not os.path.exists (config_cache) \
643 or (os.stat ('SConstruct')[stat.ST_MTIME]
644 > os.stat (config_cache)[stat.ST_MTIME]):
645 env = configure (None, None, env)
646 save_config_cache (env)
647 elif env['checksums']:
648 # just save everything
649 save_config_cache (env)
651 #urg how does #/ subst work?
653 SConscript ('buildscripts/builder.py')
655 env.PrependENVPath ('PATH',
656 os.path.join (env['absbuild'], env['out'], 'usr/bin'))
658 LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond/', version)
660 if not os.path.exists (LILYPONDPREFIX):
661 os.makedirs (LILYPONDPREFIX)
663 env.Command (LILYPONDPREFIX, ['#/SConstruct', '#/VERSION'], symlink_tree)
664 env.Depends ('lily', LILYPONDPREFIX)
667 'LILYPONDPREFIX' : LILYPONDPREFIX,
668 'TEXMF' : '{$LILYPONDPREFIX,'
669 + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}',
672 BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
673 BUILD_LILYPOND = '$absbuild/lily/$out/lilypond ${__verbose}'
674 BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py ${__verbose}'
676 if env['verbose'] and env['verbose'] != '0':
677 env['__verbose'] = ' --verbose'
678 env['set__x'] = 'set -x;'
680 # post-option environment-update
684 lilypond_datadir = sharedir_package,
685 localedir = localedir,
686 local_lilypond_datadir = sharedir_package_version,
687 lilypondprefix = lilypondprefix,
688 sharedir_package = sharedir_package,
689 sharedir_doc_package = sharedir_doc_package,
690 sharedir_package_version = sharedir_package_version,
691 libdir_package = libdir_package,
692 libdir_package_version = libdir_package_version,
694 LILYPOND = BUILD_LILYPOND,
695 ABC2LY = BUILD_ABC2LY,
696 LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
697 LILYPOND_BOOK_FORMAT = 'texi-html',
698 MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
701 env.Append (CCFLAGS = ['-pipe', '-Wno-pmf-conversions'])
703 env.Append (CCFLAGS = ['-g'])
704 if env['optimising']:
705 env.Append (CCFLAGS = '-O2')
707 env.Append (CCFLAGS = ['-W', '-Wall'])
708 env.Append (CXXFLAGS = ['-Wconversion'])
711 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
712 # FIXME: ParseConfig ignores -L flag?
713 env.Append (LINKFLAGS = ['-L/usr/X11R6/lib'])
715 ## Explicit target and dependencies
717 if 'clean' in COMMAND_LINE_TARGETS:
718 # ugh: prevent reconfigure instead of clean
719 os.system ('touch %s' % config_cache)
721 command = sys.argv[0] + ' -c .'
722 sys.stdout.write ('Running %s ... ' % command)
723 sys.stdout.write ('\n')
724 s = os.system (command)
725 if os.path.exists (config_cache):
726 os.unlink (config_cache)
729 if 'sconsclean' in COMMAND_LINE_TARGETS:
730 command = 'rm -rf scons.cache $(find . -name ".scon*")'
731 s = os.system (command)
732 if os.path.exists (config_cache):
733 os.unlink (config_cache)
736 if 'realclean' in COMMAND_LINE_TARGETS:
737 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
738 sys.stdout.write ('Running %s ... ' % command)
739 sys.stdout.write ('\n')
740 s = os.system (command)
741 if os.path.exists (config_cache):
742 os.unlink (config_cache)
745 # Declare SConscript phonies
746 env.Alias ('minimal', config_cache)
749 env.Alias ('mf-essential', config_cache)
750 env.Alias ('minimal', ['python', 'lily', 'mf-essential'])
751 env.Alias ('all', ['minimal', 'mf', '.'])
754 env.Alias ('minimal', ['python', 'lily', 'mf'])
755 env.Alias ('all', ['minimal', '.'])
758 # Do we want the doc/web separation?
762 'Documentation/user',
763 'Documentation/topdocs',
764 'Documentation/bibliography',
767 # Without target arguments, do minimal build
768 if not COMMAND_LINE_TARGETS:
769 env.Default (['minimal'])
771 # GNU Make rerouting compat:
772 env.Alias ('web', 'doc')
775 env.Command (version_hh, '#/VERSION',
776 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
778 # post-config environment update
780 run_prefix = run_prefix,
781 LILYPONDPREFIX = LILYPONDPREFIX,
783 # FIXME: move to lily/SConscript?
784 LIBPATH = [os.path.join (absbuild, 'flower', env['out'])],
785 CPPPATH = [outdir, ],
786 LILYPOND_PATH = ['.',
788 '$srcdir/input/regression',
789 '$srcdir/input/test',
790 '$srcdir/input/tutorial',
791 '$srcdir/Documentation/user',
793 # os.path.join (absbuild, 'Documentation',
795 # os.path.join (absbuild, 'Documentation/user',
798 MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
799 '$absbuild/Documentation/user/$out'],
806 def cvs_entry_is_dir (line):
807 return line[0] == 'D' and line[-2] == '/'
809 def cvs_entry_is_file (line):
810 return line[0] == '/' and line[-2] == '/'
813 entries = os.path.join (dir, 'CVS/Entries')
814 if not os.path.exists (entries):
816 entries = open (entries).readlines ()
817 dir_entries = filter (cvs_entry_is_dir, entries)
818 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
820 return dirs + map (cvs_dirs, dirs)
823 entries = os.path.join (dir, 'CVS/Entries')
824 if not os.path.exists (entries):
826 entries = open (entries).readlines ()
827 file_entries = filter (cvs_entry_is_file, entries)
828 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
829 return map (lambda x: os.path.join (dir, x), files)
831 def flatten (tree, lst):
832 if type (tree) == type ([]):
834 if type (i) == type ([]):
840 if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
841 subdirs = flatten (cvs_dirs ('.'), [])
844 command = 'cd %(srcdir)s \
845 && find . -name SConscript | sed s@/SConscript@@' % vars ()
846 subdirs = string.split (os.popen (command).read ())
849 and 'all' not in COMMAND_LINE_TARGETS\
850 and 'doc' not in COMMAND_LINE_TARGETS\
851 and 'web' not in COMMAND_LINE_TARGETS\
852 and 'install' not in COMMAND_LINE_TARGETS\
853 and 'clean' not in COMMAND_LINE_TARGETS:
854 subdirs = [ 'python',
860 if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
861 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
863 src_files = ['foobar']
865 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
866 txt_files = map (lambda x: x + '.txt', readme_files)
870 # speeds up build by +- 5%
873 foo = map (lambda x: env.TXT (x + '.txt',
874 os.path.join ('Documentation/topdocs', x)),
876 tar_base = package.name + '-' + version
877 tar_name = tar_base + '.tar.gz'
878 ball_prefix = os.path.join (outdir, tar_base)
879 tar_ball = os.path.join (outdir, tar_name)
881 dist_files = src_files + txt_files
882 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
883 map (lambda x: env.Depends (tar_ball, x), ball_files)
884 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
885 'ln $SOURCE $TARGET'), dist_files)
886 tar = env.Command (tar_ball, src_files,
887 ['rm -f $$(find $TARGET.dir -name .sconsign)',
888 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
889 env.Alias ('tar', tar)
891 dist_ball = os.path.join (package.release_dir, tar_name)
892 env.Command (dist_ball, tar_ball,
893 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
894 + 'ln $SOURCE $TARGET')
895 env.Depends ('dist', dist_ball)
896 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
897 patch = env.PATCH (patch_name, tar_ball)
898 env.Depends (patch_name, dist_ball)
899 env.Alias ('release', patch)
903 web_base = os.path.join (outdir, 'web')
904 web_ball = web_base + '.tar.gz'
905 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
906 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
907 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"') + '-or -type l'
908 env['web_path'] = web_path
909 web_list = os.path.join (outdir, 'weblist')
910 # compatible make heritits
911 # fixme: generate in $outdir is cwd/builddir
912 env.Command (web_list,
913 ## Adding 'doc' dependency is correct, but takes
914 ## > 5min extra if you have a peder :-)
918 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
919 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
920 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
921 'cd $absbuild && find Documentation input $web_path \
923 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
924 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
925 'cd $absbuild && ls *.html >> $TARGET',])
926 env.Command (web_ball, web_list,
927 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
928 #env.Alias ('web', web_ball)
929 www_base = os.path.join (outdir, 'www')
930 www_ball = www_base + '.tar.gz'
931 env.Command (www_ball, web_ball,
933 'mkdir -p $absbuild/$out/tmp',
934 'tar -C $absbuild/$out/tmp -xzf $SOURCE',
935 'cd $absbuild/$out/tmp && for i in $$(find . -name "$out"); '
936 + ' do mv $$i $$(dirname $$i)/out-www; done',
937 'tar -C $absbuild/$out/tmp -czf $TARGET .'])
938 env.Alias ('web', www_ball)
942 ETAGSFLAGS = """--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\\1/' \
943 --regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\\1/'""")
944 code_ext = ['.cc', '.hh', '.scm', '.tcc',]
945 env.Command ('TAGS', filter (lambda x: os.path.splitext (x)[1] in code_ext,
947 'etags $ETAGSFLAGS $SOURCES')
949 # Note: SConscripts are only needed in directories where something needs
950 # to be done, building or installing
952 if os.path.exists (os.path.join (d, 'SConscript')):
953 b = os.path.join (env['build'], d, env['out'])
954 # Support clean sourcetree build (--srcdir build)
956 if os.path.abspath (b) != os.path.abspath (d):
957 env.BuildDir (b, d, duplicate = 0)
958 SConscript (os.path.join (b, 'SConscript'))
960 env.Command ('tree', ['#/VERSION', '#/SConstruct'], symlink_tree)