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