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 LILYPOND_DATADIR=$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 packagepython.Package (srcdir)
177 packagepython.version_tuple_to_str (package.version)
179 print '*** FIXME: no packagepython. setting version to 1.0'
186 ENV = { 'PYTHONPATH': '' }
187 for key in ['GUILE_LOAD_PATH', 'LD_LIBRARY_PATH', 'PATH', 'PKG_CONFIG_PATH',
188 'PYTHONPATH', 'TEXMF']:
189 if os.environ.has_key (key):
190 ENV[key] = os.environ[key]
192 ENV['PYTHONPATH'] = os.path.join (srcdir, 'python') + ':' + ENV['PYTHONPATH']
196 BYTEORDER = sys.byteorder.upper (),
199 CPPDEFINES = '-DHAVE_CONFIG_H',
200 MAKEINFO = 'LANG= makeinfo',
201 MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
203 PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
204 'usr/pkg/gnome/lib'),
205 os.path.join (os.environ['HOME'],
206 'usr/pkg/pango/lib')],
209 TOPLEVEL_VERSION = version,
212 Help (usage + opts.GenerateHelpText (env))
214 # Add all config_vars to opts, so that they will be read and saved
215 # together with the other configure options.
216 map (lambda x: opts.AddOptions ((x,)), config_vars)
219 for key in config_vars:
220 if os.environ.has_key (key):
221 env[key] = os.environ[key]
224 # Usability switch (Anthony Roach).
225 # See http://www.scons.org/cgi-bin/wiki/GoFastButton
226 # First do: scons realclean .
228 SetOption ('max_drift', 1)
229 SetOption ('implicit_cache', 1)
230 elif env['checksums']:
231 # Always use checksums (makes more sense than timestamps).
232 SetOption ('max_drift', 0)
233 # Using *content* checksums prevents rebuilds after
234 # [re]configure if config.hh has not changed. Too bad that it
236 TargetSignatures ('content')
238 absbuild = Dir (env['build']).abspath
239 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
240 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
243 config_hh = os.path.join (outdir, 'config.hh')
244 version_hh = os.path.join (outdir, 'version.hh')
246 env.Alias ('config', config_cache)
248 cachedir = os.path.join (outdir, 'build-cache')
250 if not os.path.exists (cachedir):
251 os.makedirs (cachedir)
255 # No need to set $LILYPOND_DATADIR to run lily, but cannot install...
256 if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
257 env['prefix'] = run_prefix
259 prefix = env['prefix']
260 bindir = os.path.join (prefix, 'bin')
261 sharedir = os.path.join (prefix, 'share')
262 libdir = os.path.join (prefix, 'lib')
263 libdir_package = os.path.join (libdir, package.name)
264 libdir_package_version = os.path.join (libdir_package, version)
265 localedir = os.path.join (sharedir, 'locale')
266 sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
267 sharedir_package = os.path.join (sharedir, package.name)
268 sharedir_package_version = os.path.join (sharedir_package, version)
269 lilypondprefix = sharedir_package_version
279 def symlink_tree (target, source, env):
285 if not os.path.isdir (dir):
286 if os.path.exists (dir):
290 map (mkdir, string.split (dir, os.sep))
291 def symlink (src, dst):
293 dir = os.path.dirname (dst)
296 frm = os.path.join (srcdir, src[1:])
298 depth = len (string.split (dir, '/'))
299 if src.find ('@') > -1:
300 frm = os.path.join ('../' * depth,
301 string.replace (src, '@',
304 frm = os.path.join ('../' * depth, src,
307 frm = os.path.join (frm, os.path.basename (dst))
309 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
310 os.symlink (frm, os.path.basename (dst))
311 shutil.rmtree (run_prefix)
312 prefix = os.path.join (env['out'], 'usr')
313 map (lambda x: symlink (x[0], os.path.join (prefix,
314 x[1] % {'ver' : version})),
317 # /$ := add dst file_name
318 (('python', 'lib/lilypond/python'),
320 ('python', 'share/lilypond/%(ver)s/python'),
321 ('lily/', 'bin/lilypond'),
322 ('scripts/', 'bin/convert-ly'),
323 ('scripts/', 'bin/lilypond-book'),
324 ('scripts/', 'bin/ps2png'),
325 ('mf', 'share/lilypond/%(ver)s/dvips/mf-out'),
326 ('#ps/music-drawing-routines.ps',
327 'share/lilypond/%(ver)s/tex/music-drawing-routines.ps'),
328 ('mf', 'share/lilypond/%(ver)s/otf'),
329 ('mf', 'share/lilypond/%(ver)s/tfm'),
330 ('tex', 'share/lilypond/%(ver)s/tex/enc'),
331 ('#mf', 'share/lilypond/%(ver)s/fonts/mf'),
332 ('mf', 'share/lilypond/%(ver)s/fonts/map'),
333 ('mf', 'share/lilypond/%(ver)s/fonts/otf'),
334 ('mf', 'share/lilypond/%(ver)s/fonts/tfm'),
335 ('mf', 'share/lilypond/%(ver)s/fonts/type1'),
336 ('#tex', 'share/lilypond/%(ver)s/tex/source'),
337 ('tex', 'share/lilypond/%(ver)s/tex/tex-out'),
338 ('mf', 'share/lilypond/%(ver)s/tex/mf-out'),
339 ('#ly', 'share/lilypond/%(ver)s/ly'),
340 ('#scm', 'share/lilypond/%(ver)s/scm'),
341 ('#scripts', 'share/lilypond/%(ver)s/scripts'),
342 ('#ps', 'share/lilypond/%(ver)s/ps'),
343 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
344 ('elisp', 'share/lilypond/%(ver)s/elisp')))
346 print "FIXME: BARF BARF BARF"
350 prefix = os.path.join (env['out'], 'usr/share/lilypond/%(ver)s/fonts'
352 for ext in ('enc', 'map', 'otf', 'svg', 'tfm', 'pfa'):
353 dir = os.path.join (absbuild, prefix, ext)
354 os.system ('rm -f ' + dir)
357 os.system ('ln -s ../../../../../../../mf/%(out)s/*.%(ext)s .'
361 def configure (target, source, env):
362 dre = re.compile ('\n(200[0-9]{5})')
363 vre = re.compile ('.*?\n[^-.0-9]*([0-9][0-9]*\.[0-9]([.0-9]*[0-9])*)',
365 def get_version (program):
366 command = '(pkg-config --modversion %(program)s || %(program)s --version || %(program)s -V) 2>&1' % vars ()
367 pipe = os.popen (command)
368 output = pipe.read ()
371 splits = re.sub ('^|\s', '\n', output)
372 date_hack = re.sub (dre, '\n0.0.\\1', splits)
373 m = re.match (vre, date_hack)
377 return string.split (v, '.')
379 def test_version (lst, full_name, minimal, description, package):
380 program = os.path.basename (full_name)
381 sys.stdout.write ('Checking %s version... ' % program)
382 actual = get_version (program)
385 lst.append ((description, package, minimal, program,
388 print string.join (actual, '.')
389 if map (string.atoi, actual) \
390 < map (string.atoi, string.split (minimal, '.')):
391 lst.append ((description, package, minimal, program,
392 string.join (actual, '.')))
396 def test_program (lst, program, minimal, description, package):
397 key = program.upper ()
399 key = re.sub ('\+', 'X', key)
400 key = re.sub ('-', '_', key)
401 sys.stdout.write ('Checking for %s ... ' % program)
402 if env.has_key (key):
404 sys.stdout.write ('(cached) ')
406 f = WhereIs (program)
410 lst.append ((description, package, minimal, program,
414 return test_version (lst, program, minimal, description, package)
416 def test_lib (lst, program, minimal, description, package):
417 # FIXME: test for Debian or RPM (or -foo?) based dists
418 # to guess (or get correct!: apt-cache search?)
420 #if os.system ('pkg-config --atleast-version=0 freetype2'):
422 if test_version (lst, program, minimal, description,
423 'lib%(package)s-dev or %(package)s-devel'
425 env.ParseConfig ('pkg-config --cflags --libs %(program)s'
431 test_program (required, 'bash', '2.0', 'Bash', 'bash')
432 test_program (required, 'gcc', '4.0', 'GNU C compiler', 'gcc')
433 test_program (required, 'g++', '4.0.5', 'GNU C++ compiler', 'g++')
434 test_program (required, 'guile-config', '1.8', 'GUILE development',
435 'libguile-dev or guile-devel')
436 test_program (required, 'mf', '0.0', 'Metafont', 'tetex-bin')
437 test_program (required, 'mftrace', '1.1.19',
438 'mftrace (http://xs4all.nl/~hanwen/mftrace)', 'mftrace')
439 test_program (required, 'python', '2.1', 'Python (www.python.org)',
441 # Silly, and breaks with /bin/sh == dash
442 #test_program (required, 'sh', '0.0', 'Bourne shell', 'sh')
445 # Do not use bison 1.50 and 1.75.
446 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
447 test_program (optional, 'bison', '1.25', 'Bison -- parser generator',
449 test_program (optional, 'fontforge', '0.0.20050624', 'FontForge',
451 test_program (optional, 'flex', '0.0', 'Flex -- lexer generator',
453 test_program (optional, 'guile', '1.8', 'GUILE scheme', 'guile')
454 test_program (optional, 'gs', '8.15',
455 'Ghostscript PostScript interpreter',
456 'gs or gs-afpl or gs-esp or gs-gpl')
457 test_program (optional, 'makeinfo', '4.8', 'Makeinfo tool', 'texinfo')
458 test_program (optional, 'perl', '4.0',
459 'Perl practical efficient readonly language', 'perl')
461 def CheckYYCurrentBuffer (context):
462 context.Message ('Checking for yy_current_buffer... ')
463 ret = conf.TryCompile ("""using namespace std;
464 #include <FlexLexer.h>
465 class yy_flex_lexer: public yyFlexLexer
470 yy_current_buffer = 0;
476 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
477 : CheckYYCurrentBuffer })
480 'DIRSEP' : "'%s'" % os.sep,
481 'PATHSEP' : "'%s'" % os.pathsep,
482 'PACKAGE': '"%s"' % package.name,
483 'DATADIR' : '"%s"' % sharedir,
484 'PACKAGE_DATADIR' : '"%s"' % sharedir_package,
485 'LOCALEDIR' : '"%s"' %localedir,
487 conf.env.Append (DEFINES = defines)
489 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
490 PYTHON_INCLUDE = os.popen (command).read ()#[:-1]
492 env.Append (CCFLAGS = ['-I%s' % PYTHON_INCLUDE])
494 env.Append (CPPPATH = [PYTHON_INCLUDE])
496 headers = ('assert.h', 'grp.h', 'libio.h', 'pwd.h',
497 'sys/stat.h', 'utf8/wchar.h', 'wchar.h', 'Python.h')
499 if conf.CheckCHeader (i):
500 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
501 conf.env['DEFINES'][key] = 1
503 ccheaders = ('sstream',)
505 if conf.CheckCXXHeader (i):
506 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
507 conf.env['DEFINES'][key] = 1
509 functions = ('chroot', 'fopencookie', 'funopen',
511 'mbrtowc', 'memmem', 'snprintf', 'vsnprintf', 'wcrtomb')
513 if 0 or conf.CheckFunc (i):
514 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
515 conf.env['DEFINES'][key] = 1
517 if conf.CheckYYCurrentBuffer ():
518 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
520 if conf.CheckLib ('dl'):
525 if env.has_key ('CPPPATH'):
526 cpppath = env['CPPPATH']
528 ## FIXME: linkage, check for libguile.h and scm_boot_guile
529 #this could happen after flower...
530 env.ParseConfig ('guile-config compile')
532 test_program (required, 'pkg-config', '0.9.0',
533 'pkg-config library compile manager', 'pkg-config')
534 if test_lib (required, 'freetype2', '0.0',
535 'Development files for FreeType 2 font engine',
537 conf.env['DEFINES']['HAVE_FREETYPE2'] = '1'
539 if test_lib (required, 'pangoft2', '1.6.0',
540 'Development files for pango, with FreeType2',
542 conf.env['DEFINES']['HAVE_PANGO_FT2'] = '1'
544 if test_lib (optional, 'fontconfig', '2.2.0',
545 'Development files for fontconfig', 'fontconfig1'):
546 conf.env['DEFINES']['HAVE_FONTCONFIG'] = '1'
548 #this could happen only for compiling pango-*
550 test_lib (required, 'gtk+-2.0', '2.4.0',
551 'Development files for GTK+', 'gtk2.0')
554 # Using CCFLAGS = -I<system-dir> rather than CPPPATH = [
555 # <system-dir>] speeds up SCons
556 env['CCFLAGS'] += map (lambda x: '-I' + x,
557 env['CPPPATH'][len (cpppath):])
558 env['CPPPATH'] = cpppath
562 print '********************************'
563 print 'Please install required packages'
565 print '%s: %s-%s or newer (found: %s %s)' % i
570 print '*************************************'
571 print 'Consider installing optional packages'
573 print '%s: %s-%s or newer (found: %s %s)' % i
575 return conf.Finish ()
577 def config_header (target, source, env):
578 config = open (str (target[0]), 'w')
579 for i in sorted (env['DEFINES'].keys ()):
580 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
582 env.Command (config_hh, config_cache, config_header)
598 if not d.has_key (lst[i]):
606 def uniquify_config_vars (env):
607 for i in config_vars:
608 if env.has_key (i) and type (env[i]) == type ([]):
609 env[i] = uniquify (env[i])
611 def save_config_cache (env):
612 ## FIXME: Is this smart, using option cache for saving
613 ## config.cache? I cannot seem to find the official method.
614 uniquify_config_vars (env)
615 opts.Save (config_cache, env)
617 if 'config' in COMMAND_LINE_TARGETS:
618 sys.stdout.write ('\n')
619 sys.stdout.write ('LilyPond configured')
620 sys.stdout.write ('\n')
621 sys.stdout.write ('Now run')
622 sys.stdout.write ('\n')
623 sys.stdout.write (' scons [TARGET|DIR]...')
624 sys.stdout.write ('\n')
625 sys.stdout.write ('\n')
626 sys.stdout.write ('Examples:')
627 sys.stdout.write ('\n')
628 sys.stdout.write (' scons lily # build lilypond')
629 sys.stdout.write ('\n')
630 sys.stdout.write (' scons all # build everything')
631 sys.stdout.write ('\n')
632 sys.stdout.write (' scons doc # build documentation')
633 sys.stdout.write ('\n')
635 ## sys.stdout.write (' scons prefix=/usr DESTDIR=/tmp/pkg all install')
636 ## sys.stdout.write ('\n')
638 elif not env['checksums']:
639 # When using timestams, config.hh is NEW. The next
640 # build triggers recompilation of everything. Exiting
641 # here makes SCons use the actual timestamp for config.hh
642 # and prevents recompiling everything the next run.
643 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
644 sys.stdout.write ('Running %s ... ' % command)
645 sys.stdout.write ('\n')
646 s = os.system (command)
650 # scons: *** Calling Configure from Builders is not supported.
651 # env.Command (config_cache, None, configure)
652 if not os.path.exists (config_cache) \
653 or (os.stat ('SConstruct')[stat.ST_MTIME]
654 > os.stat (config_cache)[stat.ST_MTIME]):
655 env = configure (None, None, env)
656 save_config_cache (env)
657 elif env['checksums']:
658 # just save everything
659 save_config_cache (env)
661 #urg how does #/ subst work?
663 SConscript ('buildscripts/builder.py')
665 env.PrependENVPath ('PATH',
666 os.path.join (env['absbuild'], env['out'], 'usr/bin'))
668 LILYPOND_DATADIR = os.path.join (run_prefix, 'share/lilypond/', version)
670 if not os.path.exists (LILYPOND_DATADIR):
671 os.makedirs (LILYPOND_DATADIR)
673 env.Command (LILYPOND_DATADIR, ['#/SConstruct', '#/VERSION'], symlink_tree)
674 env.Depends ('lily', LILYPOND_DATADIR)
677 'LILYPOND_DATADIR' : LILYPOND_DATADIR,
678 'TEXMF' : '{$LILYPOND_DATADIR,'
679 + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}',
682 BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
683 BUILD_LILYPOND = '$absbuild/lily/$out/lilypond ${__verbose}'
684 BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py ${__verbose}'
686 if env['verbose'] and env['verbose'] != '0':
687 env['__verbose'] = ' --verbose'
688 env['set__x'] = 'set -x;'
690 # post-option environment-update
694 lilypond_datadir = sharedir_package,
695 localedir = localedir,
696 local_lilypond_datadir = sharedir_package_version,
697 lilypondprefix = lilypondprefix,
698 sharedir_package = sharedir_package,
699 sharedir_doc_package = sharedir_doc_package,
700 sharedir_package_version = sharedir_package_version,
701 libdir_package = libdir_package,
702 libdir_package_version = libdir_package_version,
704 LILYPOND = BUILD_LILYPOND,
705 ABC2LY = BUILD_ABC2LY,
706 LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
707 LILYPOND_BOOK_FORMAT = 'texi-html',
708 MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
711 env.Append (CCFLAGS = ['-pipe', '-Wno-pmf-conversions'])
713 env.Append (CCFLAGS = ['-g'])
714 if env['optimising']:
715 env.Append (CCFLAGS = '-O2')
717 env.Append (CCFLAGS = ['-W', '-Wall'])
718 env.Append (CXXFLAGS = ['-Wconversion'])
721 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
722 # FIXME: ParseConfig ignores -L flag?
723 env.Append (LINKFLAGS = ['-L/usr/X11R6/lib'])
725 ## Explicit target and dependencies
727 if 'clean' in COMMAND_LINE_TARGETS:
728 # ugh: prevent reconfigure instead of clean
729 os.system ('touch %s' % config_cache)
731 command = sys.argv[0] + ' -c .'
732 sys.stdout.write ('Running %s ... ' % command)
733 sys.stdout.write ('\n')
734 s = os.system (command)
735 if os.path.exists (config_cache):
736 os.unlink (config_cache)
739 if 'sconsclean' in COMMAND_LINE_TARGETS:
740 command = 'rm -rf scons.cache $(find . -name ".scon*")'
741 s = os.system (command)
742 if os.path.exists (config_cache):
743 os.unlink (config_cache)
746 if 'realclean' in COMMAND_LINE_TARGETS:
747 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
748 sys.stdout.write ('Running %s ... ' % command)
749 sys.stdout.write ('\n')
750 s = os.system (command)
751 if os.path.exists (config_cache):
752 os.unlink (config_cache)
755 # Declare SConscript phonies
756 env.Alias ('minimal', config_cache)
759 env.Alias ('mf-essential', config_cache)
760 env.Alias ('minimal', ['python', 'lily', 'mf-essential'])
761 env.Alias ('all', ['minimal', 'mf', '.'])
764 env.Alias ('minimal', ['python', 'lily', 'mf'])
765 env.Alias ('all', ['minimal', '.'])
768 # Do we want the doc/web separation?
772 'Documentation/user',
773 'Documentation/topdocs',
774 'Documentation/bibliography',
777 # Without target arguments, do minimal build
778 if not COMMAND_LINE_TARGETS:
779 env.Default (['minimal'])
781 # GNU Make rerouting compat:
782 env.Alias ('web', 'doc')
785 env.Command (version_hh, '#/VERSION',
786 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
788 # post-config environment update
790 run_prefix = run_prefix,
791 LILYPOND_DATADIR = LILYPOND_DATADIR,
793 # FIXME: move to lily/SConscript?
794 LIBPATH = [os.path.join (absbuild, 'flower', env['out'])],
795 CPPPATH = [outdir, ],
796 LILYPOND_PATH = ['.',
798 '$srcdir/input/regression',
799 '$srcdir/input/test',
800 '$srcdir/input/tutorial',
801 '$srcdir/Documentation/user',
803 # os.path.join (absbuild, 'Documentation',
805 # os.path.join (absbuild, 'Documentation/user',
808 MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
809 '$absbuild/Documentation/user/$out'],
816 def cvs_entry_is_dir (line):
817 return line[0] == 'D' and line[-2] == '/'
819 def cvs_entry_is_file (line):
820 return line[0] == '/' and line[-2] == '/'
823 entries = os.path.join (dir, 'CVS/Entries')
824 if not os.path.exists (entries):
826 entries = open (entries).readlines ()
827 dir_entries = filter (cvs_entry_is_dir, entries)
828 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
830 return dirs + map (cvs_dirs, dirs)
833 entries = os.path.join (dir, 'CVS/Entries')
834 if not os.path.exists (entries):
836 entries = open (entries).readlines ()
837 file_entries = filter (cvs_entry_is_file, entries)
838 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
839 return map (lambda x: os.path.join (dir, x), files)
841 def flatten (tree, lst):
842 if type (tree) == type ([]):
844 if type (i) == type ([]):
850 if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
851 subdirs = flatten (cvs_dirs ('.'), [])
854 command = 'cd %(srcdir)s \
855 && find . -name SConscript | sed s@/SConscript@@' % vars ()
856 subdirs = string.split (os.popen (command).read ())
859 and 'all' not in COMMAND_LINE_TARGETS\
860 and 'doc' not in COMMAND_LINE_TARGETS\
861 and 'web' not in COMMAND_LINE_TARGETS\
862 and 'install' not in COMMAND_LINE_TARGETS\
863 and 'clean' not in COMMAND_LINE_TARGETS:
864 subdirs = [ 'python',
870 if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
871 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
873 src_files = ['foobar']
875 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
876 txt_files = map (lambda x: x + '.txt', readme_files)
880 # speeds up build by +- 5%
883 foo = map (lambda x: env.TXT (x + '.txt',
884 os.path.join ('Documentation/topdocs', x)),
886 tar_base = package.name + '-' + version
887 tar_name = tar_base + '.tar.gz'
888 ball_prefix = os.path.join (outdir, tar_base)
889 tar_ball = os.path.join (outdir, tar_name)
891 dist_files = src_files + txt_files
892 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
893 map (lambda x: env.Depends (tar_ball, x), ball_files)
894 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
895 'ln $SOURCE $TARGET'), dist_files)
896 tar = env.Command (tar_ball, src_files,
897 ['rm -f $$(find $TARGET.dir -name .sconsign)',
898 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
899 env.Alias ('tar', tar)
901 dist_ball = os.path.join (package.release_dir, tar_name)
902 env.Command (dist_ball, tar_ball,
903 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
904 + 'ln $SOURCE $TARGET')
905 env.Depends ('dist', dist_ball)
906 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
907 patch = env.PATCH (patch_name, tar_ball)
908 env.Depends (patch_name, dist_ball)
909 env.Alias ('release', patch)
913 web_base = os.path.join (outdir, 'web')
914 web_ball = web_base + '.tar.gz'
915 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
916 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
917 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"') + '-or -type l'
918 env['web_path'] = web_path
919 web_list = os.path.join (outdir, 'weblist')
920 # compatible make heritits
921 # fixme: generate in $outdir is cwd/builddir
922 env.Command (web_list,
923 ## Adding 'doc' dependency is correct, but takes
924 ## > 5min extra if you have a peder :-)
928 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
929 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
930 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
931 'cd $absbuild && find Documentation input $web_path \
933 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
934 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
935 'cd $absbuild && ls *.html >> $TARGET',])
936 env.Command (web_ball, web_list,
937 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
938 #env.Alias ('web', web_ball)
939 www_base = os.path.join (outdir, 'www')
940 www_ball = www_base + '.tar.gz'
941 env.Command (www_ball, web_ball,
943 'mkdir -p $absbuild/$out/tmp',
944 'tar -C $absbuild/$out/tmp -xzf $SOURCE',
945 'cd $absbuild/$out/tmp && for i in $$(find . -name "$out"); '
946 + ' do mv $$i $$(dirname $$i)/out-www; done',
947 'tar -C $absbuild/$out/tmp -czf $TARGET .'])
948 env.Alias ('web', www_ball)
952 ETAGSFLAGS = """--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\\1/' \
953 --regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\\1/'""")
954 code_ext = ['.cc', '.hh', '.scm', '.tcc',]
955 env.Command ('TAGS', filter (lambda x: os.path.splitext (x)[1] in code_ext,
957 'etags $ETAGSFLAGS $SOURCES')
959 # Note: SConscripts are only needed in directories where something needs
960 # to be done, building or installing
962 if os.path.exists (os.path.join (d, 'SConscript')):
963 b = os.path.join (env['build'], d, env['out'])
964 # Support clean sourcetree build (--srcdir build)
966 if os.path.abspath (b) != os.path.abspath (d):
967 env.BuildDir (b, d, duplicate = 0)
968 SConscript (os.path.join (b, 'SConscript'))
970 env.Command ('tree', ['#/VERSION', '#/SConstruct'], symlink_tree)