]> git.donarmstrong.com Git - lilypond.git/blob - SConstruct
* lily/slur.cc: Add quant-score to interface. Fixes web build.
[lilypond.git] / SConstruct
1 # -*-python-*-
2
3 '''
4 Experimental scons (www.scons.org) building.
5
6 Usage
7
8     scons TARGET
9
10 build from source directory ./TARGET (not recursive)
11
12 Configure, build
13
14     scons [config]             # configure
15     scons                      # build all
16
17 Run from build tree
18
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
23
24     #optionally, if you do not use custom.py below
25     #export LILYPONDPREFIX=$run/share/lilypond
26
27     lilypond-bin input/simple
28
29 Other targets
30     scons mf-essential         # build minimal mf stuff
31
32     scons doc                  # build web doc
33     scons config               # reconfigure
34     scons install              # install
35     scons -c                   # clean
36     scons -h                   # help
37
38     scons /                    # build *everything* (including installation)
39
40 Options  (see scons -h)
41     scons build=DIR            # clean scrdir build, output below DIR
42     scons out=DIR              # write output for alterative config to DIR
43
44 Debugging
45     scons --debug=dtree
46     scons --debug=explain
47     scons verbose=1
48
49 Optional custom.py
50
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')
58
59 '''
60
61
62 # TODO:
63 #  * install doc
64
65 #  * more program configure tests (mfont, ...?)
66
67 #  * split doc target: doc input examples mutopia?
68
69 #  * more fine-grained config.hh -- move lilypondprefix to version.hh?
70 #    - config.hh:   changes after system upgrades, affects all files
71 #    - version.hh:  prefix, version etc?  affects few
72
73 #    - what about GUILE_*_VERSION, seems to be the major culprit,
74 #      for config.hh dependency escalation.  Is the lily-guile.hh
75 #      workaround necessary at all for GUILE > 1.5?
76
77 #  * grep FIXME $(find . -name 'S*t')
78
79
80 import re
81 import glob
82 import os
83 import string
84 import sys
85 import stat
86 import shutil
87
88 # duh, we need 0.95.1
89 EnsureSConsVersion (0, 95)
90
91 usage = r'''Usage:
92 scons [KEY=VALUE].. [TARGET|DIR]..
93
94 TARGETS: clean, config, doc, dist, install, mf-essential, po-update,
95          realclean, release, tar, TAGS
96
97 '''
98       
99
100 config_cache = 'scons.cache'
101
102 config_vars = [
103         'BASH',
104         'CCFLAGS',
105         'CPPPATH',
106         'CPPDEFINES',
107         'CXXFLAGS',
108         'DEFINES',
109         'LIBS',
110         'LINKFLAGS',
111         'METAFONT',
112         'PERL',
113         'PYTHON',
114         ]
115
116 # Put your favourite stuff in custom.py
117 opts = Options ([config_cache, 'custom.py'], ARGUMENTS)
118 opts.Add ('prefix', 'Install prefix', '/usr/')
119 opts.Add ('out', 'Output directory', 'out-scons')
120 opts.Add ('build', 'Build directory', '.')
121 opts.AddOptions (
122         BoolOption ('warnings', 'compile with -Wall and similiar',
123                    1),
124         BoolOption ('debugging', 'compile with debugging symbols',
125                     0),
126         BoolOption ('optimising', 'compile with optimising',
127                     1),
128         BoolOption ('shared', 'build shared libraries',
129                     0),
130         BoolOption ('static', 'build static libraries',
131                     1),
132         BoolOption ('gui', 'build with GNOME backend (EXPERIMENTAL)',
133                     1),
134         BoolOption ('verbose', 'run commands with verbose flag',
135                     0),
136         BoolOption ('checksums', 'use checksums instead of timestamps',
137                     1),
138         )
139
140 srcdir = Dir ('.').srcnode ().abspath
141
142 #ugh
143 sys.path.append (os.path.join (srcdir, 'stepmake', 'bin'))
144 import packagepython
145 package = packagepython.Package (srcdir)
146 version = packagepython.version_tuple_to_str (package.version)
147
148 ENV = { 'PATH' : os.environ['PATH'] }
149 for key in ['LD_LIBRARY_PATH', 'GUILE_LOAD_PATH', 'PKG_CONFIG_PATH']:
150         if os.environ.has_key (key):
151                 ENV[key] = os.environ[key]
152
153 env = Environment (
154         ENV = ENV,
155         
156         BASH = '/bin/bash',
157         PERL = '/usr/bin/perl',
158         PYTHON = '/usr/bin/python',
159         SH = '/bin/sh',
160
161         MAKEINFO = 'LANG= makeinfo',
162         ABC2LY_PY = srcdir + '/scripts/abc2ly.py',
163         LILYPOND_BOOK = srcdir + '/scripts/lilypond-book.py',
164         LILYPOND_BOOK_FLAGS = '',
165         LILYPOND_BOOK_FORMAT = 'texi-html',
166         LILYPOND_PY = srcdir + '/scripts/lilypond.py',
167         MF_TO_TABLE_PY = srcdir + '/buildscripts/mf-to-table.py',
168         
169         PKG_CONFIG_PATH = [os.path.join (os.environ['HOME'],
170                                          'usr/pkg/gnome/lib'),
171                            os.path.join (os.environ['HOME'],
172                                          'usr/pkg/pango/lib')],
173         GZIP='-9v',
174         MFMODE = 'ljfour',
175         TEXINFO_PAPERSIZE_OPTION = '-t @afourpaper',
176         TOPLEVEL_VERSION = version,
177         )
178
179 # Add all config_vars to opts, so that they will be read and saved
180 # together with the other configure options.
181 map (lambda x: opts.AddOptions ((x,)), config_vars)
182
183 Help (usage + opts.GenerateHelpText (env))
184
185 opts.Update (env)
186
187 # Using content checksums prevents rebuilds after [re]configure if
188 # config.hh has not changed.
189 if env['checksums']:
190         SetOption ('max_drift', 0)
191         TargetSignatures ("content")
192
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'))
196
197 CacheDir (os.path.join (outdir, 'build-cache'))
198
199 if env['debugging']:
200         # No need to set $LILYPONDPREFIX to run lily, but cannot install...
201         env['prefix'] = run_prefix
202         
203 prefix = env['prefix']
204 bindir = os.path.join (prefix, 'bin')
205 sharedir = os.path.join (prefix, 'share')
206 libdir = os.path.join (prefix, 'lib')
207 localedir = os.path.join (sharedir, 'locale')
208 sharedir_package = os.path.join (sharedir, package.name)
209 sharedir_package_version = os.path.join (sharedir_package, version)
210 lilypondprefix = sharedir_package_version
211
212 # post-option environment-update
213 env.Append (
214         srcdir = srcdir,
215         
216         bindir = bindir,
217         sharedir = sharedir,
218         lilypond_datadir = sharedir_package,
219         localedir = localedir,
220         local_lilypond_datadir = sharedir_package_version,
221         lilypondprefix = lilypondprefix,
222         sharedir_package = sharedir_package,
223         sharedir_package_version = sharedir_package_version,
224         )
225
226 if env['debugging']:
227         env.Append (CCFLAGS = ['-g', '-pipe'])
228 if env['optimising']:
229         env.Append (CCFLAGS = '-O2')
230         env.Append (CXXFLAGS = ['-DSTRING_UTILS_INLINED'])
231 if env['warnings']:
232         env.Append (CCFLAGS = ['-W', '-Wall'])
233         env.Append (CXXFLAGS = ['-Wconversion'])
234
235 # ugr,huh?
236 env.Append (LINKFLAGS = ['-Wl,--export-dynamic'])
237
238 if env['verbose']:
239         env['__verbose'] = ' --verbose'
240         env['set__x'] = 'set -x;'
241
242 config_hh = os.path.join (outdir, 'config.hh')
243 version_hh = os.path.join (outdir, 'version.hh')
244
245 env.Alias ('config', config_cache)
246
247
248 ## Explicit target and dependencies
249
250 if 'clean' in COMMAND_LINE_TARGETS:
251         # ugh: prevent reconfigure instead of clean
252         os.system ('touch %s' % config_cache)
253         
254         command = sys.argv[0] + ' -c .'
255         sys.stdout.write ('Running %s ... ' % command)
256         sys.stdout.write ('\n')
257         s = os.system (command)
258         if os.path.exists (config_cache):
259                 os.unlink (config_cache)
260         Exit (s)
261
262 if 'realclean' in COMMAND_LINE_TARGETS:
263         command = 'rm -rf $(find . -name "out-scons" -o -name ".scon*")'
264         sys.stdout.write ('Running %s ... ' % command)
265         sys.stdout.write ('\n')
266         s = os.system (command)
267         if os.path.exists (config_cache):
268                 os.unlink (config_cache)
269         Exit (s)
270
271 # Declare SConscript phonies 
272 env.Alias ('minimal', config_cache)
273 env.Alias ('mf-essential', config_cache)
274
275 env.Alias ('minimal', ['lily', 'mf-essential'])
276 env.Alias ('all', ['minimal', 'mf', '.'])
277 # Do we want the doc/web separation?
278 env.Alias ('doc',
279            ['Documentation',
280             'Documentation/user',
281             'Documentation/topdocs',
282             'Documentation/bibliography',
283             'input'])
284
285 # Without target arguments, do minimal build
286 if not COMMAND_LINE_TARGETS:
287         env.Default (['minimal'])
288
289 # GNU Make rerouting compat:
290 env.Alias ('web', 'doc')
291
292 def list_sort (lst):
293         sorted = lst
294         sorted.sort ()
295         return sorted
296
297 def configure (target, source, env):
298         vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
299         def get_version (program):
300                 command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
301                 pipe = os.popen (command)
302                 output = pipe.read ()
303                 if pipe.close ():
304                         return None
305                 v = re.sub (vre, '\\1', output)
306                 return string.split (v, '.')
307
308         def test_program (lst, program, minimal, description, package):
309                 sys.stdout.write ('Checking %s version... ' % program)
310                 actual = get_version (program)
311                 if not actual:
312                         print 'not found'
313                         lst.append ((description, package, minimal, program,
314                                      'not installed'))
315                         return
316                 sys.stdout.write (string.join (actual, '.'))
317                 sys.stdout.write ('\n')
318                 if actual < string.split (minimal, '.'):
319                         lst.append ((description, package, minimal, program,
320                                      string.join (actual, '.')))
321
322         for i in ['bash', 'perl', 'python', 'sh']:
323                 sys.stdout.write ('Checking for %s... ' % i)
324                 c = WhereIs (i)
325                 key = string.upper (i)
326                 if c:
327                         env[key] = c
328                         sys.stdout.write (c)
329                 else:
330                         sys.stdout.write ('not found: %s (using: %s)' \
331                                           % (c, env[key]))
332                         # Hmm? abort?
333                 sys.stdout.write ('\n')
334
335         required = []
336         test_program (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
337         test_program (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
338         test_program (required, 'python', '2.1', 'Python (www.python.org)', 'python')
339         test_program (required, 'guile-config', '1.6', 'GUILE development',
340                         'libguile-dev or guile-devel')
341         # Do not use bison 1.50 and 1.75.
342         test_program (required, 'bison', '1.25', 'Bison -- parser generator',
343                         'bison')
344         test_program (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
345
346
347         optional = []
348         test_program (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
349         test_program (optional, 'guile', '1.6', 'GUILE scheme',
350                         'libguile-dev or guile-devel')
351         test_program (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
352                         'mftrace')
353         test_program (optional, 'perl', '4.0',
354                         'Perl practical efficient readonly language', 'perl')
355         #test_program (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
356
357         def CheckYYCurrentBuffer (context):
358                 context.Message ('Checking for yy_current_buffer... ')
359                 ret = conf.TryCompile ("""using namespace std;
360                 #include <FlexLexer.h>
361                 class yy_flex_lexer: public yyFlexLexer
362                 {
363                 public:
364                 yy_flex_lexer ()
365                 {
366                 yy_current_buffer = 0;
367                 }
368                 };""", '.cc')
369                 context.Result (ret)
370                 return ret
371
372         conf = Configure (env, custom_tests = { 'CheckYYCurrentBuffer'
373                                                 : CheckYYCurrentBuffer })
374
375         defines = {
376            'DIRSEP' : "'%s'" % os.sep,
377            'PATHSEP' : "'%s'" % os.pathsep,
378            'TOPLEVEL_VERSION' : '"' + version + '"',
379            'PACKAGE': '"' + package.name + '"',
380            'DATADIR' : '"' + sharedir + '"',
381            'LILYPOND_DATADIR' : '"' + sharedir_package + '"',
382            'LOCAL_LILYPOND_DATADIR' : '"' + sharedir_package_version + '"',
383            'LOCALEDIR' : '"' + localedir + '"',
384         }
385         conf.env.Append (DEFINES = defines)
386
387         command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
388         PYTHON_INCLUDE = os.popen (command).read ()
389         env.Append (CPPPATH = PYTHON_INCLUDE)
390
391         headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
392         for i in headers:
393                 if conf.CheckCHeader (i):
394                         key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
395                         conf.env['DEFINES'][key] = 1
396
397         ccheaders = ('sstream',)
398         for i in ccheaders:
399                 if conf.CheckCXXHeader (i):
400                         key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
401                         conf.env['DEFINES'][key] = 1
402
403         functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
404         for i in functions:
405                 if 0 or conf.CheckFunc (i):
406                         key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
407                         conf.env['DEFINES'][key] = 1
408
409         if conf.CheckYYCurrentBuffer ():
410                 conf.env['DEFINES']['HAVE_FLEXLEXER_YY_CURRENT_BUFFER'] = 1
411
412         if conf.CheckLib ('dl'):
413                 pass
414
415         if conf.CheckLib ('kpathsea'):
416                 conf.env['DEFINES']['KPATHSEA'] = 1
417
418         # huh? 
419         if conf.CheckLib ('kpathsea', 'kpse_find_file'):
420                 conf.env['DEFINES']['HAVE_KPSE_FIND_FILE'] = '1'
421         if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
422                 conf.env['DEFINES']['HAVE_KPSE_FIND_TFM'] = '1'
423
424         #this could happen after flower...
425         env.ParseConfig ('guile-config compile')
426
427         #this could happen only for compiling pango-*
428         if env['gui']:
429                 env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
430                 env.ParseConfig ('pkg-config --cflags --libs pango')
431                 if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
432                         conf.env['DEFINES']['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
433
434                 if conf.CheckLib ('pango-1.0',
435                                   'pango_fc_font_map_add_decoder_find_func'):
436                         conf.env['DEFINES']['HAVE_PANGO_CVS'] = '1'
437                         conf.env['DEFINES']['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
438
439         if required:
440                 print
441                 print '********************************'
442                 print 'Please install required packages'
443                 for i in required:
444                         print '%s:      %s-%s or newer (found: %s %s)' % i
445                 Exit (1)
446
447         if optional:
448                 print
449                 print '*************************************'
450                 print 'Consider installing optional packages'
451                 for i in optional:
452                         print '%s:      %s-%s or newer (found: %s %s)' % i
453
454         return conf.Finish ()
455
456 def config_header (target, source, env):
457         config = open (str (target[0]), 'w')
458         for i in list_sort (env['DEFINES'].keys ()):
459                 config.write ('#define %s %s\n' % (i, env['DEFINES'][i]))
460         config.close ()
461 env.Command (config_hh, config_cache, config_header)
462
463 # hmm?
464 def xuniquify (lst):
465         n = []
466         for i in lst:
467                 if not i in n:
468                         n.append (i)
469         lst = n
470         return lst
471
472 def uniquify (lst):
473         d = {}
474         n = len (lst)
475         i = 0
476         while i < n:
477                 if not d.has_key (lst[i]):
478                         d[lst[i]] = 1
479                         i += 1
480                 else:
481                         del lst[i]
482                         n -= 1
483         return lst
484
485 def uniquify_config_vars (env):
486         for i in config_vars:
487                 if env.has_key (i) and type (env[i]) == type ([]):
488                         env[i] = uniquify (env[i])
489
490 def save_config_cache (env):
491         ## FIXME: Is this smart, using option cache for saving
492         ## config.cache?  I cannot seem to find the official method.
493         uniquify_config_vars (env)
494         opts.Save (config_cache, env)
495
496         if 'config' in COMMAND_LINE_TARGETS:
497                 sys.stdout.write ('\n')
498                 sys.stdout.write ('LilyPond configured')
499                 sys.stdout.write ('\n')
500                 sys.stdout.write ('now run')
501                 sys.stdout.write ('\n')
502                 sys.stdout.write ('    scons [TARGET|DIR]...')
503                 sys.stdout.write ('\n')
504                 Exit (0)
505         elif not env['checksums']:
506                 # When using timestams, config.hh is NEW.  The next
507                 # build triggers recompilation of everything.  Exiting
508                 # here makes SCons use the actual timestamp for config.hh
509                 # and prevents recompiling everything the next run.
510                 command = sys.argv[0] + ' ' + string.join (COMMAND_LINE_TARGETS)
511                 sys.stdout.write ('Running %s ... ' % command)
512                 sys.stdout.write ('\n')
513                 s = os.system (command)
514                 Exit (s)
515
516
517 if os.path.exists (config_cache) and 'config' in COMMAND_LINE_TARGETS:
518         os.unlink (config_cache)
519 # WTF?
520 # scons: *** Calling Configure from Builders is not supported.
521 # env.Command (config_cache, None, configure)
522 if not os.path.exists (config_cache) \
523    or (os.stat ('SConstruct')[stat.ST_MTIME]
524        > os.stat (config_cache)[stat.ST_MTIME]):
525         env = configure (None, None, env)
526         save_config_cache (env)
527 elif env['checksums']:
528         # just save everything
529         save_config_cache (env)
530
531 env.Command (version_hh, '#/VERSION',
532              '$PYTHON ./stepmake/bin/make-version.py VERSION > $TARGET')
533
534 # post-config environment update
535 env.Append (
536         absbuild = absbuild,
537         run_prefix = run_prefix,
538         LILYPONDPREFIX = os.path.join (run_prefix, 'share/lilypond'),
539
540         LIBPATH = [os.path.join (absbuild, 'flower', env['out']),],
541         ##CPPPATH = [outdir, '#',], # do not read auto*'s header
542         CPPPATH = [outdir, ],
543         LILYPOND_BIN = os.path.join (absbuild, 'lily', env['out'],
544                                      'lilypond-bin'),
545         LILYPOND_BOOK_PATH = ['.', '#/input', '#/input/regression',
546                               '#/input/test', '#/input/tutorial',
547                               os.path.join (absbuild, 'mf', env['out']),
548                               '#/Documentation/user',
549                               os.path.join (absbuild, 'Documentation',
550                                             env['out']),
551                               os.path.join (absbuild, 'Documentation/user',
552                                             env['out']),
553                               ],
554         MAKEINFO_PATH = ['.', '#/Documentation/user',
555                          os.path.join (absbuild, 'Documentation/user',
556                                        env['out'])],
557         )
558
559 Export ('env')
560 SConscript ('buildscripts/builder.py')
561
562
563 def symlink_tree (target, source, env):
564         def mkdirs (dir):
565                 def mkdir (dir):
566                         if not dir:
567                                 os.chdir (os.sep)
568                                 return
569                         if not os.path.isdir (dir):
570                                 if os.path.exists (dir):
571                                         os.unlink (dir)
572                                 os.mkdir (dir)
573                         os.chdir (dir)
574                 map (mkdir, string.split (dir, os.sep))
575         def symlink (src, dst):
576                 os.chdir (absbuild)
577                 dir = os.path.dirname (dst)
578                 mkdirs (dir)
579                 if src[0] == '#':
580                         frm = os.path.join (srcdir, src[1:])
581                 else:
582                         depth = len (string.split (dir, '/'))
583                         if src.find ('@') > -1:
584                                 frm = os.path.join ('../' * depth,
585                                                     string.replace (src, '@',
586                                                                     env['out']))
587                         else:
588                                 frm = os.path.join ('../' * depth, src,
589                                                     env['out'])
590                         if src[-1] == '/':
591                                 frm = os.path.join (frm, os.path.basename (dst))
592                 if env['verbose']:
593                         print 'ln -s %s -> %s' % (frm, os.path.basename (dst))
594                 os.symlink (frm, os.path.basename (dst))
595         shutil.rmtree (run_prefix)
596         prefix = os.path.join (env['out'], 'usr')
597         map (lambda x: symlink (x[0], os.path.join (prefix, x[1])),
598              # ^# := source dir
599              # @  := out
600              # /$ := add dst file_name
601              (('python',     'lib/lilypond/python'),
602               ('lily/',      'bin/lilypond-bin'),
603               ('scripts/',   'bin/lilypond'),
604               ('scripts/',   'bin/lilypond-book'),
605               ('#mf',        'share/lilypond/fonts/mf'),
606               ('mf',         'share/lilypond/fonts/afm'),
607               ('mf',         'share/lilypond/fonts/tfm'),
608               ('mf',         'share/lilypond/fonts/type1'),
609               ('#tex',       'share/lilypond/tex/source'),
610               ('mf',         'share/lilypond/tex/generate'),
611               ('#ly',        'share/lilypond/ly'),
612               ('#scm',       'share/lilypond/scm'),
613               ('#ps',        'share/lilypond/ps'),
614               ('po/@/nl.mo', 'share/locale/nl/LC_MESSAGES/lilypond.mo'),
615               ('elisp',      'share/lilypond/elisp')))
616         os.chdir (srcdir)
617
618 if env['debugging']:
619         stamp = os.path.join (run_prefix, 'stamp')
620         env.Command (stamp, 'SConstruct', [symlink_tree, 'touch $TARGET'])
621         env.Depends ('lily', stamp)
622         
623 #### dist, tar
624 def plus (a, b):
625         a + b
626
627 def cvs_entry_is_dir (line):
628         return line[0] == 'D' and line[-2] == '/'
629
630 def cvs_entry_is_file (line):
631         return line[0] == '/' and line[-2] == '/'
632
633 def cvs_dirs (dir):
634         ENTRIES = os.path.join (dir, 'CVS/Entries')
635         if not os.path.exists (ENTRIES):
636                 return []
637         entries = open (ENTRIES).readlines ()
638         dir_entries = filter (cvs_entry_is_dir, entries)
639         dirs = map (lambda x: os.path.join (dir, x[2:x[2:].index ('/')+3]),
640                     dir_entries)
641         return dirs + map (cvs_dirs, dirs)
642
643 def cvs_files (dir):
644         ENTRIES = os.path.join (dir, 'CVS/Entries')
645         entries = open (ENTRIES).readlines ()
646         file_entries = filter (cvs_entry_is_file, entries)
647         files = map (lambda x: x[1:x[1:].index ('/')+1], file_entries)
648         return map (lambda x: os.path.join (dir, x), files)
649
650 def flatten (tree, lst):
651         if type (tree) == type ([]):
652                 for i in tree:
653                         if type (i) == type ([]):
654                                 flatten (i, lst)
655                         else:
656                                 lst.append (i)
657         return lst
658
659 subdirs = flatten (cvs_dirs ('.'), [])
660 readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
661 foo = map (lambda x: env.TXT (x + '.txt',
662                               os.path.join ('Documentation/topdocs', x)),
663            readme_files)
664 txt_files = map (lambda x: x + '.txt', readme_files)
665 src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
666 tar_base = package.name + '-' + version
667 tar_name = tar_base + '.tar.gz'
668 ball_prefix = os.path.join (outdir, tar_base)
669 tar_ball = os.path.join (outdir, tar_name)
670
671 dist_files = src_files + txt_files
672 ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
673 map (lambda x: env.Depends (tar_ball, x), ball_files)
674 map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
675                             'ln $SOURCE $TARGET'), dist_files)
676 tar = env.Command (tar_ball, src_files,
677                    'tar czf $TARGET -C $TARGET.dir %s' % tar_base)
678 env.Alias ('tar', tar)
679
680 dist_ball = os.path.join (package.release_dir, tar_name)
681 env.Command (dist_ball, tar_ball,
682              'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
683              + 'ln $SOURCE $TARGET')
684 env.Depends ('dist', dist_ball)
685 patch_name = os.path.join (outdir, tar_base + '.diff.gz')
686 patch = env.PATCH (patch_name, tar_ball)
687 env.Depends (patch_name, dist_ball)
688 env.Alias ('release', patch)
689
690 #### web
691 web_base = os.path.join (outdir, 'web')
692 web_ball = os.path.join (web_base, '.tar.gz')
693 env['footify'] = 'MAILADDRESS=bug-lilypond@gnu.org $PYTHON stepmake/bin/add-html-footer.py --name=lilypond --version=$version'
694 env['web_ext'] = ['.html', '.ly', '.midi', '.pdf', '.png', '.ps.gz', '.txt',]
695
696 # compatible make heritits
697 # fixme: generate in $outdir is cwd/builddir
698 env.Command (web_ball, 'doc',
699              ['$PYTHON buildscripts/mutopia-index.py -o examples.html ./',
700               'cd $absbuild && $footify $$ (find . -name "*.html" -print)',
701               # uhg?
702               'cd $absbuild && rm -f $$(find . -name "*.html~" -print)',
703               'cd $absbuild && find Documentation input \
704               -path foo $web_path -false \
705               > $outdir/weblist',
706               '''echo '<META HTTP-EQUIV="refresh" content="0;URL=Documentation/out-www/index.html">' > $absbuild/index.html''',
707               '''echo '<html><body>Redirecting to the documentation index...</body></html>' >> $absbuild/index.html''',
708               # UGHR?  all .html cruft in cwd goes into the web ball?
709               'cd $absbuild && ls *.html >> $outdir/weblist',
710               'cat $outdir/weblist | (cd $absbuild; \
711               GZIP=-9v tar -czf $web_ball  -T -)',])
712 env.Alias ('web', web_ball)
713
714 #### tags
715 env.Append (
716         ETAGSFLAGS = ["""--regex='{c++}/^LY_DEFINE *(\([^,]+\)/\1/'""",
717                       """--regex='{c++}/^LY_DEFINE *([^"]*"\([^"]+\)"/\1/'"""])
718 # filter-out some files?
719 env.Command ('TAGS', src_files, 'etags $ETAGSFLAGS $SOURCES')
720
721
722 # Note: SConscripts are only needed in directories where something needs
723 # to be done, building or installing
724 for d in subdirs:
725         if os.path.exists (os.path.join (d, 'SConscript')):
726                 b = os.path.join (env['build'], d, env['out'])
727                 # Support clean sourcetree build (--srcdir build)
728                 # and ./out build.
729                 if os.path.abspath (b) != os.path.abspath (d):
730                         env.BuildDir (b, d, duplicate = 0)
731                 SConscript (os.path.join (b, 'SConscript'))
732