* Documentation/user/tutorial.itely (Integrating text and music):
[lilypond.git] / SConstruct
blob6d67479f467ad8d5e05e5a7be16de4003cbc5bba
1 # -*-python-*-
3 '''
4 Experimental scons (www.scons.org) building.
6 Usage
8 scons TARGET
10 build from source directory ./TARGET (not recursive)
12 Configure, build
14 scons [config] # configure
15 scons # build all
17 Run from build tree
19 run=$(pwd)/out-scons/usr
20 export LOCALE=$run/share/locale
21 export TEXMF='{'$run/share/lilypond,$(kpsexpand '$TEXMF')'}'
22 PATH=$run/bin:$PATH
24 #optionally, if you do not use custom.py below
25 #export LILYPONDPREFIX=$run/share/lilypond
27 lilypond-bin input/simple
29 Other targets
30 scons mf-essential # build minimal mf stuff
32 scons doc # build web doc
33 scons config # reconfigure
34 scons install # install
35 scons -c # clean
36 scons -h # help
38 scons / # build *everything* (including installation)
40 Options (see scons -h)
41 scons build=DIR # clean srcdir build, output below DIR
42 scons out=DIR # write output for alterative config to DIR
44 Debugging
45 scons --debug=dtree
46 scons --debug=explain
47 scons verbose=1
49 Optional custom.py
51 import os
52 out='out-scons'
53 optimising=0
54 debugging=1
55 gui=1
56 os.path.join (os.getcwd (), '=install')
57 prefix=os.path.join (os.environ['HOME'], 'usr', 'pkg', 'lilypond')
59 '''
62 # TODO:
63 # * usability
65 # * more program configure tests (mfont, ...?)
67 # * install doc
69 # * split doc target: doc input examples mutopia?
71 # * grep FIXME $(find . -name 'S*t')
74 import re
75 import glob
76 import os
77 import string
78 import sys
79 import stat
80 import shutil
82 # duh, we need 0.95.1
83 EnsureSConsVersion (0, 95)
85 usage = r'''Usage:
86 scons [KEY=VALUE].. [TARGET|DIR]..
88 TARGETS: clean, config, doc, dist, install, mf-essential, po-update,
89 realclean, release, sconsclean, tar, TAGS
91 '''
94 config_cache = 'scons.cache'
96 config_vars = [
97 'BASH',
98 'CCFLAGS',
99 'CPPPATH',
100 'CPPDEFINES',
101 'CXXFLAGS',
102 'DEFINES',
103 'LIBS',
104 'LINKFLAGS',
105 'METAFONT',
106 'PERL',
107 'PYTHON',
110 # Put your favourite stuff in custom.py
111 opts = Options ([config_cache, 'custom.py'], ARGUMENTS)
112 opts.Add ('prefix', 'Install prefix', '/usr/')
113 opts.Add ('out', 'Output directory', 'out-scons')
114 opts.Add ('build', 'Build directory', '.')
115 opts.Add ('DESTDIR', 'DESTDIR prepended to prefix', '')
116 opts.AddOptions (
117 BoolOption ('warnings', 'compile with -Wall and similiar',
119 BoolOption ('debugging', 'compile with debugging symbols',
121 BoolOption ('optimising', 'compile with optimising',
123 BoolOption ('shared', 'build shared libraries',
125 BoolOption ('static', 'build static libraries',
127 BoolOption ('gui', 'build with GNOME backend (EXPERIMENTAL)',
129 BoolOption ('verbose', 'run commands with verbose flag',
131 BoolOption ('checksums', 'use checksums instead of timestamps',
133 BoolOption ('fast', 'use timestamps, implicit cache, prune CPPPATH',
137 srcdir = Dir ('.').srcnode ().abspath
138 #ugh
139 sys.path.append (os.path.join (srcdir, 'stepmake', 'bin'))
140 import packagepython
141 package = packagepython.Package (srcdir)
142 version = packagepython.version_tuple_to_str (package.version)
144 ENV = { 'PATH' : os.environ['PATH'] }
145 for key in ['LD_LIBRARY_PATH', 'GUILE_LOAD_PATH', 'PKG_CONFIG_PATH']:
146 if os.environ.has_key (key):
147 ENV[key] = os.environ[key]
149 env = Environment (
150 ENV = ENV,
152 BASH = '/bin/bash',
153 PERL = '/usr/bin/perl',
154 PYTHON = '/usr/bin/python',
155 SH = '/bin/sh',
157 MAKEINFO = 'LANG= makeinfo',
158 MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
160 PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
161 'usr/pkg/gnome/lib'),
162 os.path.join (os.environ['HOME'],
163 'usr/pkg/pango/lib')],
164 GZIP='-9v',
165 MFMODE = 'ljfour',
166 TOPLEVEL_VERSION = version,
169 # Add all config_vars to opts, so that they will be read and saved
170 # together with the other configure options.
171 map (lambda x: opts.AddOptions ((x,)), config_vars)
173 Help (usage + opts.GenerateHelpText (env))
175 opts.Update (env)
177 if env['fast']:
178 # Usability switch (Anthony Roach).
179 # See http://www.scons.org/cgi-bin/wiki/GoFastButton
180 # First do: scons realclean .
181 env['checksums'] = 0
182 SetOption ('max_drift', 1)
183 SetOption ('implicit_cache', 1)
184 elif env['checksums']:
185 # Always use checksums (makes more sense than timestamps).
186 SetOption ('max_drift', 0)
187 # Using *content* checksums prevents rebuilds after
188 # [re]configure if config.hh has not changed. Too bad that it
189 # is unusably slow.
190 TargetSignatures ('content')
192 absbuild = Dir (env['build']).abspath
193 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
194 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
197 config_hh = os.path.join (outdir, 'config.hh')
198 version_hh = os.path.join (outdir, 'version.hh')
200 env.Alias ('config', config_cache)
202 cachedir = os.path.join (outdir, 'build-cache')
204 if not os.path.exists(cachedir):
205 os.makedirs(cachedir)
207 CacheDir (os.path.join (outdir, 'build-cache'))
209 # No need to set $LILYPONDPREFIX to run lily, but cannot install...
210 if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
211 env['prefix'] = run_prefix
213 prefix = env['prefix']
214 bindir = os.path.join (prefix, 'bin')
215 sharedir = os.path.join (prefix, 'share')
216 libdir = os.path.join (prefix, 'lib')
217 localedir = os.path.join (sharedir, 'locale')
218 sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
219 sharedir_package = os.path.join (sharedir, package.name)
220 sharedir_package_version = os.path.join (sharedir_package, version)
221 lilypondprefix = sharedir_package_version
223 # junkme
224 env.Append (
225 absbuild = absbuild,
226 srcdir = srcdir,
230 def list_sort (lst):
231 sorted = lst
232 sorted.sort ()
233 return sorted
236 def configure (target, source, env):
237 vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
238 def get_version (program):
239 command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
240 pipe = os.popen (command)
241 output = pipe.read ()
242 if pipe.close ():
243 return None
244 v = re.sub (vre, '\\1', output)
245 return string.split (v, '.')
247 def test_program (lst, program, minimal, description, package):
248 sys.stdout.write ('Checking %s version... ' % program)
249 actual = get_version (program)
250 if not actual:
251 print 'not found'
252 lst.append ((description, package, minimal, program,
253 'not installed'))
254 return
255 sys.stdout.write (string.join (actual, '.'))
256 sys.stdout.write ('\n')
257 if actual < string.split (minimal, '.'):
258 lst.append ((description, package, minimal, program,
259 string.join (actual, '.')))
261 for i in ['bash', 'perl', 'python', 'sh']:
262 sys.stdout.write ('Checking for %s... ' % i)
263 c = WhereIs (i)
264 key = string.upper (i)
265 if c:
266 env[key] = c
267 sys.stdout.write (c)
268 else:
269 sys.stdout.write ('not found: %s (using: %s)' \
270 % (c, env[key]))
271 # Hmm? abort?
272 sys.stdout.write ('\n')
274 required = []
275 test_program (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
276 test_program (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
277 test_program (required, 'python', '2.1', 'Python (www.python.org)', 'python')
278 test_program (required, 'guile-config', '1.6', 'GUILE development',
279 'libguile-dev or guile-devel')
280 # Do not use bison 1.50 and 1.75.
281 test_program (required, 'bison', '1.25', 'Bison -- parser generator',
282 'bison')
283 test_program (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
286 optional = []
287 test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
288 test_program (optional, 'guile', '1.6', 'GUILE scheme',
289 'libguile-dev or guile-devel')
290 test_program (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
291 'mftrace')
292 test_program (optional, 'perl', '4.0',
293 'Perl practical efficient readonly language', 'perl')
294 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
296 def CheckYYCurrentBuffer (context):
297 context.Message ('Checking for yy_current_buffer... ')
298 ret = conf.TryCompile ("""using namespace std;
299 #include <FlexLexer.h>
300 class yy_flex_lexer: public yyFlexLexer
302 public:
303 yy_flex_lexer ()
305 yy_current_buffer = 0;
307 };""", '.cc')
308 context.Result (ret)
309 return ret
311 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
312 : CheckYYCurrentBuffer })
314 defines = {
315 'DIRSEP' : "'%s'" % os.sep,
316 'PATHSEP' : "'%s'" % os.pathsep,
317 'TOPLEVEL_VERSION' : '"' + version + '"',
318 'PACKAGE': '"' + package.name + '"',
319 'DATADIR' : '"' + sharedir + '"',
320 'LILYPOND_DATADIR' : '"' + sharedir_package + '"',
321 'LOCAL_LILYPOND_DATADIR' : '"' + sharedir_package_version + '"',
322 'LOCALEDIR' : '"' + localedir + '"',
324 conf.env.Append (DEFINES = defines)
326 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
327 PYTHON_INCLUDE = os.popen (command).read ()
328 if env['fast']:
329 env.Append (CCFLAGS = ['-I%s ' % PYTHON_INCLUDE])
330 else:
331 env.Append (CPPPATH = PYTHON_INCLUDE)
333 headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
334 for i in headers:
335 if conf.CheckCHeader (i):
336 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
337 conf.env['DEFINES'][key] = 1
339 ccheaders = ('sstream',)
340 for i in ccheaders:
341 if conf.CheckCXXHeader (i):
342 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
343 conf.env['DEFINES'][key] = 1
345 functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
346 for i in functions:
347 if 0 or conf.CheckFunc (i):
348 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
349 conf.env['DEFINES'][key] = 1
351 if conf.CheckYYCurrentBuffer ():
352 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
354 if conf.CheckLib ('dl'):
355 pass
357 if conf.CheckLib ('kpathsea'):
358 conf.env['DEFINES']['KPATHSEA'] = 1
360 # huh?
361 if conf.CheckLib ('kpathsea', 'kpse_find_file'):
362 conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
363 if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
364 conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
366 if env['fast']:
367 cpppath = []
368 if env.has_key ('CPPPATH'):
369 cpppath = env['CPPPATH']
370 #this could happen after flower...
371 env.ParseConfig ('guile-config compile')
373 #this could happen only for compiling pango-*
374 if env['gui']:
375 env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
376 env.ParseConfig ('pkg-config --cflags --libs pango')
377 if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
378 conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
380 if conf.CheckLib ('pango-1.0',
381 'pango_fc_font_map_add_decoder_find_func'):
382 conf.env['DEFINES']['HAVE_PANGO_CVS'] = '1'
383 conf.env['DEFINES']['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
385 if env['fast']:
386 # Using CCFLAGS = -I<system-dir> rather than CPPPATH = [
387 # <system-dir>] speeds up SCons
388 env['CCFLAGS'] += map (lambda x: '-I' + x,
389 env['CPPPATH'][len (cpppath):])
390 env['CPPPATH'] = cpppath
392 if required:
393 print
394 print '********************************'
395 print 'Please install required packages'
396 for i in required:
397 print '%s: %s-%s or newer (found: %s %s)' % i
398 Exit (1)
400 if optional:
401 print
402 print '*************************************'
403 print 'Consider installing optional packages'
404 for i in optional:
405 print '%s: %s-%s or newer (found: %s %s)' % i
407 return conf.Finish ()
409 def config_header (target, source, env):
410 config = open (str (target[0]), 'w')
411 for i in list_sort (env['DEFINES'].keys ()):
412 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
413 config.close ()
414 env.Command (config_hh, config_cache, config_header)
416 # hmm?
417 def xuniquify (lst):
418 n = []
419 for i in lst:
420 if not i in n:
421 n.append (i)
422 lst = n
423 return lst
425 def uniquify (lst):
426 d = {}
427 n = len (lst)
428 i = 0
429 while i < n:
430 if not d.has_key (lst[i]):
431 d[lst[i]] = 1
432 i += 1
433 else:
434 del lst[i]
435 n -= 1
436 return lst
438 def uniquify_config_vars (env):
439 for i in config_vars:
440 if env.has_key (i) and type (env[i]) == type ([]):
441 env[i] = uniquify (env[i])
443 def save_config_cache (env):
444 ## FIXME: Is this smart, using option cache for saving
445 ## config.cache? I cannot seem to find the official method.
446 uniquify_config_vars (env)
447 opts.Save (config_cache, env)
449 if 'config' in COMMAND_LINE_TARGETS:
450 sys.stdout.write ('\n')
451 sys.stdout.write ('LilyPond configured')
452 sys.stdout.write ('\n')
453 sys.stdout.write ('now run')
454 sys.stdout.write ('\n')
455 sys.stdout.write (' scons [TARGET|DIR]...')
456 sys.stdout.write ('\n')
457 Exit (0)
458 elif not env['checksums']:
459 # When using timestams, config.hh is NEW. The next
460 # build triggers recompilation of everything. Exiting
461 # here makes SCons use the actual timestamp for config.hh
462 # and prevents recompiling everything the next run.
463 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
464 sys.stdout.write ('Running %s ... ' % command)
465 sys.stdout.write ('\n')
466 s = os.system (command)
467 Exit (s)
470 if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
471 os.unlink (config_cache)
472 # WTF?
473 # scons: *** Calling Configure from Builders is not supported.
474 # env.Command (config_cache, None, configure)
475 if not os.path.exists (config_cache) \
476 or (os.stat ('SConstruct')[stat.ST_MTIME]
477 > os.stat (config_cache)[stat.ST_MTIME]):
478 env = configure (None, None, env)
479 save_config_cache (env)
480 elif env['checksums']:
481 # just save everything
482 save_config_cache (env)
484 #urg how does #/ subst work?
485 Export ('env')
486 SConscript ('buildscripts/builder.py')
488 env.PrependENVPath ('PATH',
489 os.path.join (env['absbuild'], env['out'], 'usr/bin'))
491 if os.environ.has_key ('TEXMF'):
492 env.Append (ENV = {'TEXMF' : os.environ['TEXMF']})
493 env.Append (ENV = {
494 'TEXMF' : '{$LILYPONDPREFIX,' \
495 + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}',
496 'LILYPONDPREFIX' : os.path.join (run_prefix, 'share/lilypond'),
499 BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
500 BUILD_LILYPOND = '${set__x}$PYTHON $srcdir/scripts/lilypond.py${__verbose}'
501 BUILD_LILYPOND_BIN = '$absbuild/$out/lilypond-bin ${__verbose}'
502 BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py --verbose'
505 # post-option environment-update
506 env.Append (
507 bindir = bindir,
508 sharedir = sharedir,
509 lilypond_datadir = sharedir_package,
510 localedir = localedir,
511 local_lilypond_datadir = sharedir_package_version,
512 lilypondprefix = lilypondprefix,
513 sharedir_package = sharedir_package,
514 sharedir_doc_package = sharedir_doc_package,
515 sharedir_package_version = sharedir_package_version,
517 LILYPOND = BUILD_LILYPOND,
518 ABC2LY = BUILD_ABC2LY,
519 LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
520 LILYPOND_BOOK_FORMAT = 'texi-html',
521 MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
523 TEXI2DVI_PAPERSIZE = '@afourpaper',
524 TEXI2DVI_FLAGS = [ '-t $TEXI2DVI_PAPERSIZE'],
525 DVIPS_PAPERSIZE = 'a4',
526 DVIPS_FLAGS = ['-t $DVIPS_PAPERSIZE',
527 '-u+lilypond.map',
528 '-u+ec-mftrace.map'],
529 PSPDF_FLAGS = ['-sPAPERSIZE=$DVIPS_PAPERSIZE'],
532 if env['debugging']:
533 env.Append (CCFLAGS = ['-g', '-pipe'])
534 if env['optimising']:
535 env.Append (CCFLAGS = '-O2')
536 env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
537 if env['warnings']:
538 env.Append (CCFLAGS = ['-W', '-Wall'])
539 env.Append (CXXFLAGS = ['-Wconversion'])
541 # ugr,huh?
542 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
544 if env['verbose']:
545 env['__verbose'] = ' --verbose'
546 env['set__x'] = 'set -x;'
549 ## Explicit target and dependencies
551 if 'clean' in COMMAND_LINE_TARGETS:
552 # ugh: prevent reconfigure instead of clean
553 os.system ('touch %s' % config_cache)
555 command = sys.argv[0] + ' -c .'
556 sys.stdout.write ('Running %s ... ' % command)
557 sys.stdout.write ('\n')
558 s = os.system (command)
559 if os.path.exists (config_cache):
560 os.unlink (config_cache)
561 Exit (s)
563 if 'sconsclean' in COMMAND_LINE_TARGETS:
564 command = 'rm -rf scons.cache $(find . -name ".scon*")'
565 s = os.system (command)
566 if os.path.exists (config_cache):
567 os.unlink (config_cache)
568 Exit (s)
570 if 'realclean' in COMMAND_LINE_TARGETS:
571 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
572 sys.stdout.write ('Running %s ... ' % command)
573 sys.stdout.write ('\n')
574 s = os.system (command)
575 if os.path.exists (config_cache):
576 os.unlink (config_cache)
577 Exit (s)
579 # Declare SConscript phonies
580 env.Alias ('minimal', config_cache)
581 env.Alias ('mf-essential', config_cache)
583 env.Alias ('minimal', ['lily', 'mf-essential'])
584 env.Alias ('all', ['minimal', 'mf', '.'])
585 # Do we want the doc/web separation?
586 env.Alias ('doc',
587 ['Documentation',
588 'Documentation/user',
589 'Documentation/topdocs',
590 'Documentation/bibliography',
591 'input'])
593 # Without target arguments, do minimal build
594 if not COMMAND_LINE_TARGETS:
595 env.Default (['minimal'])
597 # GNU Make rerouting compat:
598 env.Alias ('web', 'doc')
601 env.Command (version_hh, '#/VERSION',
602 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
604 # post-config environment update
605 env.Append (
606 run_prefix = run_prefix,
607 LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond'),
609 LIBPATH = [os.path.join (absbuild, 'flower', env['out']),],
610 CPPPATH = [outdir, ],
611 LILYPOND_PATH = ['.', '$srcdir/input',
612 '$srcdir/input/regression',
613 '$srcdir/input/test',
614 '$srcdir/input/tutorial',
615 '$srcdir/Documentation/user',
616 '$absbuild/mf/$out',
617 # os.path.join (absbuild, 'Documentation',
618 # env['out']),
619 # os.path.join (absbuild, 'Documentation/user',
620 # env['out']),
622 MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
623 '$absbuild/Documentation/user/$out'],
626 def symlink_tree (target, source, env):
627 def mkdirs (dir):
628 def mkdir (dir):
629 if not dir:
630 os.chdir (os.sep)
631 return
632 if not os.path.isdir (dir):
633 if os.path.exists (dir):
634 os.unlink (dir)
635 os.mkdir (dir)
636 os.chdir (dir)
637 map (mkdir, string.split (dir, os.sep))
638 def symlink (src, dst):
639 os.chdir (absbuild)
640 dir = os.path.dirname (dst)
641 mkdirs (dir)
642 if src[0] == '#':
643 frm = os.path.join (srcdir, src[1:])
644 else:
645 depth = len (string.split (dir, '/'))
646 if src.find ('@') > -1:
647 frm = os.path.join ('../' * depth,
648 string.replace (src, '@',
649 env['out']))
650 else:
651 frm = os.path.join ('../' * depth, src,
652 env['out'])
653 if src[-1] == '/':
654 frm = os.path.join (frm, os.path.basename (dst))
655 if env['verbose']:
656 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
657 os.symlink (frm, os.path.basename (dst))
658 shutil.rmtree (run_prefix)
659 prefix = os.path.join (env['out'], 'usr')
660 map (lambda x: symlink (x[0], os.path.join (prefix, x[1])),
661 # ^# := source dir
662 # @ := out
663 # /$ := add dst file_name
664 (('python', 'lib/lilypond/python'),
665 ('lily/', 'bin/lilypond-bin'),
666 ('scripts/', 'bin/lilypond'),
667 ('scripts/', 'bin/lilypond-book'),
668 ('mf', 'share/lilypond/dvips'),
669 ('#ps', 'share/lilypond/tex/music-drawing-routines.ps'),
670 ('mf', 'share/lilypond/afm'),
671 ('mf', 'share/lilypond/tfm'),
672 ('#mf', 'share/lilypond/fonts/mf'),
673 ('mf', 'share/lilypond/fonts/afm'),
674 ('mf', 'share/lilypond/fonts/tfm'),
675 ('mf', 'share/lilypond/fonts/type1'),
676 ('#tex', 'share/lilypond/tex/source'),
677 ('mf', 'share/lilypond/tex/generate'),
678 ('#ly', 'share/lilypond/ly'),
679 ('#scm', 'share/lilypond/scm'),
680 ('#ps', 'share/lilypond/ps'),
681 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
682 ('elisp', 'share/lilypond/elisp')))
683 os.chdir (srcdir)
685 if env['debugging']:
686 stamp = os.path.join (run_prefix, 'stamp')
687 env.Command (stamp, 'SConstruct', [symlink_tree, 'touch $TARGET'])
688 env.Depends ('lily', stamp)
690 #### dist, tar
691 def plus (a, b):
692 a + b
694 def cvs_entry_is_dir (line):
695 return line[0] == 'D' and line[-2] == '/'
697 def cvs_entry_is_file (line):
698 return line[0] == '/' and line[-2] == '/'
700 def cvs_dirs (dir):
701 ENTRIES = os.path.join (dir, 'CVS/Entries')
702 if not os.path.exists (ENTRIES):
703 return []
704 entries = open (ENTRIES).readlines ()
705 dir_entries = filter (cvs_entry_is_dir, entries)
706 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
707 dir_entries)
708 return dirs + map (cvs_dirs, dirs)
710 def cvs_files (dir):
711 ENTRIES = os.path.join (dir, 'CVS/Entries')
712 entries = open (ENTRIES).readlines ()
713 file_entries = filter (cvs_entry_is_file, entries)
714 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
715 return map (lambda x: os.path.join (dir, x), files)
717 def flatten (tree, lst):
718 if type (tree) == type ([]):
719 for i in tree:
720 if type (i) == type ([]):
721 flatten (i, lst)
722 else:
723 lst.append (i)
724 return lst
726 if env['fast']\
727 and 'all' not in COMMAND_LINE_TARGETS\
728 and 'doc' not in COMMAND_LINE_TARGETS\
729 and 'web' not in COMMAND_LINE_TARGETS\
730 and 'install' not in COMMAND_LINE_TARGETS\
731 and 'clean' not in COMMAND_LINE_TARGETS:
732 subdirs = ['lily', 'lily/include', 'flower', 'flower/include', 'mf']
733 else:
734 subdirs = flatten (cvs_dirs ('.'), [])
735 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
736 foo = map (lambda x: env.TXT (x + '.txt',
737 os.path.join ('Documentation/topdocs', x)),
738 readme_files)
739 txt_files = map (lambda x: x + '.txt', readme_files)
740 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
741 tar_base = package.name + '-' + version
742 tar_name = tar_base + '.tar.gz'
743 ball_prefix = os.path.join (outdir, tar_base)
744 tar_ball = os.path.join (outdir, tar_name)
746 dist_files = src_files + txt_files
747 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
748 map (lambda x: env.Depends (tar_ball, x), ball_files)
749 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
750 'ln $SOURCE $TARGET'), dist_files)
751 tar = env.Command (tar_ball, src_files,
752 ['rm -f $$(find $TARGET.dir -name .sconsign)',
753 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
754 env.Alias ('tar', tar)
756 dist_ball = os.path.join (package.release_dir, tar_name)
757 env.Command (dist_ball, tar_ball,
758 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
759 + 'ln $SOURCE $TARGET')
760 env.Depends ('dist', dist_ball)
761 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
762 patch = env.PATCH (patch_name, tar_ball)
763 env.Depends (patch_name, dist_ball)
764 env.Alias ('release', patch)
766 #### web
767 web_base = os.path.join (outdir, 'web')
768 web_ball = web_base + '.tar.gz'
769 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
770 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
771 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"')
772 env['web_path'] = web_path
773 web_list = os.path.join (outdir, 'weblist')
774 # compatible make heritits
775 # fixme: generate in $outdir is cwd/builddir
776 env.Command (web_list,
777 ## this is correct, but takes > 5min if you have a peder :-)
778 ##'doc',
779 '#/VERSION',
780 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
781 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
782 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
783 'cd $absbuild && find Documentation input $web_path \
784 > $TARGET',
785 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
786 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
787 'cd $absbuild && ls *.html >> $TARGET',])
788 env.Command (web_ball, web_list,
789 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
790 #env.Alias ('web', web_ball)
791 www_base = os.path.join (outdir, 'www')
792 www_ball = www_base + '.tar.gz'
793 env.Command (www_ball, web_ball,
794 ['rm -rf $out/tmp',
795 'mkdir -p $absbuild/$out/tmp',
796 'tar -C $absbuild/$out/tmp -xzf $SOURCE',
797 'cd $absbuild/$out/tmp && for i in $$(find . -name "$out"); do mv $$i $$(dirname $$i)/out-www; done',
798 'tar -C $absbuild/$out/tmp -czf $TARGET .'])
799 env.Alias ('web', www_ball)
801 #### tags
802 env.Append (
803 ETAGSFLAGS = """--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\\1/' \
804 --regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\\1/'""")
805 code_ext = ['.cc', '.hh', '.scm', '.tcc',]
806 env.Command ('TAGS', filter (lambda x: os.path.splitext (x)[1] in code_ext,
807 src_files),
808 'etags $ETAGSFLAGS $SOURCES')
810 # Note: SConscripts are only needed in directories where something needs
811 # to be done, building or installing
812 for d in subdirs:
813 if os.path.exists (os.path.join (d, 'SConscript')):
814 b = os.path.join (env['build'], d, env['out'])
815 # Support clean sourcetree build (--srcdir build)
816 # and ./out build.
817 if os.path.abspath (b) != os.path.abspath (d):
818 env.BuildDir (b, d, duplicate = 0)
819 SConscript (os.path.join (b, 'SConscript'))