#
import os, sys, re, shutil, glob
-from SCons.Util import WhereIs
+from SCons.Util import *
def getVerFromConfigure(path):
- " get lyx version from the AC_INIT line of configure.ac "
+ ''' get lyx version from the AC_INIT line of configure.ac,
+ and LYX_DATE from an AC_SUBST line.
+ '''
try:
config = open(os.path.join(path, 'configure.ac'))
except:
return 'x.x.x'
# find a line like follows
# AC_INIT(LyX,1.4.4svn,[lyx-devel@lists.lyx.org],[lyx])
- pat = re.compile('AC_INIT\([^,]+,([^,]+),')
+ 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 pat.match(line):
- (version,) = pat.match(line).groups()
- return version.strip()
- return 'x.x.x'
+ 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):
# 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")
#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 checkCXXGlobalCstd(conf):
- ''' Check the use of std::tolower or tolower '''
+ ''' Checking the use of std::tolower or tolower '''
check_global_cstd_source = '''
#include <cctype>
using std::tolower;
return 0;
}
'''
- conf.Message('Check for the use of global cstd... ')
- ret = conf.TryLink(check_global_cstd_source, '.c')
+ 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
return ('int', 'int *', 'struct timeval *')
-def checkBoostLibraries(conf, libs, lib_paths, inc_paths, version, isDebug):
+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
- version: required boost version
+ 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:
- # direct form: e.g. libboost_iostreams.a
- # ignore isDebug
- if False not in [os.path.isfile(os.path.join(path, 'libboost_%s.a' % lib)) for lib in libs]:
- conf.Result('yes')
- found_lib = True
- lib_path = path
- lib_names = libs
- break
+ 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, 'libboost_%s-*.a' % lib))
+ 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:
- lib_files = filter(lambda x: re.search('libboost_%s-\w+-mt-[^spn]+-%s.a' % (lib, version), x), files)
+ 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:
- lib_files = filter(lambda x: re.search('libboost_%s-\w+-mt-([^dgy]+-)*%s.a' % (lib, version), x), files)
+ 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:
- print 'Warning: Can not find an appropriate boost library in %s.' % path
- lib_files = filter(lambda x: re.search('libboost_%s-[\w-]+%s.a' % (lib, version), x), files)
- if len(lib_files) > 0:
- print 'Use library %s' % 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
- lib_names.append(lib_files[0].split(os.sep)[-1][3:-2])
+ 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):
- file = os.path.join(dir, 'boost', 'version.hpp')
- version_string = '#define BOOST_LIB_VERSION "%s"' % version
- return os.path.isfile(file) and version_string in open(file).read()
+ 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 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 = '''
return LC_MESSAGES;
}
'''
- conf.Message('Check for LC_MESSAGES in locale.h... ')
+ conf.Message('Checking for LC_MESSAGES in locale.h... ')
ret = conf.TryLink(check_LC_MESSAGES, '.c')
conf.Result(ret)
return ret
return 0;
}
'''
- conf.Message('Check if the declaration of iconv needs const... ')
- ret = conf.TryLink(check_iconv_const, '.c')
+ conf.Message('Checking if the declaration of iconv needs const... ')
+ ret = conf.TryLink(check_iconv_const, '.cpp')
conf.Result(ret)
return ret
return 0;
}
'''
- conf.Message('Check the size of wchar_t... ')
+ 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'):
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 = [], types = [], libs = [],
+ headers = [], functions = [], declarations = [], types = [], libs = [],
custom_tests = [], extra_items = []):
''' create a configuration file, with options
config_file: which file to create
('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
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]] = True
+ result[header[1]] = 1
cont += configString('#define %s 1' % header[1], desc = description)
else:
- result[header[1]] = False
+ 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]] = True
+ result[func[1]] = 1
cont += configString('#define %s 1' % func[1], desc = description)
else:
- result[func[1]] = False
+ 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]] = True
+ result[t[1]] = 1
cont += configString('#define %s 1' % t[1], desc = description)
else:
- result[t[1]] = False
+ result[t[1]] = 0
cont += configString('/* #undef %s */' % t[1], desc = description)
# libraries
for lib in libs:
else:
lib_list = lib[0]
# check if any of the lib exists
- result[lib[1]] = False
+ 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]] = True
+ result[lib[1]] = 1
if len(lib) == 3:
result[lib[2]] = ll
cont += configString('#define %s 1' % lib[1], desc = description)
# custom tests
for test in custom_tests:
if test[0]:
- result[test[1]] = True
+ 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]] = False
+ result[test[1]] = 0
if len(test) == 3:
cont += configString('/* #undef %s */' % test[1], desc = test[2])
else:
''' Install lyx.sh '''
postinstall_script = os.path.join(path, 'lyx.sh')
script = open(postinstall_script, 'w')
- script.write('''#!/bin/sh
+ script.write(r'''#!/bin/sh
# Add /usr/share/lyx/fonts to /etc/fonts/local.conf
# if it is not already there.