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