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