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