]> git.lyx.org Git - lyx.git/blob - development/scons/scons_utils.py
Scons: finalize update_po target.
[lyx.git] / development / scons / scons_utils.py
1 # vi:filetype=python:expandtab:tabstop=4:shiftwidth=4
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 *
17
18
19 def getVerFromConfigure(path):
20     " get lyx version from the AC_INIT line of configure.ac "
21     try:
22         config = open(os.path.join(path, 'configure.ac'))
23     except:
24         print "Can not open configure.ac. "
25         return 'x.x.x'
26     # find a line like follows
27     # AC_INIT(LyX,1.4.4svn,[lyx-devel@lists.lyx.org],[lyx])
28     pat = re.compile('AC_INIT\([^,]+,([^,]+),')
29     for line in config.readlines():
30         if pat.match(line):
31             (version,) = pat.match(line).groups()
32             return version.strip()
33     return 'x.x.x'
34
35
36
37 def writeToFile(filename, lines, append = False):
38     " utility function: write or append lines to filename "
39     # create directory if needed
40     dir = os.path.split(filename)[0]
41     if dir != '' and not os.path.isdir(dir):
42         os.makedirs(dir)
43     if append:
44         file = open(filename, 'a')
45     else:
46         file = open(filename, 'w')
47     file.write(lines)
48     file.close()
49
50
51 def env_subst(target, source, env):
52     ''' subst variables in source by those in env, and output to target
53         source and target are scons File() objects
54
55         %key% (not key itself) is an indication of substitution
56     '''
57     assert len(target) == 1
58     assert len(source) == 1
59     target_file = file(str(target[0]), "w")
60     source_file = file(str(source[0]), "r")
61
62     contents = source_file.read()
63     for k, v in env.items():
64         try:
65             val = env.subst('$'+k)
66             # temporary fix for the \Resource backslash problem
67             val = val.replace('\\', '/')
68             # multi-line replacement
69             val = val.replace('\n',r'\\n\\\n')
70             contents = re.sub('@'+k+'@', val, contents)
71         except:
72             pass
73     target_file.write(contents + "\n")
74     target_file.close()
75     #st = os.stat(str(source[0]))
76     #os.chmod(str(target[0]), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
77
78
79 def env_nsis(source, target, env, for_signature):
80     ''' Get nsis command line '''
81     def quoteIfSpaced(str):
82         if ' ' in str:
83             return '"' + str + '"'
84         else:
85             return str
86     ret = env['NSIS'] + " /V1 "
87     if env.has_key('NSISFLAGS'):
88         for flag in env['NSISFLAGS']:
89             ret += flag
90             ret += ' '
91     if env.has_key('NSISDEFINES'):
92         for d in env['NSISDEFINES']:
93             ret += '/D'+d
94             if env['NSISDEFINES'][d]:
95                 ret += '=' + quoteIfSpaced(env['NSISDEFINES'][d])
96             ret += ' '
97     # bundled?
98     if '-bundle.exe' in str(target[0]):
99         ret += '/DSETUPTYPE_BUNDLE=1 '
100     for s in source:
101         ret += quoteIfSpaced(str(s))
102     return ret
103
104
105 def env_toc(target, source, env):
106     '''Generate target from source files'''
107     # this is very tricky because we need to use installed lyx2lyx with 
108     # correct lyx2lyx_version.py
109     sys.path.append(env['LYX2LYX_DEST'])
110     sys.path.append(env.Dir('$TOP_SRCDIR/lib/doc').abspath)
111     import doc_toc
112     # build toc
113     doc_toc.build_toc(str(target[0]), [file.abspath for file in source])
114     
115     
116 def env_cat(target, source, env):
117     '''Cat source > target. Avoid pipe to increase portability'''
118     output = open(env.File(target[0]).abspath, 'w')
119     for src in source:
120         input = open(env.File(src).abspath)
121         output.write(input.read())
122         input.close()
123     output.close()
124
125
126 def createResFromIcon(env, icon_file, rc_file):
127     ''' create a rc file with icon, and return res file (windows only) '''
128     if os.name == 'nt':
129         rc_name = env.File(rc_file).abspath
130         dir = os.path.split(rc_name)[0]
131         if not os.path.isdir(dir):
132             os.makedirs(dir)
133         rc = open(rc_name, 'w')
134         print >> rc, 'IDI_ICON1  ICON DISCARDABLE "%s"' % \
135             os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'development', 'win32',
136                 'packaging', 'icons', icon_file).replace('\\', '\\\\')
137         rc.close()
138         return env.RES(rc_name)
139     else:
140         return []
141
142
143 #
144 # autoconf tests
145 #
146
147 def checkPkgConfig(conf, version):
148     ''' Return false if pkg_config does not exist, or is too old '''
149     conf.Message('Checking for pkg-config...')
150     ret = conf.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
151     conf.Result(ret)
152     return ret
153
154
155 def checkPackage(conf, pkg):
156     ''' check if pkg is under the control of conf '''
157     conf.Message('Checking for package %s...' % pkg)
158     ret = conf.TryAction("pkg-config --print-errors --exists %s" % pkg)[0]
159     conf.Result(ret)
160     return ret
161
162
163 def checkMkdirOneArg(conf):
164     check_mkdir_one_arg_source = """
165 #include <sys/stat.h>
166 int main()
167 {
168     mkdir("somedir");
169 }
170 """
171     conf.Message('Checking for the number of args for mkdir... ')
172     ret = conf.TryLink(check_mkdir_one_arg_source, '.c') or \
173         conf.TryLink('#include <unistd.h>' + check_mkdir_one_arg_source, '.c') or \
174         conf.TryLink('#include <direct.h>' + check_mkdir_one_arg_source, '.c')
175     if ret:
176         conf.Result('one')
177     else:
178         conf.Result('two')
179     return ret
180
181
182 def checkCXXGlobalCstd(conf):
183     ''' Checking the use of std::tolower or tolower '''
184     check_global_cstd_source = '''
185 #include <cctype>
186 using std::tolower;
187 int main()
188 {
189     return 0;
190 }
191 '''
192     conf.Message('Checking for the use of global cstd... ')
193     ret = conf.TryLink(check_global_cstd_source, '.c')
194     conf.Result(ret)
195     return ret
196
197
198 def checkSelectArgType(conf):
199     ''' Adapted from autoconf '''
200     conf.Message('Checking for arg types for select... ')
201     for arg234 in ['fd_set *', 'int *', 'void *']:
202         for arg1 in ['int', 'size_t', 'unsigned long', 'unsigned']:
203             for arg5 in ['struct timeval *', 'const struct timeval *']:
204                 check_select_source = '''
205 #if HAVE_SYS_SELECT_H
206 # include <sys/select.h>
207 #endif
208 #if HAVE_SYS_SOCKET_H
209 # include <sys/socket.h>
210 #endif
211 extern int select (%s, %s, %s, %s, %s);
212 int main()
213 {
214     return(0);
215 }
216 ''' % (arg1, arg234, arg234, arg234, arg5)
217                 ret = conf.TryLink(check_select_source, '.c')
218                 if ret:
219                     conf.Result(ret)
220                     return (arg1, arg234, arg5)
221     conf.Result('no (use default)')
222     return ('int', 'int *', 'struct timeval *')
223
224
225 def checkBoostLibraries(conf, libs, lib_paths, inc_paths, versions, isDebug):
226     ''' look for boost libraries
227       libs: library names
228       lib_paths: try these paths for boost libraries
229       inc_paths: try these paths for boost headers
230       versions:   supported boost versions
231       isDebug:   if true, use debug libraries
232     '''
233     conf.Message('Checking for boost library %s... ' % ', '.join(libs))
234     libprefix = conf.env['LIBPREFIX']
235     libsuffix = '(%s|%s)' % (conf.env['LIBSUFFIX'], conf.env['SHLIBSUFFIX'])
236     found_lib = False
237     found_inc = False
238     lib_names = []
239     lib_path = None
240     inc_path = None
241     for path in lib_paths:
242         conf.Log("Looking into %s\n" % path)
243         for lib in libs:
244             # get all the libs, then filter for the right library
245             files = glob.glob(os.path.join(path, '%sboost_%s-*.*' % (libprefix, lib)))
246             # check things like libboost_iostreams-gcc-mt-d-1_33_1.a
247             if len(files) > 0:
248                 conf.Log("Find boost libraries: %s\n" % files)
249                 # runtime code includes s,g,y,d,p,n, where we should look for
250                 # d,g,y for debug, s,p,n for release
251                 lib_files = []
252                 if isDebug:
253                     for ver in versions:
254                         lib_files += filter(lambda x: re.search('%sboost_%s-\w+-mt-[^spn]+-%s%s' % (libprefix, lib, ver, libsuffix), x), files)
255                 else:
256                     for ver in versions:
257                         lib_files += filter(lambda x: re.search('%sboost_%s-\w+-mt-([^dgy]+-)*%s%s' % (libprefix, lib, ver, libsuffix), x), files)
258                 if len(lib_files) == 0:
259                     # use alternative libraries
260                     for ver in versions:
261                         lib_files += filter(lambda x: re.search('%sboost_%s-[\w-]+%s%s' % (libprefix, lib, ver, libsuffix), x), files)
262                 if len(lib_files) > 0:
263                     # get xxx-gcc-1_33_1 from /usr/local/lib/libboost_xxx-gcc-1_33_1.a
264                     name = lib_files[0].split(os.sep)[-1][len(libprefix):]
265                     lib_names.append(name.split('.')[0])
266                     conf.Log("Qualified libraries: %s\n" % lib_names)
267                 else:
268                     conf.Log("No qualified library is found.\n")
269                     break
270         if len(lib_names) == len(libs):
271             found_lib = True
272             lib_path = path
273             break
274     if not found_lib:
275         if len(lib_names) == 0:
276             conf.Log("No boost library is found\n")
277         else:
278             conf.Log("Found boost libraries: %s\n" % lib_names)
279         conf.Result('no')
280         return (None, None, None)
281     # check version number in boost/version.hpp
282     def isValidBoostDir(dir):
283         version_file = os.path.join(dir, 'boost', 'version.hpp')
284         if not os.path.isfile(version_file):
285             return False
286         version_file_content = open(version_file).read()
287         version_strings = ['#define BOOST_LIB_VERSION "%s"' % ver for ver in versions]
288         return True in [x in version_file_content for x in version_strings]
289     # check for boost header file
290     for path in inc_paths:
291         conf.Log("Checking for inc path: %s\n" % path)
292         if isValidBoostDir(path):
293             inc_path = path
294             found_inc = True
295         else:   # check path/boost_1_xx_x/boost
296             dirs = glob.glob(os.path.join(path, 'boost-*'))
297             if len(dirs) > 0 and isValidBoostDir(dirs[0]):
298                 conf.Log("Checing for sub directory: %s\n" % dirs[0])
299                 inc_path = dirs[0]
300                 found_inc = True
301     # return result
302     if found_inc:
303         conf.Result('yes')
304         conf.Log('Using boost libraries %s\n' % (', '.join(lib_names)))
305         return (lib_names, lib_path, inc_path)
306     else:
307         conf.Result('no')
308         return (None, None, None)
309
310
311 def checkCommand(conf, cmd):
312     ''' check the existence of a command
313         return full path to the command, or none
314     '''
315     conf.Message('Checking for command %s...' % cmd)
316     res = WhereIs(cmd)
317     conf.Result(res is not None)
318     return res
319
320
321 def checkNSIS(conf):
322     ''' check the existence of nsis compiler, return the fullpath '''
323     conf.Message('Checking for nsis compiler...')
324     res = None
325     if can_read_reg:
326         # If we can read the registry, get the NSIS command from it
327         try:
328             k = RegOpenKeyEx(hkey_mod.HKEY_LOCAL_MACHINE,
329                                   'SOFTWARE\\NSIS')
330             val, tok = RegQueryValueEx(k,None)
331             ret = val + os.path.sep + 'makensis.exe'
332             if os.path.isfile(ret):
333                 res = '"' + ret + '"'
334             else:
335                 res = None
336         except:
337             pass # Couldn't find the key, just act like we can't read the registry
338     # Hope it's on the path
339     if res is None:
340         res = WhereIs('makensis.exe')
341     conf.Result(res is not None)
342     return res
343
344
345 def checkLC_MESSAGES(conf):
346     ''' check the definition of LC_MESSAGES '''
347     check_LC_MESSAGES = '''
348 #include <locale.h>
349 int main()
350 {
351     return LC_MESSAGES;
352 }
353 '''
354     conf.Message('Checking for LC_MESSAGES in locale.h... ')
355     ret = conf.TryLink(check_LC_MESSAGES, '.c')
356     conf.Result(ret)
357     return ret
358
359
360 def checkIconvConst(conf):
361     ''' check the declaration of iconv '''
362     check_iconv_const = '''
363 #include <iconv.h>
364 // this declaration will fail when there already exists a non const char** 
365 // version which returns size_t
366 double iconv(iconv_t cd,  char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
367 int main() {
368     return 0; 
369 }
370 '''
371     conf.Message('Checking if the declaration of iconv needs const... ')
372     ret = conf.TryLink(check_iconv_const, '.c')
373     conf.Result(ret)
374     return ret
375
376
377 def checkSizeOfWChar(conf):
378     ''' check the size of wchar '''
379     check_sizeof_wchar = '''
380 int i[ ( sizeof(wchar_t)==%d ? 1 : -1 ) ];
381 int main()
382 {
383     return 0;
384 }
385 '''
386     conf.Message('Checking the size of wchar_t... ')
387     if conf.TryLink(check_sizeof_wchar % 2, '.cpp'):
388         ret = 2
389     elif conf.TryLink(check_sizeof_wchar % 4, '.cpp'):
390         ret = 4
391     else:
392         ret = 0
393     conf.Result(str(ret))
394     return ret
395
396
397 def createConfigFile(conf, config_file,
398     config_pre = '', config_post = '',
399     headers = [], functions = [], types = [], libs = [],
400     custom_tests = [], extra_items = []):
401     ''' create a configuration file, with options
402         config_file: which file to create
403         config_pre: first part of the config file
404         config_post: last part of the config file
405         headers: header files to check, in the form of a list of
406             ('file', 'HAVE_FILE', 'c'/'c++')
407         functions: functions to check, in the form of a list of
408             ('func', 'HAVE_func', 'include lines'/None)
409         types: types to check, in the form of a list of
410             ('type', 'HAVE_TYPE', 'includelines'/None)
411         libs: libraries to check, in the form of a list of
412             ('lib', 'HAVE_LIB', 'LIB_NAME'). HAVE_LIB will be set if 'lib' exists,
413             or any of the libs exists if 'lib' is a list of libs.
414             Optionally, user can provide another key LIB_NAME, that will
415             be set to the detected lib (or None otherwise).
416         custom_tests: extra tests to perform, in the form of a list of
417             (test (True/False), 'key', 'desc', 'true config line', 'false config line')
418             If the last two are ignored, '#define key 1' '/*#undef key */'
419             will be used.
420         extra_items: extra configuration lines, in the form of a list of
421             ('config', 'description')
422     Return:
423         The result of each test, as a dictioanry of
424             res['XXX'] = True/False
425         XXX are keys defined in each argument.
426     '''
427     cont = config_pre + '\n'
428     result = {}
429     # add to this string, in appropriate format
430     def configString(lines, desc=''):
431         text = ''
432         if lines.strip() != '':
433             if desc != '':
434                 text += '/* ' + desc + ' */\n'
435             text += lines + '\n\n'
436         return text
437     #
438     # headers
439     for header in headers:
440         description = "Define to 1 if you have the <%s> header file." % header[0]
441         if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
442             (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
443             result[header[1]] = 1
444             cont += configString('#define %s 1' % header[1], desc = description)
445         else:
446             result[header[1]] = 0
447             cont += configString('/* #undef %s */' % header[1], desc = description)
448     # functions
449     for func in functions:
450         description = "Define to 1 if you have the `%s' function." % func[0]
451         if conf.CheckFunc(func[0], header=func[2]):
452             result[func[1]] = 1
453             cont += configString('#define %s 1' % func[1], desc = description)
454         else:
455             result[func[1]] = 0
456             cont += configString('/* #undef %s */' % func[1], desc = description)
457     # types
458     for t in types:
459         description = "Define to 1 if you have the `%s' type." % t[0]
460         if conf.CheckType(t[0], includes=t[2]):
461             result[t[1]] = 1
462             cont += configString('#define %s 1' % t[1], desc = description)
463         else:
464             result[t[1]] = 0
465             cont += configString('/* #undef %s */' % t[1],  desc = description)
466     # libraries
467     for lib in libs:
468         description = "Define to 1 if you have the `%s' library (-l%s)." % (lib[0], lib[0])
469         if type(lib[0]) is type(''):
470             lib_list = [lib[0]]
471         else:
472             lib_list = lib[0]
473         # check if any of the lib exists
474         result[lib[1]] = 0
475         # if user want the name of the lib detected
476         if len(lib) == 3:
477             result[lib[2]] = None
478         for ll in lib_list:
479             if conf.CheckLib(ll):
480                 result[lib[1]] = 1
481                 if len(lib) == 3:
482                     result[lib[2]] = ll
483                 cont += configString('#define %s 1' % lib[1], desc = description)
484                 break
485         # if not found
486         if not result[lib[1]]:
487             cont += configString('/* #undef %s */' % lib[1], desc = description)
488     # custom tests
489     for test in custom_tests:
490         if test[0]:
491             result[test[1]] = 1
492             if len(test) == 3:
493                 cont += configString('#define %s 1' % test[1], desc = test[2])
494             else:
495                 cont += configString(test[3], desc = test[2])
496         else:
497             result[test[1]] = 0
498             if len(test) == 3:
499                 cont += configString('/* #undef %s */' % test[1], desc = test[2])
500             else:
501                 cont += configString(test[4], desc = test[2])
502     # extra items (no key is returned)
503     for item in extra_items:
504         cont += configString(item[0], desc = item[1])
505     # add the last part
506     cont += '\n' + config_post + '\n'
507     # write to file
508     writeToFile(config_file, cont)
509     return result
510
511
512 def installCygwinLDScript(path):
513     ''' Install i386pe.x-no-rdata '''
514     ld_script = os.path.join(path, 'i386pe.x-no-rdata')
515     script = open(ld_script, 'w')
516     script.write('''/* specific linker script avoiding .rdata sections, for normal executables
517 for a reference see
518 http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
519 http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
520 */
521 OUTPUT_FORMAT(pei-i386)
522 SEARCH_DIR("/usr/i686-pc-cygwin/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/lib/w32api");
523 ENTRY(_mainCRTStartup)
524 SECTIONS
525 {
526   .text  __image_base__ + __section_alignment__  :
527   {
528     *(.init)
529     *(.text)
530     *(SORT(.text$*))
531     *(.glue_7t)
532     *(.glue_7)
533     ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
534                         LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*));  LONG (0);
535     ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
536                         LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*));  LONG (0);
537     *(.fini)
538     /* ??? Why is .gcc_exc here?  */
539     *(.gcc_exc)
540     PROVIDE (etext = .);
541     *(.gcc_except_table)
542   }
543   /* The Cygwin32 library uses a section to avoid copying certain data
544     on fork.  This used to be named ".data".  The linker used
545     to include this between __data_start__ and __data_end__, but that
546     breaks building the cygwin32 dll.  Instead, we name the section
547     ".data_cygwin_nocopy" and explictly include it after __data_end__. */
548   .data BLOCK(__section_alignment__) :
549   {
550     __data_start__ = . ;
551     *(.data)
552     *(.data2)
553     *(SORT(.data$*))
554     *(.rdata)
555     *(SORT(.rdata$*))
556     *(.eh_frame)
557     ___RUNTIME_PSEUDO_RELOC_LIST__ = .;
558     __RUNTIME_PSEUDO_RELOC_LIST__ = .;
559     *(.rdata_runtime_pseudo_reloc)
560     ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
561     __RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
562     __data_end__ = . ;
563     *(.data_cygwin_nocopy)
564   }
565   .rdata BLOCK(__section_alignment__) :
566   {
567   }
568   .pdata BLOCK(__section_alignment__) :
569   {
570     *(.pdata)
571   }
572   .bss BLOCK(__section_alignment__) :
573   {
574     __bss_start__ = . ;
575     *(.bss)
576     *(COMMON)
577     __bss_end__ = . ;
578   }
579   .edata BLOCK(__section_alignment__) :
580   {
581     *(.edata)
582   }
583   /DISCARD/ :
584   {
585     *(.debug$S)
586     *(.debug$T)
587     *(.debug$F)
588     *(.drectve)
589   }
590   .idata BLOCK(__section_alignment__) :
591   {
592     /* This cannot currently be handled with grouped sections.
593         See pe.em:sort_sections.  */
594     SORT(*)(.idata$2)
595     SORT(*)(.idata$3)
596     /* These zeroes mark the end of the import list.  */
597     LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
598     SORT(*)(.idata$4)
599     SORT(*)(.idata$5)
600     SORT(*)(.idata$6)
601     SORT(*)(.idata$7)
602   }
603   .CRT BLOCK(__section_alignment__) :
604   {
605     ___crt_xc_start__ = . ;
606     *(SORT(.CRT$XC*))  /* C initialization */
607     ___crt_xc_end__ = . ;
608     ___crt_xi_start__ = . ;
609     *(SORT(.CRT$XI*))  /* C++ initialization */
610     ___crt_xi_end__ = . ;
611     ___crt_xl_start__ = . ;
612     *(SORT(.CRT$XL*))  /* TLS callbacks */
613     /* ___crt_xl_end__ is defined in the TLS Directory support code */
614     ___crt_xp_start__ = . ;
615     *(SORT(.CRT$XP*))  /* Pre-termination */
616     ___crt_xp_end__ = . ;
617     ___crt_xt_start__ = . ;
618     *(SORT(.CRT$XT*))  /* Termination */
619     ___crt_xt_end__ = . ;
620   }
621   .tls BLOCK(__section_alignment__) :
622   {
623     ___tls_start__ = . ;
624     *(.tls)
625     *(.tls$)
626     *(SORT(.tls$*))
627     ___tls_end__ = . ;
628   }
629   .endjunk BLOCK(__section_alignment__) :
630   {
631     /* end is deprecated, don't use it */
632     PROVIDE (end = .);
633     PROVIDE ( _end = .);
634     __end__ = .;
635   }
636   .rsrc BLOCK(__section_alignment__) :
637   {
638     *(.rsrc)
639     *(SORT(.rsrc$*))
640   }
641   .reloc BLOCK(__section_alignment__) :
642   {
643     *(.reloc)
644   }
645   .stab BLOCK(__section_alignment__) (NOLOAD) :
646   {
647     *(.stab)
648   }
649   .stabstr BLOCK(__section_alignment__) (NOLOAD) :
650   {
651     *(.stabstr)
652   }
653   /* DWARF debug sections.
654     Symbols in the DWARF debugging sections are relative to the beginning
655     of the section.  Unlike other targets that fake this by putting the
656     section VMA at 0, the PE format will not allow it.  */
657   /* DWARF 1.1 and DWARF 2.  */
658   .debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
659   {
660     *(.debug_aranges)
661   }
662   .debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
663   {
664     *(.debug_pubnames)
665   }
666   /* DWARF 2.  */
667   .debug_info BLOCK(__section_alignment__) (NOLOAD) :
668   {
669     *(.debug_info) *(.gnu.linkonce.wi.*)
670   }
671   .debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
672   {
673     *(.debug_abbrev)
674   }
675   .debug_line BLOCK(__section_alignment__) (NOLOAD) :
676   {
677     *(.debug_line)
678   }
679   .debug_frame BLOCK(__section_alignment__) (NOLOAD) :
680   {
681     *(.debug_frame)
682   }
683   .debug_str BLOCK(__section_alignment__) (NOLOAD) :
684   {
685     *(.debug_str)
686   }
687   .debug_loc BLOCK(__section_alignment__) (NOLOAD) :
688   {
689     *(.debug_loc)
690   }
691   .debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
692   {
693     *(.debug_macinfo)
694   }
695   /* SGI/MIPS DWARF 2 extensions.  */
696   .debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
697   {
698     *(.debug_weaknames)
699   }
700   .debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
701   {
702     *(.debug_funcnames)
703   }
704   .debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
705   {
706     *(.debug_typenames)
707   }
708   .debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
709   {
710     *(.debug_varnames)
711   }
712   /* DWARF 3.  */
713   .debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
714   {
715     *(.debug_ranges)
716   }
717 }
718 ''')
719     script.close()
720     return(ld_script)
721
722
723 def installCygwinPostinstallScript(path):
724     ''' Install lyx.sh '''
725     postinstall_script = os.path.join(path, 'lyx.sh')
726     script = open(postinstall_script, 'w')
727     script.write(r'''#!/bin/sh
728
729 # Add /usr/share/lyx/fonts to /etc/fonts/local.conf
730 # if it is not already there.
731 if [ -f /etc/fonts/local.conf ]; then
732     grep -q /usr/share/lyx/fonts /etc/fonts/local.conf
733     if [ $? -ne 0 ]; then
734         sed 's/^<\/fontconfig>/<dir>\/usr\/share\/lyx\/fonts<\/dir>\n<\/fontconfig>/' /etc/fonts/local.conf > /etc/fonts/local.conf.tmp
735         mv -f /etc/fonts/local.conf.tmp /etc/fonts/local.conf
736         fc-cache /usr/share/lyx/fonts
737     fi
738 fi
739     ''')
740     script.close()
741     return(postinstall_script)
742
743
744 try:
745     # these will be used under win32
746     import win32file
747     import win32event
748     import win32process
749     import win32security
750 except:
751     # does not matter if it fails on other systems
752     pass
753
754
755 class loggedSpawn:
756     def __init__(self, env, logfile, longarg, info):
757         # save the spawn system
758         self.env = env
759         self.logfile = logfile
760         # clear the logfile (it may not exist)
761         if logfile != '':
762             # this will overwrite existing content.
763             writeToFile(logfile, info, append=False)
764         #
765         self.longarg = longarg
766         # get hold of the old spawn? (necessary?)
767         self._spawn = env['SPAWN']
768
769     # define new SPAWN
770     def spawn(self, sh, escape, cmd, args, spawnenv):
771         # get command line
772         newargs = ' '.join(map(escape, args[1:]))
773         cmdline = cmd + " " + newargs
774         #
775         # if log is not empty, write to it
776         if self.logfile != '':
777             # this tend to be slow (?) but ensure correct output
778             # Note that cmdline may be long so I do not escape it
779             try:
780                 # since this is not an essential operation, proceed if things go wrong here.
781                 writeToFile(self.logfile, cmd + " " + ' '.join(args[1:]) + '\n', append=True)
782             except:
783                 print "Warning: can not write to log file ", self.logfile
784         #
785         # if the command is not too long, use the old
786         if not self.longarg or len(cmdline) < 8000:
787             exit_code = self._spawn(sh, escape, cmd, args, spawnenv)
788         else:
789             sAttrs = win32security.SECURITY_ATTRIBUTES()
790             StartupInfo = win32process.STARTUPINFO()
791             for var in spawnenv:
792                 spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
793             # check for any special operating system commands
794             if cmd == 'del':
795                 for arg in args[1:]:
796                     win32file.DeleteFile(arg)
797                 exit_code = 0
798             else:
799                 # otherwise execute the command.
800                 hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
801                 win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
802                 exit_code = win32process.GetExitCodeProcess(hProcess)
803                 win32file.CloseHandle(hProcess);
804                 win32file.CloseHandle(hThread);
805         return exit_code
806
807
808 def setLoggedSpawn(env, logfile = '', longarg=False, info=''):
809     ''' This function modify env and allow logging of
810         commands to a logfile. If the argument is too long
811         a win32 spawn will be used instead of the system one
812     '''
813     #
814     # create a new spwn object
815     ls = loggedSpawn(env, logfile, longarg, info)
816     # replace the old SPAWN by the new function
817     env['SPAWN'] = ls.spawn
818