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