]> git.donarmstrong.com Git - lilypond.git/blobdiff - SConstruct
Updates. Add targets: tar, dist, release.
[lilypond.git] / SConstruct
index 4a3de0368eb76acae278fdcb23caedd55d96826d..95c2253ccd06a98ef3eaf17702c43bd45ad3dcb3 100644 (file)
@@ -5,6 +5,17 @@ Experimental scons (www.scons.org) building:
 
 Usage:
     scons
+    scons lily            # build lily
+
+    LILYPONDPREFIX=out-scons/usr/share/lilypond lily/out-scons/lilypond-bin
+    scons doc             # build web doc
+
+    scons fonts           # build all font stuff (split this? )
+
+    scons config          # reconfigure
+
+    scons /               # builds all possible targets
+
     scons install
     scons -c              # clean
     scons -h              # help
@@ -20,21 +31,21 @@ optimising=0
 debugging=1
 gui=1
 os.path.join (os.getcwd (), '=install')
+prefix=os.path.join (os.environ['HOME'], 'usr', 'pkg', 'lilypond')
 
 '''
 
 
 # TODO:
-#   * running from build-dir, without installing?
-#     - scons will not install, if PREFIX lives outside of CWD
-#     - build symlink tree
-#       + mimicking regular installation setup?
-#       + use tweaked scons 'install' target?
+#   * add missing dirs
+#   * cleanup
+
+#   * separate environments?
+#     - compile environment checks headers and libraries
+#     - doc environment checks doc stuff
+
 #   * commandline targets:
-#      - clean => -c
-#      - dist, tar => env.Tar
-#   * Documentation, scripts
-#   * env.Tar
+#      - clean => -c ?
 #   * more fine-grained config.h -- move lilypondprefix to version.hh?
 #     - config.h:   changes after system upgrades, affects all files
 #     - version.hh:  prefix, version etc?  affects few
@@ -45,10 +56,29 @@ import os
 import sys
 import string
 
+subdirs = ['flower', 'lily', 'mf', 'scm', 'ly', 'Documentation',
+          'Documentation/user', 'input']
+
+usage = r'''Usage:
+scons [KEY=VALUE].. [TARGET]..
+
+where TARGET is config|lily|all|fonts|doc|tar|dist|release
+'''
+      
 env = Environment ()
 
-# put your favourite stuff in custom.py
-opts = Options ('custom.py', ARGUMENTS)
+# Without target arguments, build lily only
+if not COMMAND_LINE_TARGETS:
+       env.Default ('lily')
+
+# All builds everything (all directories)
+env.Alias ('all', ['lily', 'mf', 'input', 'Documentation'])
+
+
+## FIXME: opts in function
+
+# Put your favourite stuff in custom.py
+opts = Options (['config.cache', 'custom.py'], ARGUMENTS)
 opts.Add ('prefix', 'Install prefix', '/usr/')
 opts.Add ('out', 'Output directory', 'out-scons')
 opts.Add ('build', 'Build directory', '.')
@@ -69,10 +99,13 @@ opts.AddOptions (
                    0),
        )
 
-Help (opts.GenerateHelpText (env))
+Help (usage + opts.GenerateHelpText (env))
 
 env = Environment (options = opts)
 
+opts.Update (env)
+opts.Save ('config.cache', env)
+
 env.CacheDir (os.path.join (env['build'], '=build-cache'))
 
 #ugh
@@ -107,158 +140,201 @@ if env['warnings']:
        env.Append (CXXFLAGS = '-Wall')
        env.Append (CXXFLAGS = '-Wconversion')
 
-env['MFMODE'] = 'ljfour'
 
 
-conf = Configure (env)
-
-
-vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
-def get_version (program):
-       command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
-       pipe = os.popen (command)
-       output = pipe.read ()
-       if pipe.close ():
-               return None
-       v = re.sub (vre, '\\1', output)
-       return string.split (v, '.')
-
-def assert_version (lst, program, minimal, description, package):
-       global required
-       sys.stdout.write ('Checking %s version... ' % program)
-       actual = get_version (program)
-       if not actual:
-               print 'not found'
-               lst.append ((description, package, minimal, program,
-                            'not installed'))
-               return
-       sys.stdout.write (string.join (actual, '.'))
-       sys.stdout.write ('\n')
-       if actual < string.split (minimal, '.'):
-               lst.append ((description, package, minimal, program,
-                            string.join (actual, '.')))
-
-required = []
-assert_version (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
-assert_version (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
-assert_version (required, 'python', '2.1', 'Python (www.python.org)', 'python')
-assert_version (required, 'guile-config', '1.6', 'GUILE development',
-               'libguile-dev or guile-devel')
-# Do not use bison 1.50 and 1.75.
-assert_version (required, 'bison', '1.25', 'Bison -- parser generator',
-               'bison')
-assert_version (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
-
-
-optional = []
-assert_version (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
-assert_version (optional, 'guile', '1.6', 'GUILE scheme',
-               'libguile-dev or guile-devel')
-assert_version (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
-               'mftrace')
-assert_version (optional, 'perl', '4.0',
-               'Perl practical efficient readonly language', 'perl')
-#assert_version (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
-
-
-defines = {
-   'DIRSEP' : "'/'",
-   'PATHSEP' : "':'",
-   'TOPLEVEL_VERSION' : '"' + env['version'] + '"',
-   'PACKAGE': '"' + package.name + '"',
-   'DATADIR' : '"' + env['sharedir'] + '"',
-   'LILYPOND_DATADIR' : '"' + env['sharedir_package'] + '"',
-   'LOCAL_LILYPOND_DATADIR' : '"' + env['sharedir_package_version'] + '"',
-   'LOCALEDIR' : '"' + env['localedir'] + '"',
-}
-
-
-command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
-PYTHON_INCLUDE = os.popen (command).read ()
-env.Append (CPPPATH = PYTHON_INCLUDE)
-
-
-headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
-for i in headers:
-       if conf.CheckCHeader (i):
-                       key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
-                defines[key] = '1'
-
-ccheaders = ('sstream',)
-for i in ccheaders:
-       if conf.CheckCXXHeader (i):
-                       key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
-                defines[key] = '1'
-
-functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
-for i in functions:
-       if 0 or conf.CheckFunc (i):
-                       key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
-                defines[key] = '1'
-
-
-key = 'HAVE_FLEXLEXER_YY_CURRENT_BUFFER'
-defines[key] = conf.TryCompile ("""using namespace std;
-#include <FlexLexer.h>
-class yy_flex_lexer: public yyFlexLexer
-{
-  public:
-    yy_flex_lexer ()
-    {
-      yy_current_buffer = 0;
-    }
-};""", 'cc')
-
-if conf.CheckLib ('dl'):
-       pass
-
-if conf.CheckLib ('kpathsea'):
-       defines['KPATHSEA'] = '1'
-
-# huh? 
-if conf.CheckLib ('kpathsea', 'kpse_find_file'):
-       defines['HAVE_KPSE_FIND_FILE'] = '1'
-if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
-       defines['HAVE_KPSE_FIND_TFM'] = '1'
-
-#this could happen after flower...
-env.ParseConfig ('guile-config compile')
-
-#this could happen only for compiling pango-*
-if env['gui']:
-       env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
-       env.ParseConfig ('pkg-config --cflags --libs pango')
-       if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
-               defines['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
-
-       if conf.CheckLib ('pango-1.0',
-                         'pango_fc_font_map_add_decoder_find_func'):
-               defines['HAVE_PANGO_CVS'] = '1'
-               defines['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
-
-env = conf.Finish ()
+##Import ('env')
+here = os.getcwd ()
+reldir = str (Dir ('.').srcnode ())
+os.chdir (reldir)
+srcdir = os.getcwd ()
+os.chdir (here)
+##outdir = os.path.join (env['build'], reldir, env['out'])
+outdir = os.path.join (env['build'], env['out'])
 
+env['srcdir'] = srcdir
 build = env['build']
 out = env['out']
-##reldir = str (Dir ('.').srcnode ())
-reldir = os.getcwd ()
-outdir = os.path.join (env['build'], reldir, env['out'])
-if not os.path.exists (outdir):
-       os.mkdir (outdir)
+
 
 def list_sort (lst):
        sorted = lst
        sorted.sort ()
        return sorted
-       
-config = open (os.path.join (outdir, 'config.h'), 'w')
-for i in list_sort (defines.keys ()):
-       config.write ('#define %s %s\n' % (i, defines[i]))
-config.close ()
 
-os.system (sys.executable \
-          + ' ./stepmake/bin/make-version.py VERSION > '\
-          + os.path.join (outdir, 'version.hh'))
+env['MFMODE'] = 'ljfour'
+config_h = os.path.join (outdir, 'config.h')
+env.Alias ('config', config_h)
+
+def configure (env):
+       conf = Configure (env)
+
+       vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
+       def get_version (program):
+               command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
+               pipe = os.popen (command)
+               output = pipe.read ()
+               if pipe.close ():
+                       return None
+               v = re.sub (vre, '\\1', output)
+               return string.split (v, '.')
+
+       def assert_version (lst, program, minimal, description, package):
+               global required
+               sys.stdout.write ('Checking %s version... ' % program)
+               actual = get_version (program)
+               if not actual:
+                       print 'not found'
+                       lst.append ((description, package, minimal, program,
+                                    'not installed'))
+                       return
+               sys.stdout.write (string.join (actual, '.'))
+               sys.stdout.write ('\n')
+               if actual < string.split (minimal, '.'):
+                       lst.append ((description, package, minimal, program,
+                                    string.join (actual, '.')))
+
+       required = []
+       assert_version (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
+       assert_version (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
+       assert_version (required, 'python', '2.1', 'Python (www.python.org)', 'python')
+       assert_version (required, 'guile-config', '1.6', 'GUILE development',
+                       'libguile-dev or guile-devel')
+       # Do not use bison 1.50 and 1.75.
+       assert_version (required, 'bison', '1.25', 'Bison -- parser generator',
+                       'bison')
+       assert_version (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
+
+
+       optional = []
+       assert_version (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
+       assert_version (optional, 'guile', '1.6', 'GUILE scheme',
+                       'libguile-dev or guile-devel')
+       assert_version (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
+                       'mftrace')
+       assert_version (optional, 'perl', '4.0',
+                       'Perl practical efficient readonly language', 'perl')
+       #assert_version (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
+
+
+       defines = {
+          'DIRSEP' : "'/'",
+          'PATHSEP' : "':'",
+          'TOPLEVEL_VERSION' : '"' + env['version'] + '"',
+          'PACKAGE': '"' + package.name + '"',
+          'DATADIR' : '"' + env['sharedir'] + '"',
+          'LILYPOND_DATADIR' : '"' + env['sharedir_package'] + '"',
+          'LOCAL_LILYPOND_DATADIR' : '"' + env['sharedir_package_version'] + '"',
+          'LOCALEDIR' : '"' + env['localedir'] + '"',
+       }
+
+
+       command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
+       PYTHON_INCLUDE = os.popen (command).read ()
+       env.Append (CPPPATH = PYTHON_INCLUDE)
+
+       headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
+       for i in headers:
+               if conf.CheckCHeader (i):
+                       key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
+                       defines[key] = '1'
+
+       ccheaders = ('sstream',)
+       for i in ccheaders:
+               if conf.CheckCXXHeader (i):
+                       key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
+                       defines[key] = '1'
+
+       functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
+       for i in functions:
+               if 0 or conf.CheckFunc (i):
+                       key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
+                       defines[key] = '1'
+
+       key = 'HAVE_FLEXLEXER_YY_CURRENT_BUFFER'
+
+       sys.stdout.write('Checking for yy_current_buffer ... ')
+       sys.stdout.flush()
+       res = conf.TryCompile ("""using namespace std;
+       #include <FlexLexer.h>
+       class yy_flex_lexer: public yyFlexLexer
+       {
+         public:
+           yy_flex_lexer ()
+           {
+             yy_current_buffer = 0;
+           }
+       };""", '.cc')
+       if res:
+               defines[key] = '1'
+               sys.stdout.write('yes\n')
+       else:
+               sys.stdout.write('no\n')
+
+
+       if conf.CheckLib ('dl'):
+               pass
+
+       if conf.CheckLib ('kpathsea'):
+               defines['KPATHSEA'] = '1'
+
+       # huh? 
+       if conf.CheckLib ('kpathsea', 'kpse_find_file'):
+               defines['HAVE_KPSE_FIND_FILE'] = '1'
+       if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
+               defines['HAVE_KPSE_FIND_TFM'] = '1'
+
+       #this could happen after flower...
+       env.ParseConfig ('guile-config compile')
+
+       #this could happen only for compiling pango-*
+       if env['gui']:
+               env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
+               env.ParseConfig ('pkg-config --cflags --libs pango')
+               if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
+                       defines['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
+
+               if conf.CheckLib ('pango-1.0',
+                                 'pango_fc_font_map_add_decoder_find_func'):
+                       defines['HAVE_PANGO_CVS'] = '1'
+                       defines['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
+
+       # ugh - needed at all?  make Builder/Command for config.h!
+       if not os.path.exists (outdir):
+               os.mkdir (outdir)
+
+       config = open (config_h, 'w')
+       for i in list_sort (defines.keys ()):
+               config.write ('#define %s %s\n' % (i, defines[i]))
+       config.close ()
+
+
+       os.system (sys.executable \
+                  + ' ./stepmake/bin/make-version.py VERSION > '\
+                  + os.path.join (outdir, 'version.hh'))
+
+       if required:
+               print
+               print '********************************'
+               print 'Please install required packages'
+               for i in required:
+                       print '%s:      %s-%s or newer (found: %s %s)' % i
+               sys.exit (1)
+
+       if optional:
+               print
+               print '*************************************'
+               print 'Consider installing optional packages'
+               for i in optional:
+                       print '%s:      %s-%s or newer (found: %s %s)' % i
+
+       return conf.Finish ()
+
+# Hmm.  Must configure when building lily, to get compiler and linker
+# flags set-up.
+# FIXME
+if not os.path.exists (config_h) or 'config' in COMMAND_LINE_TARGETS\
+   or 'lily' in BUILD_TARGETS or 'all' in BUILD_TARGETS:
+       env = configure (env)
 
 if os.path.exists ('parser'):
        env.Append (LIBPATH = ['#/flower', '#/lily', '#/parser', '#/gui',],
@@ -267,32 +343,43 @@ else:
        env.Append (LIBPATH = ['#/flower/' + out,],
                    CPPPATH = [outdir, '#',])
 
-if required:
-       print
-       print '********************************'
-       print 'Please install required packages'
-       for i in required:
-               print '%s:      %s-%s or newer (found: %s %s)' % i
-       sys.exit (1)
-
-if optional:
-       print
-       print '*************************************'
-       print 'Consider installing optional packages'
-       for i in optional:
-               print '%s:      %s-%s or newer (found: %s %s)' % i
-
-#env['tarball'] = os.path.join (outdir,
-#                             package.name + '-' + env['version'] + '.tar.gz')
-
-env['tarball'] = os.path.join ('~/tmp',
-                              package.name + '-' + env['version'] + '.tar.gz')
-
 Export ('env')
 
-#subdirs = ['mf',]
-#subdirs = ['flower', 'lily', 'parser', 'gui', 'main',]
-subdirs = ['flower', 'lily', 'mf', 'scm', 'ly']
+#ugr
+if build == '.':
+       absbuild = os.getcwd ()
+else:
+       absbuild = build
+env['absbuild'] = absbuild
+
+# duh
+env['MAKEINFO'] = 'LANG= makeinfo'
+env['PYTHON'] = 'python'
+env['LILYPOND_BIN'] = os.path.join (absbuild, 'lily', out, 'lilypond-bin')
+env['LILYPONDPREFIX'] =        os.path.join (outdir, 'usr/share/lilypond')
+env['LILYPOND_BOOK'] = srcdir + '/scripts/lilypond-book.py'
+env['ABC2LY_PY'] = srcdir + '/scripts/abc2ly.py'
+env['MF_TO_TABLE_PY'] = srcdir + '/buildscripts/mf-to-table.py'
+env['LILYPOND_PY'] = srcdir + '/scripts/lilypond.py'
+env['LILYPOND_BOOK_FLAGS'] = ''
+env['LILYPOND_BOOK_FORMAT'] = 'texi-html'
+# ugh?
+env['LILYPOND_BOOK_PATH'] = ['.', '#/input', '#/input/regression',
+                            '#/input/test', '#/input/tutorial',
+                            os.path.join (absbuild, 'mf', out),
+                            '#/Documentation/user',
+                            os.path.join (absbuild, 'Documentation', out),
+                            os.path.join (absbuild, 'Documentation/user', out),
+                            ]
+                            
+env['MAKEINFO_PATH'] = ['.', '#/Documentation/user',
+                       os.path.join (absbuild, 'Documentation/user', out)]
+
+## TEXINFO_PAPERSIZE_OPTION= $(if $(findstring $(PAPERSIZE),a4),,-t @afourpaper)
+env['TEXINFO_PAPERSIZE_OPTION'] = '-t @afourpaper'
+
+SConscript ('buildscripts/builder.py')
+
 for d in subdirs:
        b = os.path.join (build, d, out)
        # Support clean sourctree build (srcdir build)
@@ -303,13 +390,88 @@ for d in subdirs:
                env.BuildDir (b, d, duplicate=0)
        SConscript (os.path.join (b, 'SConscript'))
 
+# as a builder?
+def symlink_tree (prefix):
+       def mkdirs (dir):
+               def mkdir (dir):
+                       if not dir:
+                               os.chdir (os.sep)
+                               return
+                       if not os.path.isdir (dir):
+                               if os.path.exists (dir):
+                                       os.unlink (dir)
+                               os.mkdir (dir)
+                       os.chdir (dir)
+               map (mkdir, string.split (dir, os.sep))
+       def symlink (src, dst):
+               os.chdir (absbuild)
+               dir = os.path.dirname (dst)
+               mkdirs (dir)
+               if src[0] == '#':
+                       frm = os.path.join (srcdir, src[1:])
+               else:
+                       depth = len (string.split (dir, '/'))
+                       frm = os.path.join ('../' * depth, src, out)
+               os.symlink (frm, os.path.basename (dst))
+       map (lambda x: symlink (x[0], os.path.join (prefix, x[1])),
+            (('python', 'lib/lilypond/python'),
+             # UGHR, lilypond.py uses lilypond-bin from PATH
+             ('lily',   'bin'),
+             ('#mf',    'share/lilypond/fonts/mf'),
+             ('mf',     'share/lilypond/fonts/afm'),
+             ('mf',     'share/lilypond/fonts/tfm'),
+             ('mf',     'share/lilypond/fonts/type1'),
+             ('#tex',   'share/lilypond/tex/source'),
+             ('mf',     'share/lilypond/tex/generate'),
+             ('#ly',    'share/lilypond/ly'),
+             ('#scm',   'share/lilypond/scm'),
+             ('#ps',    'share/lilypond/ps'),
+             ('elisp',  'share/lilypond/elisp')))
+       os.chdir (srcdir)
 
-readmes = ['AUTHORS.txt', 'ChangeLog', 'NEWS.txt']
-
-#testing
-env.Append (TARFLAGS = '-z --owner=0 --group=0')
-env.Append (GZIPFLAGS = '-9')
-all_sources = ['SConstruct',] + readmes + subdirs
-x = env.Tar (env['tarball'], all_sources)
-
+if env['debugging']:
+       prefix = os.path.join (out, 'usr')
+       if not os.path.exists (prefix):
+               symlink_tree (prefix)
+
+#### dist, tar
+src_files = ['ChangeLog', '.cvsignore', 'Documentation/index.html.in',
+            'lily/beam.cc']
+
+def cvs_files (dir):
+       entries = open (os.path.join (dir, 'CVS/Entries')).readlines ()
+       files = filter (lambda x: x[0] != 'D', entries)
+       return map (lambda x: os.path.join (dir, x[1:x[1:].index ('/')+1]),
+                   files)
+
+readme_files = ['AUTHORS', 'README', 'INSTALL', 'NEWS']
+foo = map (lambda x: env.Texi2txt (x + '.txt',
+                                  os.path.join ('Documentation/topdocs',
+                                                x)),
+          readme_files)
+txt_files = map (lambda x: x + '.txt', readme_files)
+src_files = reduce (lambda x, y: x + y, map (cvs_files, subdirs))
+tar_base = package.name + '-' + env['version']
+tar_name = tar_base + '.tar.gz'
+ball_prefix = os.path.join (outdir, tar_base)
+tar_ball = os.path.join (outdir, tar_name)
+
+dist_files = src_files + txt_files
+ball_files = map (lambda x: os.path.join (ball_prefix, x), dist_files)
+map (lambda x: env.Depends (tar_ball, x), ball_files)
+map (lambda x: env.Command (os.path.join (ball_prefix, x), x,
+                           'ln $SOURCE $TARGET'), dist_files)
+tar = env.Command (tar_ball, src_files,
+                  'tar czf $TARGET -C $TARGET.dir %s' % tar_base)
+env.Alias ('tar', tar)
+
+dist_ball = os.path.join (package.release_dir, tar_name)
+env.Command (dist_ball, tar_ball,
+            'if [ -e $SOURCE -a -e $TARGET ]; then rm $TARGET; fi;' \
+            + 'ln $SOURCE $TARGET')
+env.Depends ('dist', dist_ball)
+patch_name = os.path.join (outdir, tar_base + '.diff.gz')
+patch = env.PATCH (patch_name, tar_ball)
+env.Depends (patch_name, dist_ball)
+env.Alias ('release', patch)