]> git.lyx.org Git - lyx.git/blobdiff - development/scons/scons_utils.py
fix scons for Andre's LYX_DATE changes
[lyx.git] / development / scons / scons_utils.py
index 29b4823ebec95e83137f882addd11b28bf1020e6..9fa18265c49a960c712b0640f2138ebef96d9efd 100644 (file)
-# vi:filetype=python:expandtab:tabstop=2:shiftwidth=2
+# 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 WhereIs
+from SCons.Util import *
 
-config_h = os.path.join('src', 'config.h')
-config_content = ''
 
-def writeToFile(filename, lines, append = False):
-  " utility function: write or append lines to filename "
-  if append:
-    file = open(filename, 'a')
-  else:
-    file = open(filename, 'w')
-  file.write(lines)
-  file.close()
-
-
-def printEnvironment(env, keys=[]):
-  ''' used to check profile settings '''
-  dict = env.Dictionary()
-  if len(keys) == 0:
-    keys = dict.keys()
-  keys.sort()
-  for key in keys:
+def getVerFromConfigure(path):
+    ''' get lyx version from the AC_INIT line of configure.ac,
+        and LYX_DATE from an AC_SUBST line.
+    '''
     try:
-      # try to expand, but this is not always possible
-      print key, '=', env.subst('$'+key)
-    except:   
-      print '<<UNEXPANDED>>:', key, '=', dict[key]
+        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, \["(.*)"\]\)')
+    version = 'x.x.x'
+    date = 'Not released'
+    for line in config.readlines():
+        if ver_pat.match(line):
+            (version,) = ver_pat.match(line).groups()
+        if date_pat.match(line):
+            (date,) = date_pat.match(line).groups()
+        if version != 'x.x.x' and date != 'Not released':
+            break
+    return version.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)
-      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)
+    ''' 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=1 '
+    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 []
 
-#
-# glob filenames
-#
-def globSource(dir, pattern, build_dir=None, exclude=[], include=[]):
-  ''' glob files, in dir and use build_dir as returned path name '''
-  files = filter(lambda x: x not in exclude, glob.glob1(dir, pattern)) + include
-  if build_dir is None:
-    return files
-  else:
-    return ['%s/%s' % (build_dir, x) for x in files]
 
 #
 # 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
+    ''' 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 startConfigH():
-  ''' Write the first part of config.h '''
-  global config_content
-  config_content = '''/* src/config.h.  Generated by scon.  */
-
-/* -*- C++ -*- */
-/*
- * \file config.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * This is the compilation configuration file for LyX.
- * It was generated by scon.
- * You might want to change some of the defaults if something goes wrong
- * during the compilation.
- */
-
-#ifndef _CONFIG_H
-#define _CONFIG_H
-'''
-
+    ''' 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 addToConfig(lines, desc=''):
-  ''' utility function: shortcut for appending lines to outfile
-    add newline at the end of lines.
-  '''
-  global config_content
-  if lines.strip() != '':
-    if desc != '':
-      config_content += desc + '\n'
-    config_content += lines + '\n\n'
 
-
-def endConfigH(top_src_dir):
-  ''' Write the last part of config.h '''
-  global config_content
-  writeToFile(os.path.join(top_src_dir, config_h), config_content + 
-'''/************************************************************
- ** You should not need to change anything beyond this point */
-
-#ifndef HAVE_STRERROR
-#if defined(__cplusplus)
-extern "C"
-#endif
-char * strerror(int n);
-#endif
-
-#ifdef HAVE_MKSTEMP
-#ifndef HAVE_DECL_MKSTEMP
-#if defined(__cplusplus)
-extern "C"
-#endif
-int mkstemp(char*);
-#endif
-#endif
-
-#if defined(HAVE_OSTREAM) && defined(HAVE_LOCALE) && defined(HAVE_SSTREAM)
-#  define USE_BOOST_FORMAT 1
-#else
-#  define USE_BOOST_FORMAT 0
-#endif
-
-#define BOOST_USER_CONFIG <config.h>
-
-#if !defined(ENABLE_ASSERTIONS)
-#  define BOOST_DISABLE_ASSERTS 1
-#endif
-#define BOOST_ENABLE_ASSERT_HANDLER 1
-
-#define BOOST_DISABLE_THREADS 1
-#define BOOST_NO_WREGEX 1
-#define BOOST_NO_WSTRING 1
-
-#ifdef __CYGWIN__
-#  define BOOST_POSIX 1
-#endif
-
-#if defined(HAVE_NEWAPIS_H)
-#  define WANT_GETFILEATTRIBUTESEX_WRAPPER 1
-#endif
-
-#endif
-''')
-
-
-#MKDIR_TAKES_ONE_ARG
 def checkMkdirOneArg(conf):
-  check_mkdir_one_arg_source = """
+    check_mkdir_one_arg_source = """
 #include <sys/stat.h>
 int main()
 {
-  mkdir("somedir");
+    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
-
-
-# CXX_GLOBAL_CSTD
+    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):
-  ''' Check the use of std::tolower or tolower '''
-  check_global_cstd_source = '''
+    ''' Checking the use of std::tolower or tolower '''
+    check_global_cstd_source = '''
 #include <cctype>
 using std::tolower;
 int main()
 {
-  return 0;
+    return 0;
 }
 '''
