]> git.donarmstrong.com Git - lilypond.git/blob - SConstruct
(class New_slur): new file. Score based slur
[lilypond.git] / SConstruct
1 # -*-python-*-
2
3 '''
4 Experimental scons (www.scons.org) building:
5
6 Usage:
7     scons
8     LILYPONDPREFIX=out-scons/usr/share/lilypond lily/out-scons/lilypond-bin
9
10     scons install
11     scons -c              # clean
12     scons -h              # help
13
14     scons build=DIR       # scrdir build, write to new tree =build
15     scons out=DIR         # write output to deeper dir DIR
16
17 Optionally, make a custom.py.  I have
18
19 import os
20 out='out-scons'
21 optimising=0
22 debugging=1
23 gui=1
24 os.path.join (os.getcwd (), '=install')
25 prefix=os.path.join (os.environ['HOME'], 'usr', 'pkg', 'lilypond')
26
27 '''
28
29
30 # TODO:
31 #   * separate environments?
32 #     - compile environment checks headers and libraries
33 #     - doc environment checks doc stuff
34 #
35 #   * running from build-dir, without installing?
36 #     - scons will not install, if PREFIX lives outside of CWD
37 #     - build symlink tree
38 #       + mimicking regular installation setup?
39 #       + use tweaked scons 'install' target?
40 #   * commandline targets:
41 #      - clean => -c
42 #      - dist, tar => env.Tar
43 #   * Documentation, scripts
44 #   * env.Tar
45 #   * more fine-grained config.h -- move lilypondprefix to version.hh?
46 #     - config.h:   changes after system upgrades, affects all files
47 #     - version.hh:  prefix, version etc?  affects few
48
49 import re
50 import glob
51 import os
52 import sys
53 import string
54
55 env = Environment ()
56
57 # put your favourite stuff in custom.py
58 opts = Options ('custom.py', ARGUMENTS)
59 #opts = Options (None, ARGUMENTS)
60 opts.Add ('prefix', 'Install prefix', '/usr/')
61 opts.Add ('out', 'Output directory', 'out-scons')
62 opts.Add ('build', 'Build directory', '.')
63 opts.AddOptions (
64         BoolOption ('warnings', 'compile with -Wall and similiar',
65                    1),
66         BoolOption ('debugging', 'compile with debugging symbols',
67                     0),
68         BoolOption ('optimising', 'compile with optimising',
69                     1),
70         BoolOption ('shared', 'build shared libraries',
71                     0),
72         BoolOption ('static', 'build static libraries',
73                     1),
74         BoolOption ('gui', 'build with GNOME backend (EXPERIMENTAL)',
75                     1),
76         BoolOption ('verbose', 'run commands with verbose flag',
77                     0),
78         )
79
80 Help (opts.GenerateHelpText (env))
81
82 env = Environment (options = opts)
83
84 env.CacheDir (os.path.join (env['build'], '=build-cache'))
85
86 #ugh
87 sys.path.append (os.path.join ('.', 'stepmake', 'bin'))
88 import packagepython
89 package = packagepython.Package ('.')
90
91 env['version'] = packagepython.version_tuple_to_str (package.version)
92 env['bindir'] = os.path.join (env['prefix'], 'bin')
93 env['sharedir'] = os.path.join (env['prefix'], 'share')
94 env['libdir'] = os.path.join (env['prefix'], 'lib')
95 env['localedir'] = os.path.join (env['sharedir'], 'locale')
96
97 env['sharedir_package'] = os.path.join (env['sharedir'], package.name)
98 env['sharedir_package_version'] = os.path.join (env['sharedir_package'],
99                                                  env['version'])
100 env['lilypondprefix'] = os.path.join (env['sharedir_package_version'])
101
102
103 if env['debugging']:
104         env.Append (CFLAGS = '-g')
105         env.Append (CXXFLAGS = '-g')
106 if env['optimising']:
107         env.Append (CFLAGS = '-O2')
108         env.Append (CXXFLAGS = '-O2')
109         env.Append (CXXFLAGS = '-DSTRING_UTILS_INLINED')
110 if env['warnings']:
111         env.Append (CFLAGS = '-W ')
112         env.Append (CFLAGS = '-Wall')
113         # what about = ['-W', '-Wall', ...]?
114         env.Append (CXXFLAGS = '-W')
115         env.Append (CXXFLAGS = '-Wall')
116         env.Append (CXXFLAGS = '-Wconversion')
117
118 env['MFMODE'] = 'ljfour'
119
120
121 conf = Configure (env)
122
123
124 vre = re.compile ('^.*[^-.0-9]([0-9][0-9]*\.[0-9][.0-9]*).*$', re.DOTALL)
125 def get_version (program):
126         command = '(%(program)s --version || %(program)s -V) 2>&1' % vars ()
127         pipe = os.popen (command)
128         output = pipe.read ()
129         if pipe.close ():
130                 return None
131         v = re.sub (vre, '\\1', output)
132         return string.split (v, '.')
133
134 def assert_version (lst, program, minimal, description, package):
135         global required
136         sys.stdout.write ('Checking %s version... ' % program)
137         actual = get_version (program)
138         if not actual:
139                 print 'not found'
140                 lst.append ((description, package, minimal, program,
141                              'not installed'))
142                 return
143         sys.stdout.write (string.join (actual, '.'))
144         sys.stdout.write ('\n')
145         if actual < string.split (minimal, '.'):
146                 lst.append ((description, package, minimal, program,
147                              string.join (actual, '.')))
148
149 required = []
150 assert_version (required, 'gcc', '2.8', 'GNU C compiler', 'gcc')
151 assert_version (required, 'g++', '3.0.5', 'GNU C++ compiler', 'g++')
152 assert_version (required, 'python', '2.1', 'Python (www.python.org)', 'python')
153 assert_version (required, 'guile-config', '1.6', 'GUILE development',
154                 'libguile-dev or guile-devel')
155 # Do not use bison 1.50 and 1.75.
156 assert_version (required, 'bison', '1.25', 'Bison -- parser generator',
157                 'bison')
158 assert_version (required, 'flex', '0.0', 'Flex -- lexer generator', 'flex')
159
160
161 optional = []
162 assert_version (optional, 'makeinfo', '4.7', 'Makeinfo tool', 'texinfo')
163 assert_version (optional, 'guile', '1.6', 'GUILE scheme',
164                 'libguile-dev or guile-devel')
165 assert_version (optional, 'mftrace', '1.0.27', 'Metafont tracing Type1',
166                 'mftrace')
167 assert_version (optional, 'perl', '4.0',
168                 'Perl practical efficient readonly language', 'perl')
169 #assert_version (optional, 'foo', '2.0', 'Foomatic tester', 'bar')
170
171
172 defines = {
173    'DIRSEP' : "'/'",
174    'PATHSEP' : "':'",
175    'TOPLEVEL_VERSION' : '"' + env['version'] + '"',
176    'PACKAGE': '"' + package.name + '"',
177    'DATADIR' : '"' + env['sharedir'] + '"',
178    'LILYPOND_DATADIR' : '"' + env['sharedir_package'] + '"',
179    'LOCAL_LILYPOND_DATADIR' : '"' + env['sharedir_package_version'] + '"',
180    'LOCALEDIR' : '"' + env['localedir'] + '"',
181 }
182
183
184 command = r"""python -c 'import sys; sys.stdout.write ("%s/include/python%s" % (sys.prefix, sys.version[:3]))'""" #"
185 PYTHON_INCLUDE = os.popen (command).read ()
186 env.Append (CPPPATH = PYTHON_INCLUDE)
187
188 headers = ('sys/stat.h', 'assert.h', 'kpathsea/kpathsea.h', 'Python.h')
189 for i in headers:
190         if conf.CheckCHeader (i):
191                 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
192                 defines[key] = '1'
193
194 ccheaders = ('sstream',)
195 for i in ccheaders:
196         if conf.CheckCXXHeader (i):
197                 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
198                 defines[key] = '1'
199
200 functions = ('gettext', 'isinf', 'memmem', 'snprintf', 'vsnprintf')
201 for i in functions:
202         if 0 or conf.CheckFunc (i):
203                 key = re.sub ('[./]', '_', 'HAVE_' + string.upper (i))
204                 defines[key] = '1'
205
206 key = 'HAVE_FLEXLEXER_YY_CURRENT_BUFFER'
207
208 sys.stdout.write('Checking for yy_current_buffer ... ')
209 sys.stdout.flush()
210 res = conf.TryCompile ("""using namespace std;
211 #include <FlexLexer.h>
212 class yy_flex_lexer: public yyFlexLexer
213 {
214   public:
215     yy_flex_lexer ()
216     {
217       yy_current_buffer = 0;
218     }
219 };""", '.cc')
220 if res:
221         defines[key] = '1'
222         sys.stdout.write('yes\n')
223 else:
224         sys.stdout.write('no\n')
225
226
227 if conf.CheckLib ('dl'):
228         pass
229
230 if conf.CheckLib ('kpathsea'):
231         defines['KPATHSEA'] = '1'
232
233 # huh? 
234 if conf.CheckLib ('kpathsea', 'kpse_find_file'):
235         defines['HAVE_KPSE_FIND_FILE'] = '1'
236 if conf.CheckLib ('kpathsea', 'kpse_find_tfm'):
237         defines['HAVE_KPSE_FIND_TFM'] = '1'
238
239 #this could happen after flower...
240 env.ParseConfig ('guile-config compile')
241
242 #this could happen only for compiling pango-*
243 if env['gui']:
244         env.ParseConfig ('pkg-config --cflags --libs gtk+-2.0')
245         env.ParseConfig ('pkg-config --cflags --libs pango')
246         if conf.CheckCHeader ('pango/pangofc-fontmap.h'):
247                 defines['HAVE_PANGO_PANGOFC_FONTMAP_H'] = '1'
248
249         if conf.CheckLib ('pango-1.0',
250                           'pango_fc_font_map_add_decoder_find_func'):
251                 defines['HAVE_PANGO_CVS'] = '1'
252                 defines['HAVE_PANGO_FC_FONT_MAP_ADD_DECODER_FIND_FUNC'] = '1'
253
254 env = conf.Finish ()
255
256 here = os.getcwd ()
257 reldir = str (Dir ('.').srcnode ())
258 os.chdir (reldir)
259 srcdir = os.getcwd ()
260 os.chdir (here)
261 env['srcdir'] = srcdir
262
263 build = env['build']
264 out = env['out']
265 ##reldir = str (Dir ('.').srcnode ())
266 reldir = os.getcwd ()
267 outdir = os.path.join (env['build'], reldir, env['out'])
268 if not os.path.exists (outdir):
269         os.mkdir (outdir)
270
271 def list_sort (lst):
272         sorted = lst
273         sorted.sort ()
274         return sorted
275         
276 config = open (os.path.join (outdir, 'config.h'), 'w')
277 for i in list_sort (defines.keys ()):
278         config.write ('#define %s %s\n' % (i, defines[i]))
279 config.close ()
280
281 os.system (sys.executable \
282            + ' ./stepmake/bin/make-version.py VERSION > '\
283            + os.path.join (outdir, 'version.hh'))
284
285 if os.path.exists ('parser'):
286         env.Append (LIBPATH = ['#/flower', '#/lily', '#/parser', '#/gui',],
287                     CPPPATH = [outdir, '#',])
288 else:   
289         env.Append (LIBPATH = ['#/flower/' + out,],
290                     CPPPATH = [outdir, '#',])
291
292 if required:
293         print
294         print '********************************'
295         print 'Please install required packages'
296         for i in required:
297                 print '%s:      %s-%s or newer (found: %s %s)' % i
298         sys.exit (1)
299
300 if optional:
301         print
302         print '*************************************'
303         print 'Consider installing optional packages'
304         for i in optional:
305                 print '%s:      %s-%s or newer (found: %s %s)' % i
306
307 #env['tarball'] = os.path.join (outdir,
308 #                              package.name + '-' + env['version'] + '.tar.gz')
309
310 env['tarball'] = os.path.join (os.environ['HOME'], 'tmp',
311                                package.name + '-' + env['version'] + '.tar.gz')
312
313 # huh?
314 if 'tar' in COMMAND_LINE_TARGETS:
315         #env.Default (env['tarball'])
316         #env.Default (tar)
317         env.Default (env['tarball'])
318         #Default (tar)
319
320 Export ('env')
321
322 #ugr
323 if build == '.':
324         absbuild = os.getcwd ()
325 else:
326         absbuild = build
327 env['absbuild'] = absbuild
328
329 # duh
330 env['MAKEINFO'] = 'LANG= makeinfo'
331 env['PYTHON'] = 'python'
332 env['LILYPOND_BIN'] = os.path.join (absbuild, 'lily', out, 'lilypond-bin')
333 env['LILYPONDPREFIX'] = os.path.join (outdir, 'usr/share/lilypond')
334 env['LILYPOND_BOOK'] = srcdir + '/scripts/lilypond-book.py'
335 env['ABC2LY_PY'] = srcdir + '/scripts/abc2ly.py'
336 env['MF_TO_TABLE_PY'] = srcdir + '/buildscripts/mf-to-table.py'
337 env['LILYPOND_PY'] = srcdir + '/scripts/lilypond.py'
338 env['LILYPOND_BOOK_FLAGS'] = ''
339 env['LILYPOND_BOOK_FORMAT'] = 'texi-html'
340 # ugh?
341 env['LILYPOND_BOOK_PATH'] = ['.', '#/input', '#/input/regression',
342                              '#/input/test', '#/input/tutorial',
343                              os.path.join (absbuild, 'mf', out),
344                              '#/Documentation/user',
345                              os.path.join (absbuild, 'Documentation', out),
346                              os.path.join (absbuild, 'Documentation/user', out),
347                              ]
348                              
349 env['MAKEINFO_PATH'] = ['.', '#/Documentation/user',
350                         os.path.join (absbuild, 'Documentation/user', out)]
351
352 ## TEXINFO_PAPERSIZE_OPTION= $(if $(findstring $(PAPERSIZE),a4),,-t @afourpaper)
353 env['TEXINFO_PAPERSIZE_OPTION'] = '-t @afourpaper'
354 #FIXME: ./python isn't sconsed yet, add scrdir/python for lilylib.py ...
355 env.Append (PYTHONPATH = [os.path.join (outdir, 'usr/lib/python'),
356                           os.path.join (srcdir, 'buildscripts'),
357                           os.path.join (srcdir, 'python')])
358 # huh, aha?
359 env.Append (ENV = { 'PYTHONPATH' : string.join (env['PYTHONPATH'],
360                                                 os.pathsep) } )
361
362 # GS_FONTPATH, GS_LIB?
363 SConscript ('buildscripts/builder.py')
364
365 #subdirs = ['mf',]
366 #subdirs = ['flower', 'lily', 'parser', 'gui', 'main',]
367 #subdirs = ['flower', 'lily', 'mf', 'scm', 'ly']
368 subdirs = ['flower', 'lily', 'mf', 'scm', 'ly', 'Documentation',
369            'Documentation/user', 'input']
370 for d in subdirs:
371         b = os.path.join (build, d, out)
372         # Support clean sourctree build (srcdir build)
373         # and outdir build.
374         # TODO: figure out SConscript (dir, builddir, duplicate)) feature
375         if (build and build != '.') \
376            or (out and out != '.'):
377                 env.BuildDir (b, d, duplicate=0)
378         SConscript (os.path.join (b, 'SConscript'))
379
380 readme_files = ['ChangeLog', 'COPYING', 'DEDICATION', 'ROADMAP', 'THANKS']
381 readme_txt = ['AUTHORS.txt', 'README.txt', 'INSTALL.txt', 'NEWS.txt']
382 # to be [re]moved after spit
383 patch_files = ['emacsclient.patch', 'server.el.patch', 'darwin.patch']
384
385 map (lambda x: env.Texi2txt (x, os.path.join ('Documentation/topdocs',
386                                               os.path.splitext (x)[0])),
387      readme_txt)
388
389 #testing
390 env.Append (TARFLAGS = '-z --owner=0 --group=0')
391 env.Append (GZIPFLAGS = '-9')
392 all_sources = ['SConstruct',] + subdirs \
393               + ['VERSION', '.cvsignore']\
394               + readme_files + readme_txt + patch_files
395
396 tar = env.Tar (env['tarball'], all_sources)
397
398 # as a builder?
399 def symlink_tree (prefix):
400         def mkdirs (dir):
401                 def mkdir (dir):
402                         if not dir:
403                                 os.chdir (os.sep)
404                                 return
405                         if not os.path.isdir (dir):
406                                 if os.path.exists (dir):
407                                         os.unlink (dir)
408                                 os.mkdir (dir)
409                         os.chdir (dir)
410                 map (mkdir, string.split (dir, os.sep))
411         #srcdir = os.getcwd ()
412         def symlink (src, dst):
413                 dir = os.path.dirname (dst)
414                 mkdirs (dir)
415                 if src[0] == '#':
416                         frm = os.path.join (srcdir, src[1:])
417                 else:
418                         depth = len (string.split (dir))
419                         frm = os.path.join ('../' * depth, src, out)
420                 os.symlink (frm, os.path.basename (dst))
421                 os.chdir (srcdir)
422         map (lambda x: symlink (x[0], os.path.join (prefix, x[1])),
423              (('python', 'lib/lilypond/python'),
424               ('#mf',    'share/lilypond/fonts/mf'),
425               ('mf',     'share/lilypond/fonts/amf'),
426               ('mf',     'share/lilypond/fonts/tfm'),
427               ('mf',     'share/lilypond/fonts/type1'),
428               ('#tex',   'share/lilypond/tex/source'),
429               ('mf',     'share/lilypond/tex/generate'),
430               ('#ly',    'share/lilypond/ly'),
431               ('#scm',   'share/lilypond/scm'),
432               ('#ps',    'share/lilypond/ps'),
433               ('elisp',  'share/lilypond/elisp')))
434
435 if env['debugging']:
436         prefix = os.path.join (outdir, 'usr')
437         if not os.path.exists (prefix):
438                 symlink_tree (prefix)