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