-  conf.Message('Check for the use of global cstd... ')
-  ret = conf.TryLink(check_global_cstd_source, '.c')
-  conf.Result(ret)
-  return ret
+    conf.Message('Checking for the use of global cstd... ')
+    ret = conf.TryLink(check_global_cstd_source, '.c')
+    conf.Result(ret)
+    return ret
 
 
-# SELECT_TYPE_ARG1
-# SELECT_TYPE_ARG234
-# SELECT_TYPE_ARG5
 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 = '''
+    ''' 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
@@ -242,95 +257,337 @@ def checkSelectArgType(conf):
 extern int select (%s, %s, %s, %s, %s);
 int main()
 {
-  return(0);
+    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, lib, pathes):
-  ''' look for boost libraries '''
-  conf.Message('Checking for boost library %s... ' % lib)
-  for path in pathes:
-    # direct form: e.g. libboost_iostreams.a
-    if os.path.isfile(os.path.join(path, 'lib%s.a' % lib)):
-      conf.Result('yes')
-      return (path, lib)
-    # check things like libboost_iostreams-gcc.a
-    files = glob.glob(os.path.join(path, 'lib%s-*.a' % lib))
-    # if there are more than one, choose the first one
-    # FIXME: choose the best one.
-    if len(files) >= 1:
-      # get xxx-gcc from /usr/local/lib/libboost_xxx-gcc.a
-      conf.Result('yes')
-      return (path, files[0].split(os.sep)[-1][3:-2])
-  conf.Result('n')
-  return ('','')
+                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
+    ''' 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 = '''
+    ''' check the definition of LC_MESSAGES '''
+    check_LC_MESSAGES = '''
 #include <locale.h>
 int main()
 {
-  return LC_MESSAGES;
+    return LC_MESSAGES;
 }
 '''
-  conf.Message('Check for LC_MESSAGES in locale.h... ')
-  ret = conf.TryLink(check_LC_MESSAGES, '.c')
-  conf.Result(ret)
-  return ret
+    conf.Message('Checking for LC_MESSAGES in locale.h... ')
+    ret = conf.TryLink(check_LC_MESSAGES, '.c')
+    conf.Result(ret)
+    return ret
 
 
-# FIXME: not quite sure about this part.
 def checkIconvConst(conf):
-  ''' check the declaration of iconv '''
-  check_iconv_const = '''
-#include <stdlib.h>
+    ''' check the declaration of iconv '''
+    check_iconv_const = '''
 #include <iconv.h>
