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