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