-extern
-#ifdef __cplusplus
-"C"
-#endif
-#if defined(__STDC__) || defined(__cplusplus)
-size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
-#else
-size_t iconv();
-#endif
-extern size_t iconv(iconv_t cd, const char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+// 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, '.c')
+    conf.Result(ret)
+    return ret
+
+
+def checkSizeOfWChar(conf):
+    ''' check the size of wchar '''
+    check_sizeof_wchar = '''
+int i[ ( sizeof(wchar_t)==%d ? 1 : -1 ) ];
 int main()
 {
-  return 1;
+    return 0;
 }
 '''
-  conf.Message('Check if the declaration of iconv needs const... ')
-  ret = conf.TryLink(check_iconv_const, '.c')
-  conf.Result(ret)
-  return ret
+    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 
+    ''' 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
 */
@@ -341,26 +598,26 @@ SECTIONS
 {
   .text  __image_base__ + __section_alignment__  :
   {
-     *(.init)
+    *(.init)
     *(.text)
     *(SORT(.text$*))
     *(.glue_7t)
     *(.glue_7)
-     ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
+    ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
                        LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*));  LONG (0);
-     ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
+    ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
                        LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*));  LONG (0);
-     *(.fini)
+    *(.fini)
     /* ??? Why is .gcc_exc here?  */
-     *(.gcc_exc)
+    *(.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__. */
+    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__ = . ;
@@ -447,7 +704,7 @@ SECTIONS
     /* end is deprecated, don't use it */
     PROVIDE (end = .);
     PROVIDE ( _end = .);
-     __end__ = .;
+    __end__ = .;
   }
   .rsrc BLOCK(__section_alignment__) :
   {
@@ -467,9 +724,9 @@ SECTIONS
     *(.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.  */
+    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) :
   {
@@ -532,207 +789,103 @@ SECTIONS
   }
 }
 ''')
