#!/usr/bin/env python2
import distutils.sysconfig
import getopt
import glob
import os
import platform
import shutil
import subprocess
import stat
import sys
# ScintillaEditPy can only be built against Python 2.x so fail if Python 3.x
assert sys.version_info < (3,0), "sepbuild.py requires Python 2.x"
sys.path.append(os.path.join("..", "ScintillaEdit"))
import WidgetGen
scintillaDirectory = "../.."
scintillaScriptsDirectory = os.path.join(scintillaDirectory, "scripts")
sys.path.append(scintillaScriptsDirectory)
from FileGenerator import GenerateFile
# Decide up front which platform, treat anything other than Windows or OS X as Linux
PLAT_WINDOWS = platform.system() == "Windows"
PLAT_DARWIN = platform.system() == "Darwin"
PLAT_LINUX = not (PLAT_DARWIN or PLAT_WINDOWS)
def IsFileNewer(name1, name2):
""" Returns whether file with name1 is newer than file with name2. Returns 1
if name2 doesn't exist. """
if not os.path.exists(name1):
return 0
if not os.path.exists(name2):
return 1
mod_time1 = os.stat(name1)[stat.ST_MTIME]
mod_time2 = os.stat(name2)[stat.ST_MTIME]
return (mod_time1 > mod_time2)
def textFromRun(args):
proc = subprocess.Popen(args, shell=isinstance(args, str), stdout=subprocess.PIPE)
(stdoutdata, stderrdata) = proc.communicate()
if proc.returncode:
print("Warning - failed to run '" + " ".join(args) + "'")
raise OSError(proc.returncode)
return stdoutdata
def runProgram(args, exitOnFailure):
print(" ".join(args))
retcode = subprocess.call(" ".join(args), shell=True, stderr=subprocess.STDOUT)
if retcode:
print("Failed in " + " ".join(args) + " return code = " + str(retcode))
if exitOnFailure:
sys.exit()
def usage():
print("sepbuild.py [-h|--help][-c|--clean][-u|--underscore-names]")
print("")
print("Generate PySide wappers and build them.")
print("")
print("options:")
print("")
print("-c --clean remove all object and generated files")
print("-b --pyside-base Location of the PySide+Qt4 sandbox to use")
print("-h --help display this text")
print("-d --debug=yes|no force debug build (or non-debug build)")
print("-u --underscore-names use method_names consistent with GTK+ standards")
modifyFunctionElement = """ %s
"""
injectCode = """
%s
"""
injectCheckN = """
if (!cppArg%d) {
PyErr_SetString(PyExc_ValueError, "Null string argument");
return 0;
}"""
def methodSignature(name, v, options):
argTypes = ""
p1Type = WidgetGen.cppAlias(v["Param1Type"])
if p1Type == "int":
p1Type = "sptr_t"
if p1Type:
argTypes = argTypes + p1Type
p2Type = WidgetGen.cppAlias(v["Param2Type"])
if p2Type == "int":
p2Type = "sptr_t"
if p2Type and v["Param2Type"] != "stringresult":
if p1Type:
argTypes = argTypes + ", "
argTypes = argTypes + p2Type
methodName = WidgetGen.normalisedName(name, options, v["FeatureType"])
constDeclarator = " const" if v["FeatureType"] == "get" else ""
return methodName + "(" + argTypes + ")" + constDeclarator
def printTypeSystemFile(f, options):
out = []
for name in f.order:
v = f.features[name]
if v["Category"] != "Deprecated":
feat = v["FeatureType"]
if feat in ["fun", "get", "set"]:
checks = ""
if v["Param1Type"] == "string":
checks = checks + (injectCheckN % 0)
if v["Param2Type"] == "string":
if v["Param1Type"] == "": # Only arg 2 -> treat as first
checks = checks + (injectCheckN % 0)
else:
checks = checks + (injectCheckN % 1)
if checks:
inject = injectCode % checks
out.append(modifyFunctionElement % (methodSignature(name, v, options), inject))
#if v["Param1Type"] == "string":
# out.append("" + name + "\n")
return out
def doubleBackSlashes(s):
# Quote backslashes so qmake does not produce warnings
return s.replace("\\", "\\\\")
class SepBuilder:
def __init__(self):
# Discover configuration parameters
self.ScintillaEditIncludes = [".", "../ScintillaEdit", "../ScintillaEditBase", "../../include"]
if PLAT_WINDOWS:
self.MakeCommand = "nmake"
self.MakeTarget = "release"
else:
self.MakeCommand = "make"
self.MakeTarget = ""
if PLAT_DARWIN:
self.QMakeOptions = "-spec macx-g++"
else:
self.QMakeOptions = ""
# Default to debug build if running in a debug build interpreter
self.DebugBuild = hasattr(sys, 'getobjects')
# Python
self.PyVersion = "%d.%d" % sys.version_info[:2]
self.PyVersionSuffix = distutils.sysconfig.get_config_var("VERSION")
self.PyIncludes = distutils.sysconfig.get_python_inc()
self.PyPrefix = distutils.sysconfig.get_config_var("prefix")
self.PyLibDir = distutils.sysconfig.get_config_var(
("LIBDEST" if sys.platform == 'win32' else "LIBDIR"))
# Scintilla
with open("../../version.txt") as f:
version = f.read()
self.ScintillaVersion = version[0] + '.' + version[1] + '.' + version[2]
# Find out what qmake is called
self.QMakeCommand = "qmake"
if not PLAT_WINDOWS:
# On Unix qmake may not be present but qmake-qt4 may be so check
pathToQMake = textFromRun("which qmake-qt4 || which qmake").rstrip()
self.QMakeCommand = os.path.basename(pathToQMake)
# Qt default location from qmake
self._SetQtIncludeBase(textFromRun(self.QMakeCommand + " -query QT_INSTALL_HEADERS").rstrip())
# PySide default location
# No standard for installing PySide development headers and libs on Windows so
# choose /usr to be like Linux
self._setPySideBase('\\usr' if PLAT_WINDOWS else '/usr')
self.ProInclude = "sepbuild.pri"
self.qtStyleInterface = True
def _setPySideBase(self, base):
self.PySideBase = base
def _try_pkgconfig(var, package, *relpath):
try:
return textFromRun(["pkg-config", "--variable=" + var, package]).rstrip()
except OSError:
return os.path.join(self.PySideBase, *relpath)
self.PySideTypeSystem = _try_pkgconfig("typesystemdir", "pyside",
"share", "PySide", "typesystems")
self.PySideIncludeBase = _try_pkgconfig("includedir", "pyside",
"include", "PySide")
self.ShibokenIncludeBase = _try_pkgconfig("includedir", "shiboken",
"include", "shiboken")
self.PySideIncludes = [
self.ShibokenIncludeBase,
self.PySideIncludeBase,
os.path.join(self.PySideIncludeBase, "QtCore"),
os.path.join(self.PySideIncludeBase, "QtGui")]
self.PySideLibDir = _try_pkgconfig("libdir", "pyside", "lib")
self.ShibokenLibDir = _try_pkgconfig("libdir", "shiboken", "lib")
self.AllIncludes = os.pathsep.join(self.QtIncludes + self.ScintillaEditIncludes + self.PySideIncludes)
self.ShibokenGenerator = "shiboken"
# Is this still needed? It doesn't work with latest shiboken sources
#if PLAT_DARWIN:
# # On OS X, can not automatically find Shiboken dylib so provide a full path
# self.ShibokenGenerator = os.path.join(self.PySideLibDir, "generatorrunner", "shiboken")
def generateAPI(self, args):
os.chdir(os.path.join("..", "ScintillaEdit"))
if not self.qtStyleInterface:
args.insert(0, '--underscore-names')
WidgetGen.main(args)
f = WidgetGen.readInterface(False)
os.chdir(os.path.join("..", "ScintillaEditPy"))
options = {"qtStyle": self.qtStyleInterface}
GenerateFile("typesystem_ScintillaEdit.xml.template", "typesystem_ScintillaEdit.xml",
"