(make_ps_images): Escape newline.
[lilypond/patrick.git] / SConstruct
blob6246d5268ef9cdb61336fdb5db4ff3c14d808d64
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 CPPDEFINES = '-DHAVE_CONFIG_H',
154 PERL = '/usr/bin/perl',
155 PYTHON = '/usr/bin/python',
156 SH = '/bin/sh',
158 MAKEINFO = 'LANG= makeinfo',
159 MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
161 PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
162 'usr/pkg/gnome/lib'),
163 os.path.join (os.environ['HOME'],
164 'usr/pkg/pango/lib')],
165 GZIP='-9v',
166 MFMODE = 'ljfour',
167 TOPLEVEL_VERSION = version,
170 # Add all config_vars to opts, so that they will be read and saved
171 # together with the other configure options.
172 map (lambda x: opts.AddOptions ((x,)), config_vars)
174 Help (usage + opts.GenerateHelpText (env))
176 opts.Update (env)
178 if env['fast']:
179 # Usability switch (Anthony Roach).
180 # See http://www.scons.org/cgi-bin/wiki/GoFastButton
181 # First do: scons realclean .
182 env['checksums'] = 0
183 SetOption ('max_drift', 1)
184 SetOption ('implicit_cache', 1)
185 elif env['checksums']:
186 # Always use checksums (makes more sense than timestamps).
187 SetOption ('max_drift', 0)
188 # Using *content* checksums prevents rebuilds after
189 # [re]configure if config.hh has not changed. Too bad that it
190 # is unusably slow.
191 TargetSignatures ('content')
193 absbuild = Dir (env['build']).abspath
194 outdir = os.path.join (Dir (env['build']).abspath, env['out'])
195 run_prefix = os.path.join (absbuild, os.path.join (env['out'], 'usr'))
198 config_hh = os.path.join (outdir, 'config.hh')
199 version_hh = os.path.join (outdir, 'version.hh')
201 env.Alias ('config', config_cache)
203 cachedir = os.path.join (outdir, 'build-cache')
205 if not os.path.exists (cachedir):
206 os.makedirs (cachedir)
208 CacheDir (cachedir)
210 # No need to set $LILYPONDPREFIX to run lily, but cannot install...
211 if env['debugging'] and not 'install' in COMMAND_LINE_TARGETS:
212 env['prefix'] = run_prefix
214 prefix = env['prefix']
215 bindir = os.path.join (prefix, 'bin')
216 sharedir = os.path.join (prefix, 'share')
217 libdir = os.path.join (prefix, 'lib')
218 localedir = os.path.join (sharedir, 'locale')
219 sharedir_doc_package = os.path.join (sharedir, 'doc', package.name)
220 sharedir_package = os.path.join (sharedir, package.name)
221 sharedir_package_version = os.path.join (sharedir_package, version)
222 lilypondprefix = sharedir_package_version
224 # junkme
225 env.Append (
226 absbuild = absbuild,
227 srcdir = srcdir,
231 def list_sort (lst):
232 sorted = lst
233 sorted.sort ()
234 return sorted
237 def configure (target, source, env):
238 vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
239 def get_version (program):
240 command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
241 pipe = os.popen (command)
242 output = pipe.read ()
243 if pipe.close ():
244 return None
245 v = re.sub (vre, '\\1', output)
246 return string.split (v, '.')
248 def test_program (lst, program, minimal, description, package):
249 sys.stdout.write ('Checking %s version... ' % program)
250 actual = get_version (program)
251 if not actual:
252 print 'not found'
253 lst.append ((description, package, minimal, program,
254 'not installed'))
255 return
256 sys.stdout.write (string.join (actual, '.'))
257 sys.stdout.write ('\n')
258 if actual < string.split (minimal, '.'):
259 lst.append ((description, package, minimal, program,
260 string.join (actual, '.')))
262 for i in ['bash', 'perl', 'python', 'sh']:
263 sys.stdout.write ('Checking for %s... ' % i)
264 c = WhereIs (i)
265 key = string.upper (i)
266 if c:
267 env[key] = c
268 sys.stdout.write (c)
269 else:
270 sys.stdout.write ('not found: %s (using: %s)' \
271 % (c, env[key]))
272 # Hmm? abort?
273 sys.stdout.write ('\n')
275 required = []
276 test_program (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
277 test_program (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
278 test_program (required, 'python', '2.1', 'Python (www.python.org)', 'python')
279 test_program (required, 'guile-config', '1.6', 'GUILE development',
280 'libguile-dev or guile-devel')
281 # Do not use bison 1.50 and 1.75.
282 test_program (required, 'bison', '1.25', 'Bison -- parser generator',
283 'bison')
284 test_program (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
287 optional = []
288 test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
289 test_program (optional, 'guile', '1.6', 'GUILE scheme',
290 'libguile-dev or guile-devel')
291 test_program (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
292 'mftrace')
293 test_program (optional, 'perl', '4.0',
294 'Perl practical efficient readonly language', 'perl')
295 #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
297 def CheckYYCurrentBuffer (context):
298 context.Message ('Checking for yy_current_buffer... ')
299 ret = conf.TryCompile ("""using namespace std;
300 #include <FlexLexer.h>
301 class yy_flex_lexer: public yyFlexLexer
303 public:
304 yy_flex_lexer ()
306 yy_current_buffer = 0;
308 };""", '.cc')
309 context.Result (ret)
310 return ret
312 conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
313 : CheckYYCurrentBuffer })
315 defines = {
316 'DIRSEP' : "'%s'" % os.sep,
317 'PATHSEP' : "'%s'" % os.pathsep,
318 'TOPLEVEL_VERSION' : '"' + version + '"',
319 'PACKAGE': '"' + package.name + '"',
320 'DATADIR' : '"' + sharedir + '"',
321 'LILYPOND_DATADIR' : '"' + sharedir_package + '"',
322 'LOCAL_LILYPOND_DATADIR' : '"' + sharedir_package_version + '"',
323 'LOCALEDIR' : '"' + localedir + '"',
325 conf.env.Append (DEFINES = defines)
327 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
328 PYTHON_INCLUDE = os.popen (command).read ()
329 if env['fast']:
330 env.Append (CCFLAGS = ['-I%s ' % PYTHON_INCLUDE])
331 else:
332 env.Append (CPPPATH = PYTHON_INCLUDE)
334 headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'libio.h',
335 'Python.h')
336 for i in headers:
337 if conf.CheckCHeader (i):
338 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
339 conf.env['DEFINES'][key] = 1
341 ccheaders = ('sstream',)
342 for i in ccheaders:
343 if conf.CheckCXXHeader (i):
344 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
345 conf.env['DEFINES'][key] = 1
347 functions = ('fopencookie', 'funopen',
348 'gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
349 for i in functions:
350 if 0 or conf.CheckFunc (i):
351 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
352 conf.env['DEFINES'][key] = 1
354 if conf.CheckYYCurrentBuffer ():
355 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
357 if conf.CheckLib ('dl'):
358 pass
360 if conf.CheckLib ('kpathsea'):
361 conf.env['DEFINES']['KPATHSEA'] = 1
363 # huh?
364 if conf.CheckLib ('kpathsea', 'kpse_find_file'):
365 conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
366 if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
367 conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
369 # FIXME fc3 - move to kpath-guile/SConscript?
370 conf.env['DEFINES']['HAVE_LIBKPATHSEA_SO'] = '1'
372 if env['fast']:
373 cpppath = []
374 if env.has_key ('CPPPATH'):
375 cpppath = env['CPPPATH']
377 ## FIXME: linkage, check for libguile.h and scm_boot_guile
378 #this could happen after flower...
379 env.ParseConfig ('guile-config compile')
381 ## FIXME: pkg-test to required/optional
382 if os.system ('pkg-config --atleast-version=1.6.0 pango'):
383 barf
384 env.ParseConfig ('pkg-config --cflags --libs pango')
385 conf.env['DEFINES']['HAVE_PANGO16'] = '1'
387 if os.system ('pkg-config --atleast-version=1.6.0 pangoft2'):
388 barf
389 env.ParseConfig ('pkg-config --cflags --libs pangoft2')
390 conf.env['DEFINES']['HAVE_PANGO_FT2'] = '1'
392 #this could happen only for compiling pango-*
393 if env['gui']:
394 env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
395 env.ParseConfig ('pkg-config --cflags --libs pango')
396 if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
397 conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
399 if conf.CheckLib ('pango-1.0',
400 'pango_fc_font_map_add_decoder_find_func'):
401 conf.env['DEFINES']['HAVE_PANGO_CVS'] = '1'
402 conf.env['DEFINES']['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
404 if env['fast']:
405 # Using CCFLAGS = -I<system-dir> rather than CPPPATH = [
406 # <system-dir>] speeds up SCons
407 env['CCFLAGS'] += map (lambda x: '-I' + x,
408 env['CPPPATH'][len (cpppath):])
409 env['CPPPATH'] = cpppath
411 if required:
412 print
413 print '********************************'
414 print 'Please install required packages'
415 for i in required:
416 print '%s: %s-%s or newer (found: %s %s)' % i
417 Exit (1)
419 if optional:
420 print
421 print '*************************************'
422 print 'Consider installing optional packages'
423 for i in optional:
424 print '%s: %s-%s or newer (found: %s %s)' % i
426 return conf.Finish ()
428 def config_header (target, source, env):
429 config = open (str (target[0]), 'w')
430 for i in list_sort (env['DEFINES'].keys ()):
431 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
432 config.close ()
433 env.Command (config_hh, config_cache, config_header)
435 # hmm?
436 def xuniquify (lst):
437 n = []
438 for i in lst:
439 if not i in n:
440 n.append (i)
441 lst = n
442 return lst
444 def uniquify (lst):
445 d = {}
446 n = len (lst)
447 i = 0
448 while i < n:
449 if not d.has_key (lst[i]):
450 d[lst[i]] = 1
451 i += 1
452 else:
453 del lst[i]
454 n -= 1
455 return lst
457 def uniquify_config_vars (env):
458 for i in config_vars:
459 if env.has_key (i) and type (env[i]) == type ([]):
460 env[i] = uniquify (env[i])
462 def save_config_cache (env):
463 ## FIXME: Is this smart, using option cache for saving
464 ## config.cache? I cannot seem to find the official method.
465 uniquify_config_vars (env)
466 opts.Save (config_cache, env)
468 if 'config' in COMMAND_LINE_TARGETS:
469 sys.stdout.write ('\n')
470 sys.stdout.write ('LilyPond configured')
471 sys.stdout.write ('\n')
472 sys.stdout.write ('now run')
473 sys.stdout.write ('\n')
474 sys.stdout.write (' scons [TARGET|DIR]...')
475 sys.stdout.write ('\n')
476 Exit (0)
477 elif not env['checksums']:
478 # When using timestams, config.hh is NEW. The next
479 # build triggers recompilation of everything. Exiting
480 # here makes SCons use the actual timestamp for config.hh
481 # and prevents recompiling everything the next run.
482 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
483 sys.stdout.write ('Running %s ... ' % command)
484 sys.stdout.write ('\n')
485 s = os.system (command)
486 Exit (s)
489 if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
490 os.unlink (config_cache)
491 # WTF?
492 # scons: *** Calling Configure from Builders is not supported.
493 # env.Command (config_cache, None, configure)
494 if not os.path.exists (config_cache) \
495 or (os.stat ('SConstruct')[stat.ST_MTIME]
496 > os.stat (config_cache)[stat.ST_MTIME]):
497 env = configure (None, None, env)
498 save_config_cache (env)
499 elif env['checksums']:
500 # just save everything
501 save_config_cache (env)
503 #urg how does #/ subst work?
504 Export ('env')
505 SConscript ('buildscripts/builder.py')
507 env.PrependENVPath ('PATH',
508 os.path.join (env['absbuild'], env['out'], 'usr/bin'))
510 if os.environ.has_key ('TEXMF'):
511 env.Append (ENV = {'TEXMF' : os.environ['TEXMF']})
512 env.Append (ENV = {
513 'TEXMF' : '{$LILYPONDPREFIX,' \
514 + os.popen ('kpsexpand \$TEXMF').read ()[:-1] + '}',
515 'LILYPONDPREFIX' : os.path.join (run_prefix, 'share/lilypond'),
518 BUILD_ABC2LY = '${set__x}$PYTHON $srcdir/scripts/abc2ly.py'
519 BUILD_LILYPOND = '${set__x}$PYTHON $srcdir/scripts/lilypond.py${__verbose}'
520 BUILD_LILYPOND_BIN = '$absbuild/$out/lilypond-bin ${__verbose}'
521 BUILD_LILYPOND_BOOK = '$PYTHON $srcdir/scripts/lilypond-book.py --verbose'
524 # post-option environment-update
525 env.Append (
526 bindir = bindir,
527 sharedir = sharedir,
528 lilypond_datadir = sharedir_package,
529 localedir = localedir,
530 local_lilypond_datadir = sharedir_package_version,
531 lilypondprefix = lilypondprefix,
532 sharedir_package = sharedir_package,
533 sharedir_doc_package = sharedir_doc_package,
534 sharedir_package_version = sharedir_package_version,
536 LILYPOND = BUILD_LILYPOND,
537 ABC2LY = BUILD_ABC2LY,
538 LILYPOND_BOOK = BUILD_LILYPOND_BOOK,
539 LILYPOND_BOOK_FORMAT = 'texi-html',
540 MAKEINFO_FLAGS = '--css-include=$srcdir/Documentation/texinfo.css',
542 TEXI2DVI_PAPERSIZE = '@afourpaper',
543 TEXI2DVI_FLAGS = [ '-t $TEXI2DVI_PAPERSIZE'],
544 DVIPS_PAPERSIZE = 'a4',
545 DVIPS_FLAGS = ['-t $DVIPS_PAPERSIZE',
546 '-u+lilypond.map',
547 '-u+ec-mftrace.map'],
548 PSPDF_FLAGS = ['-sPAPERSIZE=$DVIPS_PAPERSIZE'],
551 if env['debugging']:
552 env.Append (CCFLAGS = ['-g', '-pipe'])
553 if env['optimising']:
554 env.Append (CCFLAGS = '-O2')
555 env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
556 if env['warnings']:
557 env.Append (CCFLAGS = ['-W', '-Wall'])
558 env.Append (CXXFLAGS = ['-Wconversion'])
560 # ugr,huh?
561 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
563 if env['verbose']:
564 env['__verbose'] = ' --verbose'
565 env['set__x'] = 'set -x;'
568 ## Explicit target and dependencies
570 if 'clean' in COMMAND_LINE_TARGETS:
571 # ugh: prevent reconfigure instead of clean
572 os.system ('touch %s' % config_cache)
574 command = sys.argv[0] + ' -c .'
575 sys.stdout.write ('Running %s ... ' % command)
576 sys.stdout.write ('\n')
577 s = os.system (command)
578 if os.path.exists (config_cache):
579 os.unlink (config_cache)
580 Exit (s)
582 if 'sconsclean' in COMMAND_LINE_TARGETS:
583 command = 'rm -rf scons.cache $(find . -name ".scon*")'
584 s = os.system (command)
585 if os.path.exists (config_cache):
586 os.unlink (config_cache)
587 Exit (s)
589 if 'realclean' in COMMAND_LINE_TARGETS:
590 command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
591 sys.stdout.write ('Running %s ... ' % command)
592 sys.stdout.write ('\n')
593 s = os.system (command)
594 if os.path.exists (config_cache):
595 os.unlink (config_cache)
596 Exit (s)
598 # Declare SConscript phonies
599 env.Alias ('minimal', config_cache)
600 env.Alias ('mf-essential', config_cache)
602 env.Alias ('minimal', ['lily', 'mf-essential'])
603 env.Alias ('all', ['minimal', 'mf', '.'])
604 # Do we want the doc/web separation?
605 env.Alias ('doc',
606 ['Documentation',
607 'Documentation/user',
608 'Documentation/topdocs',
609 'Documentation/bibliography',
610 'input'])
612 # Without target arguments, do minimal build
613 if not COMMAND_LINE_TARGETS:
614 env.Default (['minimal'])
616 # GNU Make rerouting compat:
617 env.Alias ('web', 'doc')
620 env.Command (version_hh, '#/VERSION',
621 '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
623 # post-config environment update
624 env.Append (
625 run_prefix = run_prefix,
626 LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond'),
628 # FIXME: move to lily/SConscript?
629 LIBPATH = [os.path.join (absbuild, 'flower', env['out']),
630 os.path.join (absbuild, 'kpath-guile', env['out']),
631 os.path.join (absbuild, 'ttftool', env['out']),],
632 CPPPATH = [outdir, ],
633 LILYPOND_PATH = ['.', '$srcdir/input',
634 '$srcdir/input/regression',
635 '$srcdir/input/test',
636 '$srcdir/input/tutorial',
637 '$srcdir/Documentation/user',
638 '$absbuild/mf/$out',
639 # os.path.join (absbuild, 'Documentation',
640 # env['out']),
641 # os.path.join (absbuild, 'Documentation/user',
642 # env['out']),
644 MAKEINFO_PATH = ['.', '$srcdir/Documentation/user',
645 '$absbuild/Documentation/user/$out'],
648 def symlink_tree (target, source, env):
649 def mkdirs (dir):
650 def mkdir (dir):
651 if not dir:
652 os.chdir (os.sep)
653 return
654 if not os.path.isdir (dir):
655 if os.path.exists (dir):
656 os.unlink (dir)
657 os.mkdir (dir)
658 os.chdir (dir)
659 map (mkdir, string.split (dir, os.sep))
660 def symlink (src, dst):
661 os.chdir (absbuild)
662 dir = os.path.dirname (dst)
663 mkdirs (dir)
664 if src[0] == '#':
665 frm = os.path.join (srcdir, src[1:])
666 else:
667 depth = len (string.split (dir, '/'))
668 if src.find ('@') > -1:
669 frm = os.path.join ('../' * depth,
670 string.replace (src, '@',
671 env['out']))
672 else:
673 frm = os.path.join ('../' * depth, src,
674 env['out'])
675 if src[-1] == '/':
676 frm = os.path.join (frm, os.path.basename (dst))
677 if env['verbose']:
678 print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
679 os.symlink (frm, os.path.basename (dst))
680 shutil.rmtree (run_prefix)
681 prefix = os.path.join (env['out'], 'usr')
682 map (lambda x: symlink (x[0], os.path.join (prefix,
683 x[1] % {'ver' : version})),
684 # ^# := source dir
685 # @ := out
686 # /$ := add dst file_name
687 (('python', 'lib/lilypond/python'),
688 ('lily/', 'bin/lilypond'),
689 ('scripts/', 'bin/convert-ly'),
690 ('scripts/', 'bin/lilypond-book'),
691 ('scripts/', 'bin/ps2png'),
692 ('mf', 'share/lilypond/%(ver)s/dvips/mf-out'),
693 ('#ps', 'share/lilypond/%(ver)s/dvips/ps'),
694 ('#ps', 'share/lilypond/%(ver)s/tex/music-drawing-routines.ps'),
695 ('mf', 'share/lilypond/%(ver)s/otf'),
696 ('mf', 'share/lilypond/%(ver)s/tfm'),
697 ('tex', 'share/lilypond/%(ver)s/tex/enc'),
698 ('#mf', 'share/lilypond/%(ver)s/fonts/mf'),
699 ('mf', 'share/lilypond/%(ver)s/fonts/map'),
700 ('mf', 'share/lilypond/%(ver)s/fonts/otf'),
701 ('mf', 'share/lilypond/%(ver)s/fonts/tfm'),
702 ('mf', 'share/lilypond/%(ver)s/fonts/type1'),
703 ('#tex', 'share/lilypond/%(ver)s/tex/source'),
704 ('tex', 'share/lilypond/%(ver)s/tex/tex-out'),
705 ('mf', 'share/lilypond/%(ver)s/tex/mf-out'),
706 ('#ly', 'share/lilypond/%(ver)s/ly'),
707 ('#scm', 'share/lilypond/%(ver)s/scm'),
708 ('#scripts', 'share/lilypond/%(ver)s/scripts'),
709 ('#ps', 'share/lilypond/%(ver)s/ps'),
710 ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
711 ('elisp', 'share/lilypond/%(ver)s/elisp')))
712 os.chdir (srcdir)
714 if env['debugging']:
715 stamp = os.path.join (run_prefix, 'stamp')
716 env.Command (stamp, 'SConstruct', [symlink_tree, 'touch $TARGET'])
717 env.Depends ('lily', stamp)
719 #### dist, tar
720 def plus (a, b):
721 a + b
723 def cvs_entry_is_dir (line):
724 return line[0] == 'D' and line[-2] == '/'
726 def cvs_entry_is_file (line):
727 return line[0] == '/' and line[-2] == '/'
729 def cvs_dirs (dir):
730 ENTRIES = os.path.join (dir, 'CVS/Entries')
731 if not os.path.exists (ENTRIES):
732 return []
733 entries = open (ENTRIES).readlines ()
734 dir_entries = filter (cvs_entry_is_dir, entries)
735 dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
736 dir_entries)
737 return dirs + map (cvs_dirs, dirs)
739 def cvs_files (dir):
740 ENTRIES = os.path.join (dir, 'CVS/Entries')
741 entries = open (ENTRIES).readlines ()
742 file_entries = filter (cvs_entry_is_file, entries)
743 files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
744 return map (lambda x: os.path.join (dir, x), files)
746 def flatten (tree, lst):
747 if type (tree) == type ([]):
748 for i in tree:
749 if type (i) == type ([]):
750 flatten (i, lst)
751 else:
752 lst.append (i)
753 return lst
755 if env['fast']\
756 and 'all' not in COMMAND_LINE_TARGETS\
757 and 'doc' not in COMMAND_LINE_TARGETS\
758 and 'web' not in COMMAND_LINE_TARGETS\
759 and 'install' not in COMMAND_LINE_TARGETS\
760 and 'clean' not in COMMAND_LINE_TARGETS:
761 subdirs = ['lily', 'lily/include',
762 'flower', 'flower/include',
763 'kpath-guile',
764 'ttftool',
765 'mf',
767 else:
768 subdirs = flatten (cvs_dirs ('.'), [])
770 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
771 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
772 txt_files = map (lambda x: x + '.txt', readme_files)
776 # speeds up build by +- 5%
778 if not env['fast']:
779 foo = map (lambda x: env.TXT (x + '.txt',
780 os.path.join ('Documentation/topdocs', x)),
781 readme_files)
782 tar_base = package.name + '-' + version
783 tar_name = tar_base + '.tar.gz'
784 ball_prefix = os.path.join (outdir, tar_base)
785 tar_ball = os.path.join (outdir, tar_name)
787 dist_files = src_files + txt_files
788 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
789 map (lambda x: env.Depends (tar_ball, x), ball_files)
790 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
791 'ln $SOURCE $TARGET'), dist_files)
792 tar = env.Command (tar_ball, src_files,
793 ['rm -f $$(find $TARGET.dir -name .sconsign)',
794 'tar czf $TARGET -C $TARGET.dir %s' % tar_base,])
795 env.Alias ('tar', tar)
797 dist_ball = os.path.join (package.release_dir, tar_name)
798 env.Command (dist_ball, tar_ball,
799 'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
800 + 'ln $SOURCE $TARGET')
801 env.Depends ('dist', dist_ball)
802 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
803 patch = env.PATCH (patch_name, tar_ball)
804 env.Depends (patch_name, dist_ball)
805 env.Alias ('release', patch)
807 #### web
808 if not env['fast']:
809 web_base = os.path.join (outdir, 'web')
810 web_ball = web_base + '.tar.gz'
811 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$TOPLEVEL_VERSION'
812 web_ext = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
813 web_path = '-path "*/$out/*"' + string.join (web_ext, ' -or -path "*/$out/*"')
814 env['web_path'] = web_path
815 web_list = os.path.join (outdir, 'weblist')
816 # compatible make heritits
817 # fixme: generate in $outdir is cwd/builddir
818 env.Command (web_list,
819 ## this is correct, but takes > 5min if you have a peder :-)
820 ##'doc',
821 '#/VERSION',
822 ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
823 'cd $absbuild && $footify $$(find . -name "*.html" -print)',
824 'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
825 'cd $absbuild && find Documentation input $web_path \
826 > $TARGET',
827 '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
828 '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
829 'cd $absbuild && ls *.html >> $TARGET',])
830 env.Command (web_ball, web_list,
831 ['cat $SOURCE | tar -C $absbuild -czf $TARGET -T -',])
832 #env.Alias ('web', web_ball)
833 www_base = os.path.join (outdir, 'www')
834 www_ball = www_base + '.tar.gz'
835 env.Command (www_ball, web_ball,
836 ['rm -rf $out/tmp',
837 'mkdir -p $absbuild/$out/tmp',
838 'tar -C $absbuild/$out/tmp -xzf $SOURCE',
839 'cd $absbuild/$out/tmp && for i in $$(find . -name "$out"); '
840 + ' do mv $$i $$(dirname $$i)/out-www; done',
841 'tar -C $absbuild/$out/tmp -czf $TARGET .'])
842 env.Alias ('web', www_ball)
844 #### tags
845 env.Append (
846 ETAGSFLAGS = """--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\\1/' \
847 --regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\\1/'""")
848 code_ext = ['.cc', '.hh', '.scm', '.tcc',]
849 env.Command ('TAGS', filter (lambda x: os.path.splitext (x)[1] in code_ext,
850 src_files),
851 'etags $ETAGSFLAGS $SOURCES')
853 # Note: SConscripts are only needed in directories where something needs
854 # to be done, building or installing
855 for d in subdirs:
856 if os.path.exists (os.path.join (d, 'SConscript')):
857 b = os.path.join (env['build'], d, env['out'])
858 # Support clean sourcetree build (--srcdir build)
859 # and ./out build.
860 if os.path.abspath (b) != os.path.abspath (d):
861 env.BuildDir (b, d, duplicate = 0)
862 SConscript (os.path.join (b, 'SConscript'))