File: scons_utils.py

package info (click to toggle)
lyx 2.0.3-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 96,552 kB
  • sloc: cpp: 388,556; python: 19,985; ansic: 9,725; sh: 5,696; makefile: 3,907; pascal: 1,388; objc: 985; perl: 319; yacc: 289; tcl: 163; xml: 23; sed: 16
file content (909 lines) | stat: -rw-r--r-- 30,247 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
# vi:filetype=python:expandtab:tabstop=4:shiftwidth=4
#
# file scons_utils.py
#
# This file is part of LyX, the document processor.
# Licence details can be found in the file COPYING.
#
# \author Bo Peng
# Full author contact details are available in file CREDITS.
#
# This file defines all the utility functions for the
# scons-based build system of lyx
#

import os, sys, re, shutil, glob
from SCons.Util import *


def getVerFromConfigure(path):
    ''' get lyx version from the AC_INIT line of configure.ac,
        packed major and minor version numbers from the lyx version,
        and LYX_DATE from an AC_SUBST line.
    '''
    try:
        config = open(os.path.join(path, 'configure.ac'))
    except:
        print "Can not open configure.ac. "
        return 'x.x.x'
    # find a line like follows
    # AC_INIT(LyX,1.4.4svn,[lyx-devel@lists.lyx.org],[lyx])
    ver_pat = re.compile('AC_INIT\([^,]+,([^,]+),')
    date_pat = re.compile('AC_SUBST\(LYX_DATE, \["(.*)"\]\)')
    majmin_pat = re.compile('(\d+)\.(\d+)\..*')
    version = 'x.x.x'
    majmin = 'xx'
    date = 'Not released'
    for line in config.readlines():
        if ver_pat.match(line):
            (version,) = ver_pat.match(line).groups()
            majmin_match = majmin_pat.match(version)
            majmin = majmin_match.group(1) + majmin_match.group(2)
        if date_pat.match(line):
            (date,) = date_pat.match(line).groups()
        if version != 'x.x.x' and date != 'Not released':
            break
    return version.strip(), majmin.strip(), date.strip()


def relativePath(path, base):
    '''return relative path from base, which is usually top source dir'''
    # full pathname of path
    path1 = os.path.normpath(os.path.realpath(path)).split(os.sep)
    path2 = os.path.normpath(os.path.realpath(base)).split(os.sep)
    if path1[:len(path2)] != path2:
        print "Path %s is not under top source directory" % path
    if len(path2) == len(path1):
        return ''
    path3 = os.path.join(*path1[len(path2):]);
    # replace all \ by / such that we get the same comments on Windows and *nix
    path3 = path3.replace('\\', '/')
    return path3


def isSubDir(path, base):
    '''Whether or not path is a subdirectory of base'''
    path1 = os.path.normpath(os.path.realpath(path)).split(os.sep)
    path2 = os.path.normpath(os.path.realpath(base)).split(os.sep)
    return len(path2) <= len(path1) and path1[:len(path2)] == path2


def writeToFile(filename, lines, append = False):
    " utility function: write or append lines to filename "
    # create directory if needed
    dir = os.path.split(filename)[0]
    if dir != '' and not os.path.isdir(dir):
        os.makedirs(dir)
    if append:
        file = open(filename, 'a')
    else:
        file = open(filename, 'w')
    file.write(lines)
    file.close()


def env_subst(target, source, env):
    ''' subst variables in source by those in env, and output to target
        source and target are scons File() objects

        %key% (not key itself) is an indication of substitution
    '''
    assert len(target) == 1
    assert len(source) == 1
    target_file = file(str(target[0]), "w")
    source_file = file(str(source[0]), "r")

    contents = source_file.read()
    for k, v in env.items():
        try:
            val = env.subst('$'+k)
            # temporary fix for the \Resource backslash problem
            val = val.replace('\\', '/')
            # multi-line replacement
            val = val.replace('\n',r'\\n\\\n')
            contents = re.sub('@'+k+'@', val, contents)
        except:
            pass
    target_file.write(contents + "\n")
    target_file.close()
    #st = os.stat(str(source[0]))
    #os.chmod(str(target[0]), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)


