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, 95)
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'))
174 package = packagepython.Package (srcdir)
175 version = packagepython.version_tuple_to_str (package.version)
177 ENV = { 'PATH' : os.environ['PATH'] }
178 for key in ['LD_LIBRARY_PATH', 'GUILE_LOAD_PATH', 'PKG_CONFIG_PATH', 'TEXMF']:
179 if os.environ.has_key (key):
180 ENV[key] = os.environ[key]
184 BYTEORDER = sys.byteorder.upper (),
187 CPPDEFINES = '-DHAVE_CONFIG_H',
188 MAKEINFO = 'LANG= makeinfo',
189 MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
191 PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
192 'usr/pkg/gnome/lib'),
193 os.path.join (os.environ['HOME'],
194 'usr/pkg/pango/lib')],
197 TOPLEVEL_VERSION = version,
200 Help (usage + opts.GenerateHelpText (env))
202 # Add all config_vars to opts, so that they will be read and saved
203 # together with the other configure options.
204 map (lambda x: opts.AddOptions ((x,)), config_vars)
207 for key in config_vars:
208 if os.environ.has_key (key):
209 env[key] = os.environ[key]
212 # Usability switch (Anthony Roach).
213 # See http://www.scons.org/cgi-bin/wiki/GoFastButton
214 # First do: scons realclean .
216 SetOption ('max_drift', 1)
217 SetOption ('implicit_cache', 1)
218 elif env['checksums']:
219 # Always use checksums (makes more sense than timestamps).
220 SetOption ('max_drift', 0)
221 # Using *content* checksums prevents rebuilds after
222 # [re]configure if config.hh has not changed. Too bad that it
224 TargetSignatures ('content')
226 absbuild = Dir (env['build']).abspath
227 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
228 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
231 config_hh = os.path.join (outdir, 'config.hh')
232 version_hh = os.path.join (outdir, 'version.hh')
234 env.Alias ('config', config_cache)
236 cachedir = os.path.join (outdir, 'build-cache')
238 if not os.path.exists (cachedir):
239 os.makedirs (cachedir)
243 # No need to set $LILYPONDPREFIX to run lily, but cannot install...
244 if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
245 env['prefix'] = run_prefix
247 prefix = env['prefix']
248 bindir = os.path.join (prefix, 'bin')
249 sharedir = os.path.join (prefix, 'share')
250 libdir = os.path.join (prefix, 'lib')
251 localedir = os.path.join (sharedir, 'locale')
252 sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
253 sharedir_package = os.path.join (sharedir, package.name)
254 sharedir_package_version = os.path.join (sharedir_package, version)
255 lilypondprefix = sharedir_package_version
270 def configure (target, source, env):
271 vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9]([.0-9]*[0-9])*).*$',
273 def get_version (program):
274 command = '(pkg-config --modversion %(program)s || %(program)s --version || %(program)s -V) 2>&1' % vars ()
275 pipe = os.popen (command)
276 output = pipe.read ()
279 v = re.sub (vre, '\\1', output)
282 return string.split (v, '.')
284 def test_version (lst, full_name, minimal, description, package):
285 program = os.path.basename (full_name)
286 sys.stdout.write ('Checking %s version... ' % program)
287 actual = get_version (program)
290 lst.append ((description, package, minimal, program,
293 print string.join (actual, '.')
294 if map (string.atoi, actual) \
295 < map (string.atoi, string.split (minimal, '.')):
296 lst.append ((description, package, minimal, program,
297 string.join (actual, '.')))
301 def test_program (lst, program, minimal, description, package):
302 key = program.upper ()
304 key = re.sub ('\+', 'X', key)
305 key = re.sub ('-', '_', key)
306 sys.stdout.write ('Checking for %s ... ' % program)
307 if env.has_key (key):
309 sys.stdout.write ('(cached) ')
311 f = WhereIs (program)
315 lst.append ((description, package, minimal, program,
319 return test_version (lst, program, minimal, description, package)
321 def test_lib (lst, program, minimal, description):
322 # FIXME: test for Debian or RPM (or -foo?) based dists
323 # to guess (or get correct!: apt-cache search?)
325 #if os.system ('pkg-config --atleast-version=0 freetype2'):
327 if test_version (lst, program, minimal, description,
328 'lib%(program)s-dev or %(program)s-devel'
330 env.ParseConfig ('pkg-config --cflags --libs %(program)s'
336 test_program (required, 'bash', '2.0', 'Bash', 'bash')
337 test_program (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
338 test_program (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
339 test_program (required, 'guile-config', '1.6', 'GUILE development',
340 'libguile-dev or guile-devel')
341 test_program (required, 'mf', '0.0', 'Metafont', 'tetex-bin')
342 test_program (required, 'mftrace', '1.1.6', 'mftrace (http://xs4all.nl/~hanwen/mftrace)', 'mftrace')
343 test_program (required, 'potrace', '0.0', 'Potrace', 'potrace')
344 test_program (required, 'python', '2.1', 'Python (www.python.org)', 'python')
345 test_program (required, 'sh', '0.0', 'Bourne shell', 'sh')
348 # Do not use bison 1.50 and 1.75.
349 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
350 test_program (optional, 'bison', '1.25', 'Bison -- parser generator',
352 test_program (optional, 'dvips', '0.0', 'Dvips', 'tetex-bin')
353 test_program (optional, 'fontforge', '0.0.20041224', 'FontForge', 'fontforge')
354 test_program (optional, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
355 test_program (optional, 'guile', '1.6', 'GUILE scheme', 'guile')
356 test_program (optional, 'gs', '8.14', 'Ghostscript PostScript interpreter', 'gs or gs-afpl or gs-esp or gs-gpl')
357 test_program (optional, 'mftrace', '1.1.0', 'Metafont tracing Type1',
359 test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
360 test_program (optional, 'perl', '4.0',
361 'Perl practical efficient readonly language', 'perl')
362 #test_program (optional, 'ps2pdf', '0.0', 'Ps2pdf', 'gs')
364 def CheckYYCurrentBuffer (context):
365 context.Message ('Checking for yy_current_buffer... ')
366 ret = conf.TryLink ("""using namespace std;
367 #include <FlexLexer.h>
368 class yy_flex_lexer: public yyFlexLexer
373 yy_current_buffer = 0;
379 def CheckLibkpathseaSo (context):
381 if context.env.has_key ('CFLAGS'):
382 saveCFLAGS = context.env['CFLAGS']
383 CFLAGS_shared_no_debugging = filter (lambda x: x != '-g',
386 # FIXME: how does this work, with scons
387 context.env.Replace (CFLAGS = CFLAGS_shared_no_debugging)
388 #context.env.Replace (CFLAGS = '')
389 #context.env.Append (CFLAGS = ['-shared'])
390 context.Message ('Checking for libkpathsea... ')
391 ret = conf.TryLink ('''#include <kpathsea/kpathsea.h>
394 kpse_var_expand ("\$TEXMF");
398 context.env.Replace (CFLAGS = saveCFLAGS)
399 # FIXME: this prints 'ok' already
404 sys.stdout.write ('Checking for libkpathsea.so... ')
405 testfile = str (context.sconf.lastTarget)
406 shared_size = os.path.getsize (testfile)
407 ret = shared_size < 40000
414 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
415 : CheckYYCurrentBuffer,
417 : CheckLibkpathseaSo })
420 'DIRSEP' : "'%s'" % os.sep,
421 'PATHSEP' : "'%s'" % os.pathsep,
422 'PACKAGE': '"%s"' % package.name,
423 'DATADIR' : '"%s"' % sharedir,
424 'PACKAGE_DATADIR' : '"%s"' % sharedir_package,
425 'LOCALEDIR' : '"%s"' %localedir,
427 conf.env.Append (DEFINES = defines)
429 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
430 PYTHON_INCLUDE = os.popen (command).read ()#[:-1]
432 env.Append (CCFLAGS = ['-I%s' % PYTHON_INCLUDE])
434 env.Append (CPPPATH = [PYTHON_INCLUDE])
436 headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'libio.h',
439 if conf.CheckCHeader (i):
440 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
441 conf.env['DEFINES'][key] = 1
443 ccheaders = ('sstream',)
445 if conf.CheckCXXHeader (i):
446 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
447 conf.env['DEFINES'][key] = 1
449 functions = ('fopencookie', 'funopen',
450 'gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
452 if 0 or conf.CheckFunc (i):
453 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
454 conf.env['DEFINES'][key] = 1
456 if conf.CheckYYCurrentBuffer ():
457 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
459 if conf.CheckLibkpathseaSo ():
460 conf.env['DEFINES']['HAVE_LIBKPATHSEA_SO'] = '1'
462 if conf.CheckLib ('dl'):
465 if conf.CheckLib ('kpathsea'):
466 conf.env['DEFINES']['KPATHSEA'] = 1
469 if conf.CheckLib ('kpathsea', 'kpse_find_file'):
470 conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
471 if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
472 conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
476 if env.has_key ('CPPPATH'):
477 cpppath = env['CPPPATH']
479 ## FIXME: linkage, check for libguile.h and scm_boot_guile
480 #this could happen after flower...
481 env.ParseConfig ('guile-config compile')
483 test_program (required, 'pkg-config', '0.9.0',
484 'pkg-config library compile manager', 'pkg-config')
485 if test_lib (required, 'freetype2', '0.0',
486 'Development files for FreeType 2 font engine'):
487 conf.env['DEFINES']['HAVE_FREETYPE2'] = '1'
489 if test_lib (required, 'pangoft2', '1.6.0',
490 'Development files for pango, with fontconfig2'):
491 conf.env['DEFINES']['HAVE_PANGO_FT2'] = '1'
492 conf.env['DEFINES']['HAVE_PANGO16'] = '1'
494 if test_lib (optional, 'fontconfig', '2.2.0',
495 'Development files for fontconfig'):
496 conf.env['DEFINES']['HAVE_FONTCONFIG'] = '1'
498 #this could happen only for compiling pango-*
500 test_lib (required, 'gtk+-2.0', '2.4.0',
501 'Development files for GTK+')
502 if test_lib (required, 'pango', '1.6.0',
503 'Development files for pango'):
504 conf.env['DEFINES']['HAVE_PANGO16'] = '1'
506 if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
507 conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
509 # Using CCFLAGS = -I<system-dir> rather than CPPPATH = [
510 # <system-dir>] speeds up SCons
511 env['CCFLAGS'] += map (lambda x: '-I' + x,
512 env['CPPPATH'][len (cpppath):])
513 env['CPPPATH'] = cpppath
517 print '********************************'
518 print 'Please install required packages'
520 print '%s: %s-%s or newer (found: %s %s)' % i
525 print '*************************************'
526 print 'Consider installing optional packages'
528 print '%s: %s-%s or newer (found: %s %s)' % i
530 return conf.Finish ()
532 def config_header (target, source, env):
533 config = open (str (target[0]), 'w')
534 for i in list_sort (env['DEFINES'].keys ()):
535 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
537 env.Command (config_hh, config_cache, config_header)
553 if not d.has_key (lst[i]):
561 def uniquify_config_vars (env):
562 for i in config_vars:
563 if env.has_key (i) and type (env[i]) == type ([]):
564 env[i] = uniquify (env[i])
566 def save_config_cache (env):
567 ## FIXME: Is this smart, using option cache for saving
568 ## config.cache? I cannot seem to find the official method.
569 uniquify_config_vars (env)
570 opts.Save (config_cache, env)
572 if 'config' in COMMAND_LINE_TARGETS:
573 sys.stdout.write ('\n')
574 sys.stdout.write ('LilyPond configured')
575 sys.stdout.write ('\n')
576 sys.stdout.write ('Now run')
577 sys.stdout.write ('\n')
578 sys.stdout.write (' scons [TARGET|DIR]...')
579 sys.stdout.write ('\n')
580 sys.stdout.write ('\n')
581 sys.stdout.write ('Examples:')
582 sys.stdout.write (' scons lily # build lilypond')
583 sys.stdout.write (' scons all # build everything')
584 sys.stdout.write (' scons doc # build documentation')
586 ## sys.stdout.write (' scons prefix=/usr DESTDIR=/tmp/pkg all install')
588 elif not env['checksums']:
589 # When using timestams, config.hh is NEW. The next
590 # build triggers recompilation of everything. Exiting
591 # here makes SCons use the actual timestamp for config.hh
592 # and prevents recompiling everything the next run.
593 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
594 sys.stdout.write ('Running %s ... ' % command)
595 sys.stdout.write ('\n')
596 s = os.system (command)
600 # scons: *** Calling Configure from Builders is not supported.
601 # env.Command (config_cache, None, configure)
602 if not os.path.exists (config_cache) \
603 or (os.stat ('SConstruct')[stat.ST_MTIME]
604 > os.stat (config_cache)[stat.ST_MTIME]):
605 env = configure (None, None, env)
606 save_config_cache (env)
607 elif env['checksums']:
608 # just save everything
609 save_config_cache (env)
611 #urg how does #/ subst work?
613 SConscript ('buildscripts/builder.py')
615 env.PrependENVPath ('PATH',
616 os.path.join (env['absbuild'], env['out'], 'usr/bin'))
618 LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond/', version)
621 #'LILYPONDPREFIX' : os.path.join (run_prefix, 'share/lilypond/', version),
622 'LILYPONDPREFIX' : LILYPONDPREFIX,
623 # ugh, can't use LILYPONDPREFIX here
624 #'TEXMF' : '{' + os.path.join (run_prefix, 'share/lilypond/', version)\
626 'TEXMF' : '{$LILYPONDPREFIX,'
627 + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}',
630 BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
631 BUILD_LILYPOND = '$absbuild/lily/$out/lilypond ${__verbose}'
632 BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py ${__verbose}'
635 # post-option environment-update
639 lilypond_datadir = sharedir_package,
640 localedir = localedir,
641 local_lilypond_datadir = sharedir_package_version,
642 lilypondprefix = lilypondprefix,
643 sharedir_package = sharedir_package,
644 sharedir_doc_package = sharedir_doc_package,
645 sharedir_package_version = sharedir_package_version,
647 # global build verbosity switch
648 __verbose = ' --verbose',
650 LILYPOND = BUILD_LILYPOND,
651 ABC2LY = BUILD_ABC2LY,
652 LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
653 LILYPOND_BOOK_FORMAT = 'texi-html',
654 MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
655 # should not be necessary
656 # PYTHONPATH = ['$absbuild/python/$out'],
657 TEXI2DVI_PAPERSIZE = '@afourpaper',
658 TEXI2DVI_FLAGS = [ '-t$TEXI2DVI_PAPERSIZE'],
659 DVIPS_PAPERSIZE = 'a4',
660 DVIPS_FLAGS = ['-t$DVIPS_PAPERSIZE',
662 '-u+ec-mftrace.map'],
663 PSPDF_FLAGS = ['-sPAPERSIZE=$DVIPS_PAPERSIZE'],
667 env.Append (CCFLAGS = ['-g', '-pipe'])
668 if env['optimising']:
669 env.Append (CCFLAGS = '-O2')
670 env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
672 env.Append (CCFLAGS = ['-W', '-Wall'])
673 env.Append (CXXFLAGS = ['-Wconversion'])
676 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
679 env['__verbose'] = ' --verbose'
680 env['set__x'] = 'set -x;'
683 ## Explicit target and dependencies
685 if 'clean' in COMMAND_LINE_TARGETS:
686 # ugh: prevent reconfigure instead of clean
687 os.system ('touch %s' % config_cache)
689 command = sys.argv[0] + ' -c .'
690 sys.stdout.write ('Running %s ... ' % command)
691 sys.stdout.write ('\n')
692 s = os.system (command)
693 if os.path.exists (config_cache):
694 os.unlink (config_cache)
697 if 'sconsclean' in COMMAND_LINE_TARGETS:
698 command = 'rm -rf scons.cache $(find . -name ".scon*")'
699 s = os.system (command)
700 if os.path.exists (config_cache):
701 os.unlink (config_cache)
704 if 'realclean' in COMMAND_LINE_TARGETS:
705 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
706 sys.stdout.write ('Running %s ... ' % command)
707 sys.stdout.write ('\n')
708 s = os.system (command)
709 if os.path.exists (config_cache):
710 os.unlink (config_cache)
713 # Declare SConscript phonies
714 env.Alias ('minimal', config_cache)
715 env.Alias ('mf-essential', config_cache)
717 env.Alias ('minimal', ['lily', 'mf-essential'])
718 env.Alias ('all', ['minimal', 'mf', '.'])
719 # Do we want the doc/web separation?
722 'Documentation/user',
723 'Documentation/topdocs',
724 'Documentation/bibliography',
727 # Without target arguments, do minimal build
728 if not COMMAND_LINE_TARGETS:
729 env.Default (['minimal'])
731 # GNU Make rerouting compat:
732 env.Alias ('web', 'doc')
735 env.Command (version_hh, '#/VERSION',
736 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
738 # post-config environment update
740 run_prefix = run_prefix,
741 LILYPONDPREFIX = LILYPONDPREFIX,
743 # FIXME: move to lily/SConscript?
744 LIBPATH = [os.path.join (absbuild, 'flower', env['out']),
745 os.path.join (absbuild, 'kpath-guile', env['out']),
746 os.path.join (absbuild, 'ttftool', env['out']),],
747 CPPPATH = [outdir, ],
748 LILYPOND_PATH = ['.', '$srcdir/input',
749 '$srcdir/input/regression',
750 '$srcdir/input/test',
751 '$srcdir/input/tutorial',
752 '$srcdir/Documentation/user',
754 # os.path.join (absbuild, 'Documentation',
756 # os.path.join (absbuild, 'Documentation/user',
759 MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
760 '$absbuild/Documentation/user/$out'],
763 def symlink_tree (target, source, env):
769 if not os.path.isdir (dir):
770 if os.path.exists (dir):
774 map (mkdir, string.split (dir, os.sep))
775 def symlink (src, dst):
777 dir = os.path.dirname (dst)
780 frm = os.path.join (srcdir, src[1:])
782 depth = len (string.split (dir, '/'))
783 if src.find ('@') > -1:
784 frm = os.path.join ('../' * depth,
785 string.replace (src, '@',
788 frm = os.path.join ('../' * depth, src,
791 frm = os.path.join (frm, os.path.basename (dst))
793 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
794 os.symlink (frm, os.path.basename (dst))
795 shutil.rmtree (run_prefix)
796 prefix = os.path.join (env['out'], 'usr')
797 map (lambda x: symlink (x[0], os.path.join (prefix,
798 x[1] % {'ver' : version})),
801 # /$ := add dst file_name
802 (('python', 'lib/lilypond/python'),
804 ('python', 'share/lilypond/%(ver)s/python'),
805 ('lily/', 'bin/lilypond'),
806 ('scripts/', 'bin/convert-ly'),
807 ('scripts/', 'bin/lilypond-book'),
808 ('scripts/', 'bin/ps2png'),
809 ('mf', 'share/lilypond/%(ver)s/dvips/mf-out'),
810 ('#ps', 'share/lilypond/%(ver)s/dvips/ps'),
811 ('#ps', 'share/lilypond/%(ver)s/tex/music-drawing-routines.ps'),
812 ('mf', 'share/lilypond/%(ver)s/otf'),
813 ('mf', 'share/lilypond/%(ver)s/tfm'),
814 ('tex', 'share/lilypond/%(ver)s/tex/enc'),
815 ('#mf', 'share/lilypond/%(ver)s/fonts/mf'),
816 ('mf', 'share/lilypond/%(ver)s/fonts/map'),
817 ('mf', 'share/lilypond/%(ver)s/fonts/otf'),
818 ('mf', 'share/lilypond/%(ver)s/fonts/tfm'),
819 ('mf', 'share/lilypond/%(ver)s/fonts/type1'),
820 ('#tex', 'share/lilypond/%(ver)s/tex/source'),
821 ('tex', 'share/lilypond/%(ver)s/tex/tex-out'),
822 ('mf', 'share/lilypond/%(ver)s/tex/mf-out'),
823 ('#ly', 'share/lilypond/%(ver)s/ly'),
824 ('#scm', 'share/lilypond/%(ver)s/scm'),
825 ('#scripts', 'share/lilypond/%(ver)s/scripts'),
826 ('#ps', 'share/lilypond/%(ver)s/ps'),
827 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
828 ('elisp', 'share/lilypond/%(ver)s/elisp')))
830 print "FIXME: BARF BARF BARF"
834 prefix = os.path.join (env['out'], 'usr/share/lilypond/%(ver)s/fonts'
836 for ext in ('enc', 'map', 'otf', 'svg', 'tfm', 'pfa'):
837 dir = os.path.join (absbuild, prefix, ext)
838 os.system ('rm -f ' + dir)
841 os.system ('ln -s ../../../../../../../mf/%(out)s/*.%(ext)s .'
846 stamp = os.path.join (run_prefix, 'stamp')
847 env.Command (stamp, ['#/SConstruct', '#/VERSION'],
848 [symlink_tree, 'touch $TARGET'])
849 env.Depends ('lily', stamp)
855 def cvs_entry_is_dir (line):
856 return line[0] == 'D' and line[-2] == '/'
858 def cvs_entry_is_file (line):
859 return line[0] == '/' and line[-2] == '/'
862 ENTRIES = os.path.join (dir, 'CVS/Entries')
863 if not os.path.exists (ENTRIES):
865 entries = open (ENTRIES).readlines ()
866 dir_entries = filter (cvs_entry_is_dir, entries)
867 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
869 return dirs + map (cvs_dirs, dirs)
872 ENTRIES = os.path.join (dir, 'CVS/Entries')
873 entries = open (ENTRIES).readlines ()
874 file_entries = filter (cvs_entry_is_file, entries)
875 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
876 return map (lambda x: os.path.join (dir, x), files)
878 def flatten (tree, lst):
879 if type (tree) == type ([]):
881 if type (i) == type ([]):
887 if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
888 subdirs = flatten (cvs_dirs ('.'), [])
891 command = 'cd %(srcdir)s \
892 && find . -name SConscript | sed s@/SConscript@@' % vars ()
893 subdirs = string.split (os.popen (command).read ())
896 and 'all' not in COMMAND_LINE_TARGETS\
897 and 'doc' not in COMMAND_LINE_TARGETS\
898 and 'web' not in COMMAND_LINE_TARGETS\
899 and 'install' not in COMMAND_LINE_TARGETS\
900 and 'clean' not in COMMAND_LINE_TARGETS:
901 subdirs = ['lily', 'lily/include',
902 'flower', 'flower/include',
908 if os.path.isdir ('%(srcdir)s/CVS' % vars ()):
909 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
911 src_files = ['foobar']
913 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
914 txt_files = map (lambda x: x + '.txt', readme_files)
918 # speeds up build by +- 5%
921 foo = map (lambda x: env.TXT (x + '.txt',
922 os.path.join ('Documentation/topdocs', x)),
924 tar_base = package.name + '-' + version
925 tar_name = tar_base + '.tar.gz'
926 ball_prefix = os.path.join (outdir, tar_base)
927 tar_ball = os.path.join (outdir, tar_name)
929 dist_files = src_files + txt_files
930 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
931 map (lambda x: env.Depends (tar_ball, x), ball_files)
932 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
933 'ln $SOURCE $TARGET'), dist_files)
934 tar = env.Command (tar_ball, src_files,
935 ['rm -f $$(find $TARGET.dir -name .sconsign)',
936 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
937 env.Alias ('tar', tar)
939 dist_ball = os.path.join (package.release_dir, tar_name)
940 env.Command (dist_ball, tar_ball,
941 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
942 + 'ln $SOURCE $TARGET')
943 env.Depends ('dist', dist_ball)
944 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
945 patch = env.PATCH (patch_name, tar_ball)
946 env.Depends (patch_name, dist_ball)
947 env.Alias ('release', patch)
951 web_base = os.path.join (outdir, 'web')
952 web_ball = web_base + '.tar.gz'
953 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
954 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
955 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"') + '-or -type l'
956 env['web_path'] = web_path
957 web_list = os.path.join (outdir, 'weblist')
958 # compatible make heritits
959 # fixme: generate in $outdir is cwd/builddir
960 env.Command (web_list,
961 ## Adding 'doc' dependency is correct, but takes
962 ## > 5min extra if you have a peder :-)
966 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
967 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
968 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
969 'cd $absbuild && find Documentation input $web_path \
971 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
972 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
973 'cd $absbuild && ls *.html >> $TARGET',])
974 env.Command (web_ball, web_list,
975 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
976 #env.Alias ('web', web_ball)
977 www_base = os.path.join (outdir, 'www')
978 www_ball = www_base + '.tar.gz'
979 env.Command (www_ball, web_ball,
981 'mkdir -p $absbuild/$out/tmp',
982 'tar -C $absbuild/$out/tmp -xzf $SOURCE',
983 'cd $absbuild/$out/tmp && for i in $$(find . -name "$out"); '
984 + ' do mv $$i $$(dirname $$i)/out-www; done',
985 'tar -C $absbuild/$out/tmp -czf $TARGET .'])
986 env.Alias ('web', www_ball)
990 ETAGSFLAGS = """--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\\1/' \
991 --regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\\1/'""")
992 code_ext = ['.cc', '.hh', '.scm', '.tcc',]
993 env.Command ('TAGS', filter (lambda x: os.path.splitext (x)[1] in code_ext,
995 'etags $ETAGSFLAGS $SOURCES')
997 # Note: SConscripts are only needed in directories where something needs
998 # to be done, building or installing
1000 if os.path.exists (os.path.join (d, 'SConscript')):
1001 b = os.path.join (env['build'], d, env['out'])
1002 # Support clean sourcetree build (--srcdir build)
1004 if os.path.abspath (b) != os.path.abspath (d):
1005 env.BuildDir (b, d, duplicate = 0)
1006 SConscript (os.path.join (b, 'SConscript'))