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