def env_nsis(source, target, env, for_signature):
    ''' Get nsis command line '''
    def quoteIfSpaced(str):
        if ' ' in str:
            return '"' + str + '"'
        else:
            return str
    ret = env['NSIS'] + " /V1 "
    if env.has_key('NSISFLAGS'):
        for flag in env['NSISFLAGS']:
            ret += flag
            ret += ' '
    if env.has_key('NSISDEFINES'):
        for d in env['NSISDEFINES']:
            ret += '/D'+d
            if env['NSISDEFINES'][d]:
                ret += '=' + quoteIfSpaced(env['NSISDEFINES'][d])
            ret += ' '
    # bundled?
    if '-bundle.exe' in str(target[0]):
        ret += '/DSETUPTYPE=BUNDLE '
    for s in source:
        ret += quoteIfSpaced(str(s))
    return ret


def env_toc(target, source, env):
    '''Generate target from source files'''
    # this is very tricky because we need to use installed lyx2lyx with 
    # correct lyx2lyx_version.py
    sys.path.append(env['LYX2LYX_DEST'])
    sys.path.append(env.Dir('$TOP_SRCDIR/lib/doc').abspath)
    import doc_toc
    # build toc
    doc_toc.build_toc(str(target[0]), [file.abspath for file in source])
    
    
def env_cat(target, source, env):
    '''Cat source > target. Avoid pipe to increase portability'''
    output = open(env.File(target[0]).abspath, 'w')
    for src in source:
        input = open(env.File(src).abspath)
        output.write(input.read())
        input.close()
    output.close()


def env_potfiles(target, source, env):
    '''Build po/POTFILES.in'''
    # command 
    #   grep -l '_(\".*\")' `find src \( -name '*.h' -o -name '*.cpp' -o -name '*.cpp.in' \) -print` | grep -v -e "src/support/Package.cpp$$" | sort | uniq
    # is used under *nix but windows users have to do these all in python
    target_file = open(str(target[0]), "w")
    potfiles = []
    trans = re.compile('_\(".*"\)', re.M)
    for file in source:
        rel_file = relativePath(str(file), env.subst('$TOP_SRCDIR'))
        if rel_file not in potfiles and trans.search(open(str(file)).read()):
            potfiles.append(rel_file)
    potfiles.sort()
    print >> target_file, '\n'.join(potfiles)
    target_file.close()

    
def createResFromIcon(env, icon_file, rc_file):
    ''' create a rc file with icon, and return res file (windows only) '''
    if os.name == 'nt':
        rc_name = env.File(rc_file).abspath
        dir = os.path.split(rc_name)[0]
        if not os.path.isdir(dir):
            os.makedirs(dir)
        rc = open(rc_name, 'w')
        print >> rc, 'IDI_ICON1  ICON DISCARDABLE "%s"' % \
            os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'development', 'win32',
                'packaging', 'icons', icon_file).replace('\\', '\\\\')
        rc.close()
        return env.RES(rc_name)
    else:
        return []


def env_qtResource(target, source, env):
    '''Create resource.qrc'''
    qrc = open(str(target[0]), 'w')
    print >> qrc, "<!DOCTYPE RCC><RCC version='1.0'><qresource>"
    for file in source:
        rel_file = relativePath(str(file), env.subst('$TOP_SRCDIR/lib'))
        abs_file = str(file.abspath)
        print >> qrc, '<file alias="%s">%s</file>' % (rel_file, abs_file)
    print >> qrc, '</qresource></RCC>'
    qrc.close()

#
# autoconf tests
#

def checkPkgConfig(conf, version):
    ''' Return false if pkg_config does not exist, or is too old '''
    conf.Message('Checking for pkg-config...')
    ret = conf.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
    conf.Result(ret)
    return ret


def checkPackage(conf, pkg):
    ''' check if pkg is under the control of conf '''
    conf.Message('Checking for package %s...' % pkg)
    ret = conf.TryAction("pkg-config --print-errors --exists %s" % pkg)[0]
    conf.Result(ret)
    return ret


def checkMkdirOneArg(conf):
    check_mkdir_one_arg_source = """
#include <sys/stat.h>
int main()
{
    mkdir("somedir");
}
"""
    conf.Message('Checking for the number of args for mkdir... ')
    ret = conf.TryLink(check_mkdir_one_arg_source, '.c') or \
        conf.TryLink('#include <unistd.h>' + check_mkdir_one_arg_source, '.c') or \
        conf.TryLink('#include <direct.h>' + check_mkdir_one_arg_source, '.c')
    if ret:
        conf.Result('one')
    else:
        conf.Result('two')
    return ret


