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