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