def checkCXXGlobalCstd(conf):
    ''' Checking the use of std::tolower or tolower '''
    check_global_cstd_source = '''
#include <cctype>
using std::tolower;
int main()
{
    return 0;
}
'''
    conf.Message('Checking for the use of global cstd... ')
    # if can not compile, define CXX_GLOBAL_CSTD
    ret = conf.TryLink(check_global_cstd_source, '.cpp')
    conf.Result(ret)
    return ret


def checkSelectArgType(conf):
    ''' Adapted from autoconf '''
    conf.Message('Checking for arg types for select... ')
    for arg234 in ['fd_set *', 'int *', 'void *']:
        for arg1 in ['int', 'size_t', 'unsigned long', 'unsigned']:
            for arg5 in ['struct timeval *', 'const struct timeval *']:
                check_select_source = '''
#if HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#if HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
extern int select (%s, %s, %s, %s, %s);
int main()
{
    return(0);
}
''' % (arg1, arg234, arg234, arg234, arg5)
                ret = conf.TryLink(check_select_source, '.c')
                if ret:
                    conf.Result(ret)
                    return (arg1, arg234, arg5)
    conf.Result('no (use default)')
    return ('int', 'int *', 'struct timeval *')


def checkBoostLibraries(conf, libs, lib_paths, inc_paths, versions, isDebug):
    ''' look for boost libraries
      libs: library names
      lib_paths: try these paths for boost libraries
      inc_paths: try these paths for boost headers
      versions:   supported boost versions
      isDebug:   if true, use debug libraries
    '''
    conf.Message('Checking for boost library %s... ' % ', '.join(libs))
    libprefix = conf.env['LIBPREFIX']
    libsuffix = '(%s|%s)' % (conf.env['LIBSUFFIX'], conf.env['SHLIBSUFFIX'])
    found_lib = False
    found_inc = False
    lib_names = []
    lib_path = None
    inc_path = None
    for path in lib_paths:
        conf.Log("Looking into %s\n" % path)
        for lib in libs:
            # get all the libs, then filter for the right library
            files = glob.glob(os.path.join(path, '%sboost_%s-*.*' % (libprefix, lib)))
            # check things like libboost_iostreams-gcc-mt-d-1_33_1.a
            if len(files) > 0:
                conf.Log("Find boost libraries: %s\n" % files)
                # runtime code includes s,g,y,d,p,n, where we should look for
                # d,g,y for debug, s,p,n for release
                lib_files = []
                if isDebug:
                    for ver in versions:
                        lib_files += filter(lambda x: re.search('%sboost_%s-\w+-mt-[^spn]+-%s%s' % (libprefix, lib, ver, libsuffix), x), files)
                else:
                    for ver in versions:
                        lib_files += filter(lambda x: re.search('%sboost_%s-\w+-mt-([^dgy]+-)*%s%s' % (libprefix, lib, ver, libsuffix), x), files)
                if len(lib_files) == 0:
                    # use alternative libraries
                    for ver in versions:
                        lib_files += filter(lambda x: re.search('%sboost_%s-[\w-]+%s%s' % (libprefix, lib, ver, libsuffix), x), files)
                if len(lib_files) > 0:
                    # get xxx-gcc-1_33_1 from /usr/local/lib/libboost_xxx-gcc-1_33_1.a
                    name = lib_files[0].split(os.sep)[-1][len(libprefix):]
                    lib_names.append(name.split('.')[0])
                    conf.Log("Qualified libraries: %s\n" % lib_names)
                else:
                    conf.Log("No qualified library is found.\n")
                    break
        if len(lib_names) == len(libs):
            found_lib = True
            lib_path = path
            break
    if not found_lib:
        if len(lib_names) == 0:
            conf.Log("No boost library is found\n")
        else:
            conf.Log("Found boost libraries: %s\n" % lib_names)
        conf.Result('no')
        return (None, None, None)
    # check version number in boost/version.hpp
    def isValidBoostDir(dir):
        version_file = os.path.join(dir, 'boost', 'version.hpp')
        if not os.path.isfile(version_file):
            return False
        version_file_content = open(version_file).read()
        version_strings = ['#define BOOST_LIB_VERSION "%s"' % ver for ver in versions]
        return True in [x in version_file_content for x in version_strings]
    # check for boost header file
    for path in inc_paths:
        conf.Log("Checking for inc path: %s\n" % path)
        if isValidBoostDir(path):
            inc_path = path
            found_inc = True
        else:   # check path/boost_1_xx_x/boost
            dirs = glob.glob(os.path.join(path, 'boost-*'))
            if len(dirs) > 0 and isValidBoostDir(dirs[0]):
                conf.Log("Checing for sub directory: %s\n" % dirs[0])
                inc_path = dirs[0]
                found_inc = True
    # return result
    if found_inc:
        conf.Result('yes')
        conf.Log('Using boost libraries %s\n' % (', '.join(lib_names)))
        return (lib_names, lib_path, inc_path)
    else:
        conf.Result('no')
        return (None, None, None)