-  script.close()
-  return(ld_script)
+    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
+    # 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
+    # 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 __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
-
-
-## def DistSources(env, node):
-##     env.DistFiles(_get_sources(env, node))
-## 
-## def DistFiles(env, files):
-##     assert isinstance(files, (list, tuple))
-##     DISTFILES = [env.File(fname) for fname in files]
-##     env.AppendUnique(DISTFILES=DISTFILES)
-## 
-## 
-## def make_distdir(target=None, source=None, env=None):
-##     distdir = env.subst('$DISTDIR')
-##     Execute(Delete(distdir))
-##     Execute(Mkdir(distdir))
-##     for fnode in env["DISTFILES"]:
-##         dirname, fname = os.path.split(str(fnode))
-##         if dirname:
-##             distdirname = os.path.join(distdir, dirname)
-##             if not os.path.exists(distdirname):
-##                 Execute(Mkdir(distdirname))
-##         Execute(Copy(os.path.join(distdir, dirname, fname), str(fnode)))
-##     
-## def make_dist(target=None, source=None, env=None):
-##     return Popen([env['TAR'], "-zcf",
-##                   env.subst("${PACKAGE}-${VERSION}.tar.gz"),
-##                   env.subst('$DISTDIR')]).wait()
-## 
-## def make_distcheck(target=None, source=None, env=None):
-##     distdir = env.subst('$DISTDIR')
-##     distcheckinstdir = tempfile.mkdtemp('', env.subst('${PACKAGE}-${VERSION}-instdir-'))
-##     distcheckdestdir = tempfile.mkdtemp('', env.subst('${PACKAGE}-${VERSION}-destdir-'))
-##     instdirs = [os.path.join(distcheckinstdir, d) for d in
-##                 'lib', 'share', 'bin', 'include']
-##     for dir_ in instdirs:
-##         Execute(Mkdir(dir_))
-## 
-##     cmd = env.subst("cd $DISTDIR && scons DESTDIR=%s prefix=%s"
-##                     " && scons check && scons install") %\
-##             (os.path.join(distcheckdestdir, ''), distcheckinstdir)
-##     status = Popen(cmd, shell=True).wait()
-##     if status:
-##         return status
-##     ## Check that inst dirs are empty (to catch cases of $DESTDIR not being honored
-##     for dir_ in instdirs:
-##         if os.listdir(dir_):
-##             raise SCons.Errors.BuildError(target, "%s not empy" % dir_)
-##     ## Check that something inside $DESTDIR was installed
-##     dir_ = os.path.join(distcheckdestdir, distcheckinstdir)
-##     if not os.path.exists(dir_):
-##         raise SCons.Errors.BuildError(target, "%s does not exist" % dir_)
-##     Execute(Delete(distcheckinstdir))
-##     Execute(Delete(distcheckdestdir))
-##     Execute(Delete(distdir))
-## 
-## def InstallWithDestDir(self, dir_, source):
-##     dir_ = '${DESTDIR}' + str(dir_)
-##     return SConsEnvironment.Install(self, dir_, source)
-## 
-## 
-## def InstallAsWithDestDir(self, target, source):
-##     target = '${DESTDIR}' + str(target)
-##     return SConsEnvironment.InstallAs(self, target, source)
-## 
-## def generate(env):
-##     env.EnsureSConsVersion(0, 96, 91)
-## 
-##     opts = Options(['options.cache'], ARGUMENTS)
-##     opts.Add(PathOption('prefix', 'Installation prefix', '/usr/local'))
-##     opts.Add(PathOption('exec_prefix', 'Installation prefix blah blah',
-##                         '$prefix'))
-##     opts.Add(PathOption('libdir',
-##         'Installation prefix for architecture dependent files', '$prefix/lib'))
-##     opts.Add(PathOption('includedir',
-##         'Installation prefix for C header files', '$prefix/include'))
-##     opts.Add(PathOption('datadir',
-##         'Installation prefix for architecture independent files', '$prefix/share'))
-##     opts.Add(PathOption('bindir', 'Installation prefix for programs', '$prefix/bin'))
-##     opts.Add(PathOption('DESTDIR', 'blah blah', None))
-##     opts.Update(env)
-##     opts.Save('options.cache', env)
-##     SConsEnvironment.Help(env, opts.GenerateHelpText(env))
-##     
-##     env.Append(CPPFLAGS=r' -DVERSION=\"$VERSION\"')
-##     env.Append(CCFLAGS=ARGUMENTS.get('CCFLAGS', '-g -O2'))
-## 
-##     env['GNOME_TESTS'] = dict(CheckPython=CheckPython,
-##                               CheckPythonHeaders=CheckPythonHeaders,
-##                               PkgCheckModules=PkgCheckModules)
-## 
-##     SConsEnvironment.DistSources = DistSources
-##     SConsEnvironment.DistFiles = DistFiles
-##     env['DISTDIR'] = "${PACKAGE}-${VERSION}"
-## 
-##     #env.Command(env.Dir("$DISTDIR"), None, make_distdir)
-##     
-##     distdir_alias = env.Alias("distdir", None, make_distdir)
-##     dist_alias = env.Alias("dist", None, make_dist)
-##     env.Depends(dist_alias, distdir_alias)
-##     distcheck_alias = env.Alias("distcheck", None, make_distcheck)
-##     env.Depends(distcheck_alias, distdir_alias)
-##     env.AlwaysBuild(env.Alias('check'))
-## 
-##     #env['TARFLAGS'] ='-c -z'
-##     #env['TARSUFFIX'] = '.tar.gz'
-##     #tar = env.Tar('${PACKAGE}-${VERSION}.tar.gz', "${DISTDIR}")
-##     #env.Depends(tar, distdir_alias)
-##     #print env['DEFAULT_TARGETS']
-## 
-##     #env.Depends(distdir_alias, "${DISTFILES}")
-##     #env.Alias('dist', tar)
-##     env.AlwaysBuild('dist')
-##     env.AlwaysBuild('distdir')
-##     env.AlwaysBuild('distcheck')
-##     env.DistFiles(['SConstruct', 'scons/gnome.py'])
-## 
-##     env['BUILDERS']['EnvSubstFile'] = SCons.Builder.Builder(action=env_subst)
-## 
-##     SConsEnvironment.PythonByteCompile = env.Action(byte_compile_python)
-##     
-##     env.Install = new.instancemethod(InstallWithDestDir, env, env.__class__)
-##     env.InstallAs = new.instancemethod(InstallAsWithDestDir, env, env.__class__)
-## 
-## 
-##  
+    ''' 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