]> git.lyx.org Git - lyx.git/blob - development/scons/scons_utils.py
Scons-build system moves to development/scons, from Bo Peng (ben.bob@gmail.com)
[lyx.git] / development / scons / scons_utils.py
1 # vi:filetype=python:expandtab:tabstop=2:shiftwidth=2
2 #
3 # file scons_utils.py
4
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
7
8 # \author Bo Peng
9 # Full author contact details are available in file CREDITS.
10 #
11 # This file defines all the utility functions for the
12 # scons-based build system of lyx
13
14
15 import os, sys, re, shutil, glob
16
17 config_h = os.path.join('src', 'config.h')
18
19 def writeToFile(filename, lines, append = False):
20   " utility function: write or append lines to filename "
21   if append:
22     file = open(filename, 'a')
23   else:
24     file = open(filename, 'w')
25   file.write(lines)
26   file.close()
27
28
29 def addToConfig(lines, top_src_dir):
30   ''' utility function: shortcut for appending lines to outfile
31     add newline at the end of lines.
32   '''
33   if lines.strip() != '':
34     writeToFile(os.path.join(top_src_dir, config_h), lines + '\n\n', append = True)
35
36
37 def printEnvironment(env, keys=[]):
38   ''' used to check profile settings '''
39   dict = env.Dictionary()
40   if len(keys) == 0:
41     keys = dict.keys()
42   keys.sort()
43   for key in keys:
44     try:
45       # try to expand, but this is not always possible
46       print key, '=', env.subst('$'+key)
47     except:   
48       print '<<UNEXPANDED>>:', key, '=', dict[key]
49
50
51 def env_subst(target, source, env):
52   ''' subst variables in source by those in env, and output to target
53     source and target are scons File() objects
54
55     %key% (not key itself) is an indication of substitution
56   '''
57   assert len(target) == 1
58   assert len(source) == 1
59   target_file = file(str(target[0]), "w")
60   source_file = file(str(source[0]), "r")
61   
62   contents = source_file.read()
63   for k in env.get('SUBST_KEYS', []):
64     if not env.has_key(k):
65       print "Failed to subst key ", k, " from file", str(source[0])
66       raise
67     contents = re.sub('@'+k+'@', env.subst('$'+k).replace('\n',r'\\n\\\n'), contents)
68   target_file.write(contents + "\n")
69   target_file.close()
70   #st = os.stat(str(source[0]))
71   #os.chmod(str(target[0]), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
72
73
74 def env_filecopy(target, source, env):
75   shutil.copy(str(source[0]), str(target[0]))
76
77
78 #
79 # autoconf tests
80 #
81
82 def checkPkgConfig(conf, version):
83   ''' Return false if pkg_config does not exist, or is too old '''
84   conf.Message('Checking for pkg-config...')
85   ret = conf.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
86   conf.Result(ret)
87   return ret
88
89
90 def checkPackage(conf, pkg):
91   ''' check if pkg is under the control of conf '''
92   conf.Message('Checking for package %s...' % pkg)
93   ret = conf.TryAction("pkg-config --print-errors --exists %s" % pkg)[0]
94   conf.Result(ret)
95   return ret
96
97
98 def startConfigH(top_src_dir):
99   ''' Write the first part of config.h '''
100   writeToFile(os.path.join(top_src_dir, config_h), 
101 '''/* src/config.h.  Generated by scon.  */
102
103 /* -*- C++ -*- */
104 /*
105  * \file config.h
106  * This file is part of LyX, the document processor.
107  * Licence details can be found in the file COPYING.
108  *
109  * This is the compilation configuration file for LyX.
110  * It was generated by scon.
111  * You might want to change some of the defaults if something goes wrong
112  * during the compilation.
113  */
114
115 #ifndef _CONFIG_H
116 #define _CONFIG_H
117 ''')
118
119
120 def endConfigH(top_src_dir):
121   ''' Write the last part of config.h '''
122   writeToFile(os.path.join(top_src_dir, config_h), '''
123 /************************************************************
124  ** You should not need to change anything beyond this point */
125
126 #ifndef HAVE_STRERROR
127 #if defined(__cplusplus)
128 extern "C"
129 #endif
130 char * strerror(int n);
131 #endif
132
133 #ifdef HAVE_MKSTEMP
134 #ifndef HAVE_DECL_MKSTEMP
135 #if defined(__cplusplus)
136 extern "C"
137 #endif
138 int mkstemp(char*);
139 #endif
140 #endif
141
142 #ifdef __EMX__
143 #  include "support/os2_defines.h"
144 #endif
145
146 #if defined(HAVE_OSTREAM) && defined(HAVE_LOCALE) && defined(HAVE_SSTREAM)
147 #  define USE_BOOST_FORMAT 1
148 #else
149 #  define USE_BOOST_FORMAT 0
150 #endif
151
152 #define BOOST_USER_CONFIG <config.h>
153
154 #if !defined(ENABLE_ASSERTIONS)
155 #  define BOOST_DISABLE_ASSERTS 1
156 #endif
157 #define BOOST_ENABLE_ASSERT_HANDLER 1
158
159 #define BOOST_DISABLE_THREADS 1
160 #define BOOST_NO_WREGEX 1
161 #define BOOST_NO_WSTRING 1
162
163 #ifdef __CYGWIN__
164 #  define BOOST_POSIX 1
165 #endif
166
167 #if defined(HAVE_NEWAPIS_H)
168 #  define WANT_GETFILEATTRIBUTESEX_WRAPPER 1
169 #endif
170
171 #endif
172 ''', append=True)
173
174
175 #HAVE_PUTENV
176 def checkPutenv(conf):
177   check_putenv_source = """
178 #include <stdlib.h>
179 int main()
180 {
181   putenv("");
182   return(0);
183 }
184 """
185   conf.Message('Checking for putenv... ')
186   ret = conf.TryLink(check_putenv_source, '.c')
187   conf.Result(ret)
188   return ret
189
190
191 #HAVE_DECL_ISTREAMBUF_ITERATOR
192 def checkIstreambufIterator(conf):
193   check_istreambuf_iterator_source = """
194 #include <streambuf> 
195 #include <istream>
196 int main()
197 {
198   std::istreambuf_iterator<std::istream> iter;
199   return 0;
200 }
201 """
202   conf.Message('Checking for iostreambuf::iterator... ')
203   ret = conf.TryLink(check_istreambuf_iterator_source, '.cpp')
204   conf.Result(ret)
205   return ret
206
207
208 #MKDIR_TAKES_ONE_ARG
209 def checkMkdirOneArg(conf):
210   check_mkdir_one_arg_source = """
211 #include <sys/stat.h>
212 int main()
213 {
214   mkdir("somedir");
215 }
216 """
217   conf.Message('Checking for the number of args for mkdir... ')
218   ret = conf.TryLink(check_mkdir_one_arg_source, '.c')
219   if ret:
220     conf.Result('one')
221   else:
222     conf.Result('two')
223   return ret
224
225
226 #HAVE_STD_COUNT
227 def checkStdCount(conf):
228   check_std_count_source = """
229 #include <algorithm>
230 using std::count;
231 int countChar(char * b, char * e, char const c)
232 {
233   return count(b, e, c);
234 }
235
236 int main()
237 {
238   char a[] = "hello";
239   int i = countChar(a, a + 5, 'l');
240 }
241 """
242   conf.Message('Checking for std::count... ')
243   ret = conf.TryLink(check_std_count_source, '.cpp')
244   conf.Result(ret)
245   return ret
246
247
248 # SELECT_TYPE_ARG1
249 # SELECT_TYPE_ARG234
250 # SELECT_TYPE_ARG5
251 def checkSelectArgType(conf):
252   ''' Adapted from autoconf '''
253   conf.Message('Checking for arg types for select... ')
254   for arg234 in ['fd_set *', 'int *', 'void *']:
255     for arg1 in ['int', 'size_t', 'unsigned long', 'unsigned']:
256       for arg5 in ['struct timeval *', 'const struct timeval *']:
257         check_select_source = '''
258 #if HAVE_SYS_SELECT_H
259 # include <sys/select.h>
260 #endif
261 #if HAVE_SYS_SOCKET_H
262 # include <sys/socket.h>
263 #endif
264 extern int select (%s, %s, %s, %s, %s);
265 int main()
266 {
267   return(0);
268 }
269 ''' % (arg1, arg234, arg234, arg234, arg5)
270         ret = conf.TryLink(check_select_source, '.c')
271         if ret:
272           conf.Result(ret)
273           return (arg1, arg234, arg5)
274   conf.Result('no (use default)')
275   return ('int', 'int *', 'struct timeval *')
276
277
278 def checkBoostLibraries(conf, lib, pathes):
279   ''' look for boost libraries '''
280   conf.Message('Checking for boost library %s... ' % lib)
281   for path in pathes:
282     # direct form: e.g. libboost_iostreams.a
283     if os.path.isfile(os.path.join(path, 'lib%s.a' % lib)):
284       conf.Result('yes')
285       return (path, lib)
286     # check things like libboost_iostreams-gcc.a
287     files = glob.glob(os.path.join(path, 'lib%s-*.a' % lib))
288     # if there are more than one, choose the first one
289     # FIXME: choose the best one.
290     if len(files) >= 1:
291       # get xxx-gcc from /usr/local/lib/libboost_xxx-gcc.a
292       conf.Result('yes')
293       return (path, files[0].split(os.sep)[-1][3:-2])
294   conf.Result('n')
295   return ('','')
296
297
298 import SCons.Node
299 def processLang(env, folder):
300   """ Process translations (.po files) in a po/ dir 
301     This is copied from KDE knetstats-1.5/admin/kde.py
302
303         FIXME: imcomplete
304   """
305   import glob
306   dir=SCons.Node.FS.default_fs.Dir(folder).srcnode()
307   fld=dir.srcnode()
308   tmptransfiles = glob.glob(str(fld)+'/*.po')
309   
310   transfiles=[]
311   if env.has_key('_BUILDDIR_'):
312     bdir=env['_BUILDDIR_']
313     for dir in env.make_list(tmptransfiles):
314       transfiles.append( env.join(bdir, dir) )
315   else: 
316     transfiles=tmptransfiles
317
318   env['MSGFMT'] = 'msgfmt'
319   env['BUILDERS']['Transfiles']=SCons.Builder.Builder(action='$MSGFMT $SOURCE -o $TARGET',suffix='.gmo',src_suffix='.po')
320   languages=None
321   # FIXME: KDE has this ARGS thing...
322   #if env['ARGS'] and env['ARGS'].has_key('languages'):
323   #  languages=env.make_list(env['ARGS']['languages'])
324   mydir=SCons.Node.FS.default_fs.Dir('.')
325   for f in transfiles:
326     fname=f.replace(mydir.abspath, '')
327     file=SCons.Node.FS.default_fs.File(fname)
328     country = SCons.Util.splitext(file.name)[0]
329     if not languages or country in languages:
330       result = env.Transfiles(file)
331   # FIXME
332   #    dir=env.join( getInstDirForResType(env, 'KDELOCALE'), country)
333   #    env.bksys_install(env.join(dir, 'LC_MESSAGES'), result, destfile=appname+'.mo')
334
335
336 def installCygwinLDScript(path):
337   ''' Install i386pe.x-no-rdata '''
338   ld_script = os.path.join(path, 'i386pe.x-no-rdata')
339   script = open(ld_script, 'w')
340   script.write('''/* specific linker script avoiding .rdata sections, for normal executables 
341 for a reference see 
342 http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
343 http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
344 */
345 OUTPUT_FORMAT(pei-i386)
346 SEARCH_DIR("/usr/i686-pc-cygwin/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/lib/w32api");
347 ENTRY(_mainCRTStartup)
348 SECTIONS
349 {
350   .text  __image_base__ + __section_alignment__  :
351   {
352      *(.init)
353     *(.text)
354     *(SORT(.text$*))
355     *(.glue_7t)
356     *(.glue_7)
357      ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
358                         LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*));  LONG (0);
359      ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
360                         LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*));  LONG (0);
361      *(.fini)
362     /* ??? Why is .gcc_exc here?  */
363      *(.gcc_exc)
364     PROVIDE (etext = .);
365     *(.gcc_except_table)
366   }
367   /* The Cygwin32 library uses a section to avoid copying certain data
368      on fork.  This used to be named ".data".  The linker used
369      to include this between __data_start__ and __data_end__, but that
370      breaks building the cygwin32 dll.  Instead, we name the section
371      ".data_cygwin_nocopy" and explictly include it after __data_end__. */
372   .data BLOCK(__section_alignment__) :
373   {
374     __data_start__ = . ;
375     *(.data)
376     *(.data2)
377     *(SORT(.data$*))
378     *(.rdata)
379     *(SORT(.rdata$*))
380     *(.eh_frame)
381     ___RUNTIME_PSEUDO_RELOC_LIST__ = .;
382     __RUNTIME_PSEUDO_RELOC_LIST__ = .;
383     *(.rdata_runtime_pseudo_reloc)
384     ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
385     __RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
386     __data_end__ = . ;
387     *(.data_cygwin_nocopy)
388   }
389   .rdata BLOCK(__section_alignment__) :
390   {
391   }
392   .pdata BLOCK(__section_alignment__) :
393   {
394     *(.pdata)
395   }
396   .bss BLOCK(__section_alignment__) :
397   {
398     __bss_start__ = . ;
399     *(.bss)
400     *(COMMON)
401     __bss_end__ = . ;
402   }
403   .edata BLOCK(__section_alignment__) :
404   {
405     *(.edata)
406   }
407   /DISCARD/ :
408   {
409     *(.debug$S)
410     *(.debug$T)
411     *(.debug$F)
412     *(.drectve)
413   }
414   .idata BLOCK(__section_alignment__) :
415   {
416     /* This cannot currently be handled with grouped sections.
417         See pe.em:sort_sections.  */
418     SORT(*)(.idata$2)
419     SORT(*)(.idata$3)
420     /* These zeroes mark the end of the import list.  */
421     LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
422     SORT(*)(.idata$4)
423     SORT(*)(.idata$5)
424     SORT(*)(.idata$6)
425     SORT(*)(.idata$7)
426   }
427   .CRT BLOCK(__section_alignment__) :
428   {
429     ___crt_xc_start__ = . ;
430     *(SORT(.CRT$XC*))  /* C initialization */
431     ___crt_xc_end__ = . ;
432     ___crt_xi_start__ = . ;
433     *(SORT(.CRT$XI*))  /* C++ initialization */
434     ___crt_xi_end__ = . ;
435     ___crt_xl_start__ = . ;
436     *(SORT(.CRT$XL*))  /* TLS callbacks */
437     /* ___crt_xl_end__ is defined in the TLS Directory support code */
438     ___crt_xp_start__ = . ;
439     *(SORT(.CRT$XP*))  /* Pre-termination */
440     ___crt_xp_end__ = . ;
441     ___crt_xt_start__ = . ;
442     *(SORT(.CRT$XT*))  /* Termination */
443     ___crt_xt_end__ = . ;
444   }
445   .tls BLOCK(__section_alignment__) :
446   {
447     ___tls_start__ = . ;
448     *(.tls)
449     *(.tls$)
450     *(SORT(.tls$*))
451     ___tls_end__ = . ;
452   }
453   .endjunk BLOCK(__section_alignment__) :
454   {
455     /* end is deprecated, don't use it */
456     PROVIDE (end = .);
457     PROVIDE ( _end = .);
458      __end__ = .;
459   }
460   .rsrc BLOCK(__section_alignment__) :
461   {
462     *(.rsrc)
463     *(SORT(.rsrc$*))
464   }
465   .reloc BLOCK(__section_alignment__) :
466   {
467     *(.reloc)
468   }
469   .stab BLOCK(__section_alignment__) (NOLOAD) :
470   {
471     *(.stab)
472   }
473   .stabstr BLOCK(__section_alignment__) (NOLOAD) :
474   {
475     *(.stabstr)
476   }
477   /* DWARF debug sections.
478      Symbols in the DWARF debugging sections are relative to the beginning
479      of the section.  Unlike other targets that fake this by putting the
480      section VMA at 0, the PE format will not allow it.  */
481   /* DWARF 1.1 and DWARF 2.  */
482   .debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
483   {
484     *(.debug_aranges)
485   }
486   .debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
487   {
488     *(.debug_pubnames)
489   }
490   /* DWARF 2.  */
491   .debug_info BLOCK(__section_alignment__) (NOLOAD) :
492   {
493     *(.debug_info) *(.gnu.linkonce.wi.*)
494   }
495   .debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
496   {
497     *(.debug_abbrev)
498   }
499   .debug_line BLOCK(__section_alignment__) (NOLOAD) :
500   {
501     *(.debug_line)
502   }
503   .debug_frame BLOCK(__section_alignment__) (NOLOAD) :
504   {
505     *(.debug_frame)
506   }
507   .debug_str BLOCK(__section_alignment__) (NOLOAD) :
508   {
509     *(.debug_str)
510   }
511   .debug_loc BLOCK(__section_alignment__) (NOLOAD) :
512   {
513     *(.debug_loc)
514   }
515   .debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
516   {
517     *(.debug_macinfo)
518   }
519   /* SGI/MIPS DWARF 2 extensions.  */
520   .debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
521   {
522     *(.debug_weaknames)
523   }
524   .debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
525   {
526     *(.debug_funcnames)
527   }
528   .debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
529   {
530     *(.debug_typenames)
531   }
532   .debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
533   {
534     *(.debug_varnames)
535   }
536   /* DWARF 3.  */
537   .debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
538   {
539     *(.debug_ranges)
540   }
541 }
542 ''')
543   script.close()
544   return(ld_script)
545
546
547 try:
548   # these will be used under win32
549   import win32file
550   import win32event
551   import win32process
552   import win32security
553 except:
554   # does not matter if it fails on other systems
555   pass
556
557
558 class loggedSpawn:
559   def __init__(self, env, logfile, longarg, info):
560     # save the spawn system
561     self.env = env
562     self.logfile = logfile
563     # clear the logfile (it may not exist)
564     if logfile != '':
565       # this will overwrite existing content.
566       writeToFile(logfile, info, append=False)
567     # 
568     self.longarg = longarg
569     # get hold of the old spawn? (necessary?)
570     self._spawn = env['SPAWN']
571
572   # define new SPAWN
573   def spawn(self, sh, escape, cmd, args, spawnenv):
574     # get command line
575     newargs = ' '.join(map(escape, args[1:]))
576     cmdline = cmd + " " + newargs
577     #
578     # if log is not empty, write to it
579     if self.logfile != '':
580       # this tend to be slow (?) but ensure correct output
581       # Note that cmdline may be long so I do not escape it
582       try:
583         # since this is not an essential operation, proceed if things go wrong here.
584         writeToFile(self.logfile, cmd + " " + ' '.join(args[1:]) + '\n', append=True)
585       except:
586         print "Warning: can not write to log file ", self.logfile
587     #
588     # if the command is not too long, use the old
589     if not self.longarg or len(cmdline) < 8000:
590       exit_code = self._spawn(sh, escape, cmd, args, spawnenv)
591     else:  
592       sAttrs = win32security.SECURITY_ATTRIBUTES()
593       StartupInfo = win32process.STARTUPINFO()
594       for var in spawnenv:
595         spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
596       # check for any special operating system commands
597       if cmd == 'del':
598         for arg in args[1:]:
599           win32file.DeleteFile(arg)
600         exit_code = 0
601       else:
602         # otherwise execute the command.
603         hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
604         win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
605         exit_code = win32process.GetExitCodeProcess(hProcess)
606         win32file.CloseHandle(hProcess);
607         win32file.CloseHandle(hThread);
608     return exit_code
609
610
611 def setLoggedSpawn(env, logfile = '', longarg=False, info=''):
612   ''' This function modify env and allow logging of
613     commands to a logfile. If the argument is too long
614     a win32 spawn will be used instead of the system one
615   '''
616   #
617   # create a new spwn object
618   ls = loggedSpawn(env, logfile, longarg, info)
619   # replace the old SPAWN by the new function
620   env['SPAWN'] = ls.spawn
621
622
623 ## def CheckPython(context, minver):
624 ##     context.Message('Checking for Python >= %s...' % '.'.join(str(x) for x in minver))
625 ##     try:
626 ##         python = context.env['PYTHON']
627 ##     except KeyError:
628 ##         try:
629 ##             python = os.environ['PYTHON']
630 ##         except KeyError:
631 ##             python = WhereIs("python")
632 ##             if not python:
633 ##                 python = python = WhereIs("python%i.%i" % (minver[0], minver[1]))
634 ##     minverhex = 0
635 ##     minver = list(minver) + [0, 0, 0, 0]
636 ##     for i in xrange(0, 4):
637 ##         minverhex = (minverhex << 8) + minver[i]
638 ##     prog = "import sys; sys.exit(sys.hexversion >= %s)" % minverhex
639 ##     if python is None:
640 ##         python = 'python'
641 ##     try:
642 ##         result = Popen([python, "-c", prog]).wait()
643 ##     except OSError:
644 ##         context.Result(False)
645 ##         return False
646 ##     context.Result(result)
647 ##     if result:
648 ##         context.env.Replace(PYTHON=python)
649 ##         proc = Popen([python, "-c", "import sys; print sys.version[:3]"], stdout=PIPE)
650 ##         pyver = proc.communicate()[0].rstrip()
651 ##         context.env.Replace(PYTHON_VERSION=pyver)
652 ##         context.env.Replace(pythondir="$prefix/lib/python$PYTHON_VERSION/site-packages")
653 ##         context.env.Replace(pyexecdir="${exec_prefix}/lib/python$PYTHON_VERSION/site-packages")
654 ##     return result
655 ## 
656 ## def DistSources(env, node):
657 ##     env.DistFiles(_get_sources(env, node))
658 ## 
659 ## def DistFiles(env, files):
660 ##     assert isinstance(files, (list, tuple))
661 ##     DISTFILES = [env.File(fname) for fname in files]
662 ##     env.AppendUnique(DISTFILES=DISTFILES)
663 ## 
664 ## 
665 ## def make_distdir(target=None, source=None, env=None):
666 ##     distdir = env.subst('$DISTDIR')
667 ##     Execute(Delete(distdir))
668 ##     Execute(Mkdir(distdir))
669 ##     for fnode in env["DISTFILES"]:
670 ##         dirname, fname = os.path.split(str(fnode))
671 ##         if dirname:
672 ##             distdirname = os.path.join(distdir, dirname)
673 ##             if not os.path.exists(distdirname):
674 ##                 Execute(Mkdir(distdirname))
675 ##         Execute(Copy(os.path.join(distdir, dirname, fname), str(fnode)))
676 ##     
677 ## def make_dist(target=None, source=None, env=None):
678 ##     return Popen([env['TAR'], "-zcf",
679 ##                   env.subst("${PACKAGE}-${VERSION}.tar.gz"),
680 ##                   env.subst('$DISTDIR')]).wait()
681 ## 
682 ## def make_distcheck(target=None, source=None, env=None):
683 ##     distdir = env.subst('$DISTDIR')
684 ##     distcheckinstdir = tempfile.mkdtemp('', env.subst('${PACKAGE}-${VERSION}-instdir-'))
685 ##     distcheckdestdir = tempfile.mkdtemp('', env.subst('${PACKAGE}-${VERSION}-destdir-'))
686 ##     instdirs = [os.path.join(distcheckinstdir, d) for d in
687 ##                 'lib', 'share', 'bin', 'include']
688 ##     for dir_ in instdirs:
689 ##         Execute(Mkdir(dir_))
690 ## 
691 ##     cmd = env.subst("cd $DISTDIR && scons DESTDIR=%s prefix=%s"
692 ##                     " && scons check && scons install") %\
693 ##             (os.path.join(distcheckdestdir, ''), distcheckinstdir)
694 ##     status = Popen(cmd, shell=True).wait()
695 ##     if status:
696 ##         return status
697 ##     ## Check that inst dirs are empty (to catch cases of $DESTDIR not being honored
698 ##     for dir_ in instdirs:
699 ##         if os.listdir(dir_):
700 ##             raise SCons.Errors.BuildError(target, "%s not empy" % dir_)
701 ##     ## Check that something inside $DESTDIR was installed
702 ##     dir_ = os.path.join(distcheckdestdir, distcheckinstdir)
703 ##     if not os.path.exists(dir_):
704 ##         raise SCons.Errors.BuildError(target, "%s does not exist" % dir_)
705 ##     Execute(Delete(distcheckinstdir))
706 ##     Execute(Delete(distcheckdestdir))
707 ##     Execute(Delete(distdir))
708 ## 
709 ## def InstallWithDestDir(self, dir_, source):
710 ##     dir_ = '${DESTDIR}' + str(dir_)
711 ##     return SConsEnvironment.Install(self, dir_, source)
712 ## 
713 ## 
714 ## def InstallAsWithDestDir(self, target, source):
715 ##     target = '${DESTDIR}' + str(target)
716 ##     return SConsEnvironment.InstallAs(self, target, source)
717 ## 
718 ## def generate(env):
719 ##     env.EnsureSConsVersion(0, 96, 91)
720 ## 
721 ##     opts = Options(['options.cache'], ARGUMENTS)
722 ##     opts.Add(PathOption('prefix', 'Installation prefix', '/usr/local'))
723 ##     opts.Add(PathOption('exec_prefix', 'Installation prefix blah blah',
724 ##                         '$prefix'))
725 ##     opts.Add(PathOption('libdir',
726 ##         'Installation prefix for architecture dependent files', '$prefix/lib'))
727 ##     opts.Add(PathOption('includedir',
728 ##         'Installation prefix for C header files', '$prefix/include'))
729 ##     opts.Add(PathOption('datadir',
730 ##         'Installation prefix for architecture independent files', '$prefix/share'))
731 ##     opts.Add(PathOption('bindir', 'Installation prefix for programs', '$prefix/bin'))
732 ##     opts.Add(PathOption('DESTDIR', 'blah blah', None))
733 ##     opts.Update(env)
734 ##     opts.Save('options.cache', env)
735 ##     SConsEnvironment.Help(env, opts.GenerateHelpText(env))
736 ##     
737 ##     env.Append(CPPFLAGS=r' -DVERSION=\"$VERSION\"')
738 ##     env.Append(CCFLAGS=ARGUMENTS.get('CCFLAGS', '-g -O2'))
739 ## 
740 ##     env['GNOME_TESTS'] = dict(CheckPython=CheckPython,
741 ##                               CheckPythonHeaders=CheckPythonHeaders,
742 ##                               PkgCheckModules=PkgCheckModules)
743 ## 
744 ##     SConsEnvironment.DistSources = DistSources
745 ##     SConsEnvironment.DistFiles = DistFiles
746 ##     env['DISTDIR'] = "${PACKAGE}-${VERSION}"
747 ## 
748 ##     #env.Command(env.Dir("$DISTDIR"), None, make_distdir)
749 ##     
750 ##     distdir_alias = env.Alias("distdir", None, make_distdir)
751 ##     dist_alias = env.Alias("dist", None, make_dist)
752 ##     env.Depends(dist_alias, distdir_alias)
753 ##     distcheck_alias = env.Alias("distcheck", None, make_distcheck)
754 ##     env.Depends(distcheck_alias, distdir_alias)
755 ##     env.AlwaysBuild(env.Alias('check'))
756 ## 
757 ##     #env['TARFLAGS'] ='-c -z'
758 ##     #env['TARSUFFIX'] = '.tar.gz'
759 ##     #tar = env.Tar('${PACKAGE}-${VERSION}.tar.gz', "${DISTDIR}")
760 ##     #env.Depends(tar, distdir_alias)
761 ##     #print env['DEFAULT_TARGETS']
762 ## 
763 ##     #env.Depends(distdir_alias, "${DISTFILES}")
764 ##     #env.Alias('dist', tar)
765 ##     env.AlwaysBuild('dist')
766 ##     env.AlwaysBuild('distdir')
767 ##     env.AlwaysBuild('distcheck')
768 ##     env.DistFiles(['SConstruct', 'scons/gnome.py'])
769 ## 
770 ##     env['BUILDERS']['EnvSubstFile'] = SCons.Builder.Builder(action=env_subst)
771 ## 
772 ##     SConsEnvironment.PythonByteCompile = env.Action(byte_compile_python)
773 ##     
774 ##     env.Install = new.instancemethod(InstallWithDestDir, env, env.__class__)
775 ##     env.InstallAs = new.instancemethod(InstallAsWithDestDir, env, env.__class__)
776 ## 
777 ## 
778 ##  
779