def checkCommand(conf, cmd):
    ''' check the existence of a command
        return full path to the command, or none
    '''
    conf.Message('Checking for command %s...' % cmd)
    res = WhereIs(cmd)
    conf.Result(res is not None)
    return res


def checkNSIS(conf):
    ''' check the existence of nsis compiler, return the fullpath '''
    conf.Message('Checking for nsis compiler...')
    res = None
    if can_read_reg:
        # If we can read the registry, get the NSIS command from it
        try:
            k = RegOpenKeyEx(hkey_mod.HKEY_LOCAL_MACHINE,
                                  'SOFTWARE\\NSIS')
            val, tok = RegQueryValueEx(k,None)
            ret = val + os.path.sep + 'makensis.exe'
            if os.path.isfile(ret):
                res = '"' + ret + '"'
            else:
                res = None
        except:
            pass # Couldn't find the key, just act like we can't read the registry
    # Hope it's on the path
    if res is None:
        res = WhereIs('makensis.exe')
    conf.Result(res is not None)
    return res


def checkLC_MESSAGES(conf):
    ''' check the definition of LC_MESSAGES '''
    check_LC_MESSAGES = '''
#include <locale.h>
int main()
{
    return LC_MESSAGES;
}
'''
    conf.Message('Checking for LC_MESSAGES in locale.h... ')
    ret = conf.TryLink(check_LC_MESSAGES, '.c')
    conf.Result(ret)
    return ret


def checkIconvConst(conf):
    ''' check the declaration of iconv '''
    check_iconv_const = '''
#include <iconv.h>
// this declaration will fail when there already exists a non const char** 
// version which returns size_t
double iconv(iconv_t cd,  char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
int main() {
    return 0; 
}
'''
    conf.Message('Checking if the declaration of iconv needs const... ')
    ret = conf.TryLink(check_iconv_const, '.cpp')
    conf.Result(ret)
    return ret


def checkSizeOfWChar(conf):
    ''' check the size of wchar '''
    check_sizeof_wchar = '''
#include <wchar.h>
int i[ ( sizeof(wchar_t)==%d ? 1 : -1 ) ];
int main()
{
    return 0;
}
'''
    conf.Message('Checking the size of wchar_t... ')
    if conf.TryLink(check_sizeof_wchar % 2, '.cpp'):
        ret = 2
    elif conf.TryLink(check_sizeof_wchar % 4, '.cpp'):
        ret = 4
    else:
        ret = 0
    conf.Result(str(ret))
    return ret


def checkDeclaration(conf, func, headers):
    ''' check if a function is declared in given headers '''
    check_decl = '''
#include <%%s>
int main()
{
#ifndef %s
    char *p = (char *) %s;
#endif
}
''' % (func, func)
    conf.Message('Checking for the declaration of function %s... ' % func)
    ret = True in [conf.TryLink(check_decl % header, '.c') for header in headers]
    conf.Result(ret)
    return ret

    
