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