-# 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 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)
+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()
-#
-# 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]
+
+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=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 []
+
+
+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
+ ''' 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
-'''
-
-
-def addToConfig(lines, newline=2):
- ''' utility function: shortcut for appending lines to outfile
- add newline at the end of lines.
- '''
- global config_content
- if lines.strip() != '':
- config_content += lines + '\n'*newline
-
-
-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
+ ''' 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
-#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... ')
+ # if can not compile, define CXX_GLOBAL_CSTD
+ ret = conf.TryLink(check_global_cstd_source, '.cpp')
+ 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
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, '.cpp')
+ 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
*/
{
.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__ = . ;
/* end is deprecated, don't use it */
PROVIDE (end = .);
PROVIDE ( _end = .);
- __end__ = .;
+ __end__ = .;
}
.rsrc BLOCK(__section_alignment__) :
{
*(.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) :
{
}
}
''')
- 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