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