def createConfigFile(conf, config_file,
    config_pre = '', config_post = '',
    headers = [], functions = [], declarations = [], types = [], libs = [],
    custom_tests = [], extra_items = []):
    ''' create a configuration file, with options
        config_file: which file to create
        config_pre: first part of the config file
        config_post: last part of the config file
        headers: header files to check, in the form of a list of
            ('file', 'HAVE_FILE', 'c'/'c++')
        functions: functions to check, in the form of a list of
            ('func', 'HAVE_func', 'include lines'/None)
        declarations: function declarations to check, in the form of a list of
            ('func', 'HAVE_DECL_func', header_files)
        types: types to check, in the form of a list of
            ('type', 'HAVE_TYPE', 'includelines'/None)
        libs: libraries to check, in the form of a list of
            ('lib', 'HAVE_LIB', 'LIB_NAME'). HAVE_LIB will be set if 'lib' exists,
            or any of the libs exists if 'lib' is a list of libs.
            Optionally, user can provide another key LIB_NAME, that will
            be set to the detected lib (or None otherwise).
        custom_tests: extra tests to perform, in the form of a list of
            (test (True/False), 'key', 'desc', 'true config line', 'false config line')
            If the last two are ignored, '#define key 1' '/*#undef key */'
            will be used.
        extra_items: extra configuration lines, in the form of a list of
            ('config', 'description')
    Return:
        The result of each test, as a dictioanry of
            res['XXX'] = True/False
        XXX are keys defined in each argument.
    '''
    cont = config_pre + '\n'
    result = {}
    # add to this string, in appropriate format
    def configString(lines, desc=''):
        text = ''
        if lines.strip() != '':
            if desc != '':
                text += '/* ' + desc + ' */\n'
            text += lines + '\n\n'
        return text
    #
    # headers
    for header in headers:
        description = "Define to 1 if you have the <%s> header file." % header[0]
        if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
            (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
            result[header[1]] = 1
            cont += configString('#define %s 1' % header[1], desc = description)
        else:
            result[header[1]] = 0
            cont += configString('/* #undef %s */' % header[1], desc = description)
    # functions
    for func in functions:
        description = "Define to 1 if you have the `%s' function." % func[0]
        if conf.CheckFunc(func[0], header=func[2]):
            result[func[1]] = 1
            cont += configString('#define %s 1' % func[1], desc = description)
        else:
            result[func[1]] = 0
            cont += configString('/* #undef %s */' % func[1], desc = description)
    for decl in declarations:
        description = "Define to 1 if you have the declaration of `%s', and to 0 if you don't." % decl[0]
        if conf.CheckDeclaration(decl[0], decl[2]):
            result[decl[1]] = 1
            cont += configString('#define %s 1' % decl[1], desc = description)
        else:
            result[decl[1]] = 0
            cont += configString('/* #undef %s */' % decl[1], desc = description)
    # types
    for t in types:
        description = "Define to 1 if you have the `%s' type." % t[0]
        if conf.CheckType(t[0], includes=t[2]):
            result[t[1]] = 1
            cont += configString('#define %s 1' % t[1], desc = description)
        else:
            result[t[1]] = 0
            cont += configString('/* #undef %s */' % t[1],  desc = description)
    # libraries
    for lib in libs:
        description = "Define to 1 if you have the `%s' library (-l%s)." % (lib[0], lib[0])
        if type(lib[0]) is type(''):
            lib_list = [lib[0]]
        else:
            lib_list = lib[0]
        # check if any of the lib exists
        result[lib[1]] = 0
        # if user want the name of the lib detected
        if len(lib) == 3:
            result[lib[2]] = None
        for ll in lib_list:
            if conf.CheckLib(ll):
                result[lib[1]] = 1
                if len(lib) == 3:
                    result[lib[2]] = ll
                cont += configString('#define %s 1' % lib[1], desc = description)
                break
        # if not found
        if not result[lib[1]]:
            cont += configString('/* #undef %s */' % lib[1], desc = description)
    # custom tests
    for test in custom_tests:
        if test[0]:
            result[test[1]] = 1
            if len(test) == 3:
                cont += configString('#define %s 1' % test[1], desc = test[2])
            else:
                cont += configString(test[3], desc = test[2])
        else:
            result[test[1]] = 0
            if len(test) == 3:
                cont += configString('/* #undef %s */' % test[1], desc = test[2])
            else:
                cont += configString(test[4], desc = test[2])
    # extra items (no key is returned)
    for item in extra_items:
        cont += configString(item[0], desc = item[1])
    # add the last part
    cont += '\n' + config_post + '\n'
    # write to file
    writeToFile(config_file, cont)
    return result


def installCygwinLDScript(path):
    ''' Install i386pe.x-no-rdata '''
    ld_script = os.path.join(path, 'i386pe.x-no-rdata')
    script = open(ld_script, 'w')
    script.write('''/* specific linker script avoiding .rdata sections, for normal executables
for a reference see
http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
*/
OUTPUT_FORMAT(pei-i386)
SEARCH_DIR("/usr/i686-pc-cygwin/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/lib/w32api");
ENTRY(_mainCRTStartup)
SECTIONS
{
  .text  __image_base__ + __section_alignment__  :
  {
    *(.init)
    *(.text)
    *(SORT(.text$*))
    *(.glue_7t)
    *(.glue_7)
    ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
			LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*));  LONG (0);
    ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
			LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*));  LONG (0);
    *(.fini)
    /* ??? Why is .gcc_exc here?  */
    *(.gcc_exc)
    PROVIDE (etext = .);
    *(.gcc_except_table)
  }
  /* The Cygwin32 library uses a section to avoid copying certain data
    on fork.  This used to be named ".data".  The linker used
    to include this between __data_start__ and __data_end__, but that
    breaks building the cygwin32 dll.  Instead, we name the section
    ".data_cygwin_nocopy" and explictly include it after __data_end__. */
  .data BLOCK(__section_alignment__) :
  {
    __data_start__ = . ;
    *(.data)
    *(.data2)
    *(SORT(.data$*))
    *(.rdata)
    *(SORT(.rdata$*))
    *(.eh_frame)
    ___RUNTIME_PSEUDO_RELOC_LIST__ = .;
    __RUNTIME_PSEUDO_RELOC_LIST__ = .;
    *(.rdata_runtime_pseudo_reloc)
    ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
    __RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
    __data_end__ = . ;
    *(.data_cygwin_nocopy)
  }
  .rdata BLOCK(__section_alignment__) :
  {
  }
  .pdata BLOCK(__section_alignment__) :
  {
    *(.pdata)
  }
  .bss BLOCK(__section_alignment__) :
  {
    __bss_start__ = . ;
    *(.bss)
    *(COMMON)
    __bss_end__ = . ;
  }
  .edata BLOCK(__section_alignment__) :
  {
    *(.edata)
  }
  /DISCARD/ :
  {
    *(.debug$S)
    *(.debug$T)
    *(.debug$F)
    *(.drectve)
  }
  .idata BLOCK(__section_alignment__) :
  {
    /* This cannot currently be handled with grouped sections.
	See pe.em:sort_sections.  */
    SORT(*)(.idata$2)
    SORT(*)(.idata$3)
    /* These zeroes mark the end of the import list.  */
    LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
    SORT(*)(.idata$4)
    SORT(*)(.idata$5)
    SORT(*)(.idata$6)
    SORT(*)(.idata$7)
  }
  .CRT BLOCK(__section_alignment__) :
  {
    ___crt_xc_start__ = . ;
    *(SORT(.CRT$XC*))  /* C initialization */
    ___crt_xc_end__ = . ;
    ___crt_xi_start__ = . ;
    *(SORT(.CRT$XI*))  /* C++ initialization */
    ___crt_xi_end__ = . ;
    ___crt_xl_start__ = . ;
    *(SORT(.CRT$XL*))  /* TLS callbacks */
    /* ___crt_xl_end__ is defined in the TLS Directory support code */
    ___crt_xp_start__ = . ;
    *(SORT(.CRT$XP*))  /* Pre-termination */
    ___crt_xp_end__ = . ;
    ___crt_xt_start__ = . ;
    *(SORT(.CRT$XT*))  /* Termination */
    ___crt_xt_end__ = . ;
  }
  .tls BLOCK(__section_alignment__) :
  {
    ___tls_start__ = . ;
    *(.tls)
    *(.tls$)
    *(SORT(.tls$*))
    ___tls_end__ = . ;
  }
  .endjunk BLOCK(__section_alignment__) :
  {
    /* end is deprecated, don't use it */
    PROVIDE (end = .);
    PROVIDE ( _end = .);
    __end__ = .;
  }
  .rsrc BLOCK(__section_alignment__) :
  {
    *(.rsrc)
    *(SORT(.rsrc$*))
  }
  .reloc BLOCK(__section_alignment__) :
  {
    *(.reloc)
  }
  .stab BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.stab)
  }
  .stabstr BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.stabstr)
  }
  /* DWARF debug sections.
    Symbols in the DWARF debugging sections are relative to the beginning
    of the section.  Unlike other targets that fake this by putting the
    section VMA at 0, the PE format will not allow it.  */
  /* DWARF 1.1 and DWARF 2.  */
  .debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_aranges)
  }
  .debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_pubnames)
  }
  /* DWARF 2.  */
  .debug_info BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_info) *(.gnu.linkonce.wi.*)
  }
  .debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_abbrev)
  }
  .debug_line BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_line)
  }
  .debug_frame BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_frame)
  }
  .debug_str BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_str)
  }
  .debug_loc BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_loc)
  }
  .debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_macinfo)
  }
  /* SGI/MIPS DWARF 2 extensions.  */
  .debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_weaknames)
  }
  .debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_funcnames)
  }
  .debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_typenames)
  }
  .debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_varnames)
  }
  /* DWARF 3.  */
  .debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
  {
    *(.debug_ranges)
  }
}
''')
    script.close()
    return(ld_script)


def installCygwinPostinstallScript(path):
    ''' Install lyx.sh '''
    postinstall_script = os.path.join(path, 'lyx.sh')
    script = open(postinstall_script, 'w')
    script.write(r'''#!/bin/sh

# Add /usr/share/lyx/fonts to /etc/fonts/local.conf
# if it is not already there.
if [ -f /etc/fonts/local.conf ]; then
    grep -q /usr/share/lyx/fonts /etc/fonts/local.conf
    if [ $? -ne 0 ]; then
        sed 's/^<\/fontconfig>/<dir>\/usr\/share\/lyx\/fonts<\/dir>\n<\/fontconfig>/' /etc/fonts/local.conf > /etc/fonts/local.conf.tmp
        mv -f /etc/fonts/local.conf.tmp /etc/fonts/local.conf
        fc-cache /usr/share/lyx/fonts
    fi
fi
    ''')
    script.close()
    return(postinstall_script)


try:
    # these will be used under win32
    import win32file
    import win32event
    import win32process
    import win32security
except:
    # does not matter if it fails on other systems
    pass


class loggedSpawn:
    def __init__(self, env, logfile, longarg, info):
        # save the spawn system
        self.env = env
        self.logfile = logfile
        # clear the logfile (it may not exist)
        if logfile != '':
            # this will overwrite existing content.
            writeToFile(logfile, info, append=False)
        #
        self.longarg = longarg
        # get hold of the old spawn? (necessary?)
        self._spawn = env['SPAWN']

    # define new SPAWN
    def spawn(self, sh, escape, cmd, args, spawnenv):
        # get command line
        newargs = ' '.join(map(escape, args[1:]))
        cmdline = cmd + " " + newargs
        #
        # if log is not empty, write to it
        if self.logfile != '':
            # this tend to be slow (?) but ensure correct output
            # Note that cmdline may be long so I do not escape it
            try:
                # since this is not an essential operation, proceed if things go wrong here.
                writeToFile(self.logfile, cmd + " " + ' '.join(args[1:]) + '\n', append=True)
            except:
                print "Warning: can not write to log file ", self.logfile
        #
        # if the command is not too long, use the old
        if not self.longarg or len(cmdline) < 8000:
            exit_code = self._spawn(sh, escape, cmd, args, spawnenv)
        else:
            sAttrs = win32security.SECURITY_ATTRIBUTES()
            StartupInfo = win32process.STARTUPINFO()
            for var in spawnenv:
                spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
            # check for any special operating system commands
            if cmd == 'del':
                for arg in args[1:]:
                    win32file.DeleteFile(arg)
                exit_code = 0
            else:
                # otherwise execute the command.
                hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
                win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
                exit_code = win32process.GetExitCodeProcess(hProcess)
                win32file.CloseHandle(hProcess);
                win32file.CloseHandle(hThread);
        return exit_code


def setLoggedSpawn(env, logfile = '', longarg=False, info=''):
    ''' This function modify env and allow logging of
        commands to a logfile. If the argument is too long
        a win32 spawn will be used instead of the system one
    '''
    #
    # create a new spwn object
    ls = loggedSpawn(env, logfile, longarg, info)
    # replace the old SPAWN by the new function
    env['SPAWN'] = ls.spawn