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