diff -r 546cad3627e2 Lib/tkinter/_fix.py
--- a/Lib/tkinter/_fix.py Thu Dec 05 22:47:19 2013 +0100
+++ b/Lib/tkinter/_fix.py Thu Dec 05 16:21:34 2013 -0600
@@ -48,8 +48,13 @@
prefix = os.path.join(sys.base_prefix,"tcl")
if not os.path.exists(prefix):
- # devdir/../tcltk/lib
- prefix = os.path.join(sys.base_prefix, os.path.pardir, "tcltk", "lib")
+ # devdir/../tcltk-[platform]-py[version]/lib
+ prefix = os.path.join(sys.base_prefix, os.path.pardir)
+ platform = 'x64' if sys.maxsize > 2**32 else 'Win32'
+ py_version = '{}{}'.format(*sys.version_info[:2]) # e.g. '34'
+ prefix = os.path.join(prefix,
+ "tcltk-{}-py{}".format(platform, py_version),
+ "lib")
prefix = os.path.abspath(prefix)
# if this does not exist, no further search is needed
if os.path.exists(prefix):
diff -r 546cad3627e2 PCbuild/_tkinter.vcxproj
--- a/PCbuild/_tkinter.vcxproj Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/_tkinter.vcxproj Thu Dec 05 16:21:34 2013 -0600
@@ -149,90 +149,16 @@
-
+
+
+ X64
+
$(tcltkDir)\include;%(AdditionalIncludeDirectories)
WITH_APPINIT;%(PreprocessorDefinitions)
- $(tcltkLibDebug);%(AdditionalDependencies)
-
-
-
-
- X64
-
-
- $(tcltk64Dir)\include;%(AdditionalIncludeDirectories)
- WITH_APPINIT;%(PreprocessorDefinitions)
-
-
- $(tcltk64LibDebug);%(AdditionalDependencies)
-
-
-
-
- $(tcltkDir)\include;%(AdditionalIncludeDirectories)
- WITH_APPINIT;%(PreprocessorDefinitions)
-
-
- $(tcltkLib);%(AdditionalDependencies)
-
-
-
-
- X64
-
-
- $(tcltk64Dir)\include;%(AdditionalIncludeDirectories)
- WITH_APPINIT;%(PreprocessorDefinitions)
-
-
- $(tcltk64Lib);%(AdditionalDependencies)
-
-
-
-
- $(tcltkDir)\include;%(AdditionalIncludeDirectories)
- WITH_APPINIT;%(PreprocessorDefinitions)
-
-
- $(tcltkLib);%(AdditionalDependencies)
-
-
-
-
- X64
-
-
- $(tcltk64Dir)\include;%(AdditionalIncludeDirectories)
- WITH_APPINIT;%(PreprocessorDefinitions)
-
-
- $(tcltk64Lib);%(AdditionalDependencies)
- MachineX64
-
-
-
-
- $(tcltkDir)\include;%(AdditionalIncludeDirectories)
- WITH_APPINIT;%(PreprocessorDefinitions)
-
-
- $(tcltkLib);%(AdditionalDependencies)
-
-
-
-
- X64
-
-
- $(tcltk64Dir)\include;%(AdditionalIncludeDirectories)
- WITH_APPINIT;%(PreprocessorDefinitions)
-
-
- $(tcltk64Lib);%(AdditionalDependencies)
- MachineX64
+ $(tcltkDir)\lib\tcl$(tclVer).lib;$(tcltkDir)\lib\tk$(tkVer).lib
@@ -244,8 +170,12 @@
{cf7ac3d1-e2df-41d2-bea6-1e2556cdea26}
false
+
+ {F9B75318-C258-4652-BF17-CA0C492B931B}
+ false
+
-
\ No newline at end of file
+
diff -r 546cad3627e2 PCbuild/build_tkinter.py
--- a/PCbuild/build_tkinter.py Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/build_tkinter.py Thu Dec 05 16:21:34 2013 -0600
@@ -7,71 +7,146 @@
import os
import sys
+import getopt
+from buildlib import get_properties
-here = os.path.abspath(os.path.dirname(__file__))
-par = os.path.pardir
+NMAKE = ('nmake /nologo /f %s %s %s')
-TCL = "tcl8.6.1"
-TK = "tk8.6.1"
-TIX = "tix-8.4.3.3"
-
-ROOT = os.path.abspath(os.path.join(here, par, par))
-NMAKE = ('nmake /nologo /f %s %s %s')
+VCVERSION = 'VC10'
def nmake(makefile, command="", **kw):
defines = ' '.join(k+'='+str(v) for k, v in kw.items())
cmd = NMAKE % (makefile, defines, command)
- print("\n\n"+cmd+"\n")
+ print("\n\n"+cmd+"\n", flush=True)
if os.system(cmd) != 0:
raise RuntimeError(cmd)
-def build(platform, clean):
- if platform == "Win32":
- dest = os.path.join(ROOT, "tcltk")
+
+def build(platform, target, debug):
+ # Allow both processor architecture and platform names as valid arguments
+ if platform in ("Win32", "x86"):
machine = "IX86"
- elif platform == "AMD64":
- dest = os.path.join(ROOT, "tcltk64")
+ platform = "Win32"
+ elif platform in ("x64", "AMD64"):
machine = "AMD64"
+ platform = "x64"
else:
- raise ValueError(platform)
+ raise ValueError('unsupported platform: %r' % (platform,))
+
+ if target not in ('build', 'rebuild', 'clean'):
+ raise ValueError("no rule to make target '%s'" % (target,))
+
+ if debug:
+ configuration = 'Debug'
+ else:
+ configuration = 'Release'
+ props = get_properties('tcltk', platform, configuration)
+
+ if target == 'clean':
+ # Nuke the installation directory
+ cmd = 'rmdir /s /q "%s"' % props['tcltkDir']
+ print('\n\n' + cmd, flush=True)
+ if os.path.exists(props['tcltkDir']):
+ os.system(cmd)
+
+ slndir = props['SolutionDir']
+
+ def _install_if_needed(name, inst_dir, makefile, defines):
+ # we should already be in the right folder
+ dll_name = '{}{}.dll'.format(name, props['{}Ver'.format(name)])
+ installed_path = os.path.relpath(os.path.join(inst_dir, dll_name))
+ try:
+ installed_mtime = os.path.getmtime(installed_path)
+ except FileNotFoundError:
+ installed_mtime = None
+
+ build_dir = '{}_{}'.format(configuration, VCVERSION)
+ build_path = os.path.join(build_dir, dll_name)
+
+ built_mtime = os.path.getmtime(build_path)
+
+ if installed_mtime is None or built_mtime > installed_mtime:
+ if name in ('tcl', 'tk'):
+ install_targets = ('install-binaries', 'install-libraries')
+ else: # name == 'tix'
+ install_targets = ('install',)
+ for tget in install_targets:
+ nmake(makefile, tget, **defines)
# TCL
- tcldir = os.path.join(ROOT, TCL)
if 1:
- os.chdir(os.path.join(tcldir, "win"))
- if clean:
- nmake("makefile.vc", "clean")
- nmake("makefile.vc", MACHINE=machine)
- nmake("makefile.vc", "install", INSTALLDIR=dest, MACHINE=machine)
+ os.chdir(os.path.join(slndir, props['tclDir'], "win"))
+ defines = dict(MACHINE=machine, OPTS=('symbols' if debug else ''),
+ INSTALLDIR=os.path.relpath(props['tcltkDir']))
+ if target in ('clean', 'rebuild'):
+ nmake("makefile.vc", "clean", **defines)
+ if target in ('build', 'rebuild'):
+ for tget in ('core', 'shell', 'dlls'):
+ nmake("makefile.vc", tget, **defines)
+
+ dll_install_dir = os.path.join(props['tcltkDir'], 'bin')
+ _install_if_needed('tcl', dll_install_dir, 'makefile.vc', defines)
+
# TK
if 1:
- os.chdir(os.path.join(ROOT, TK, "win"))
- if clean:
- nmake("makefile.vc", "clean", DEBUG=0, TCLDIR=tcldir)
- nmake("makefile.vc", DEBUG=0, MACHINE=machine, TCLDIR=tcldir)
- nmake("makefile.vc", "install", DEBUG=0, INSTALLDIR=dest, MACHINE=machine, TCLDIR=tcldir)
+ os.chdir(os.path.join(slndir, props['tkDir'], "win"))
+ defines = dict(MACHINE=machine, OPTS=('symbols' if debug else ''),
+ INSTALLDIR=os.path.relpath(props['tcltkDir']),
+ TCLDIR=os.path.relpath(props['tclDir']))
+ if target in ('clean', 'rebuild'):
+ nmake("makefile.vc", "clean", **defines)
+ if target in ('build', 'rebuild'):
+ nmake("makefile.vc", "release", **defines)
+
+ dll_install_dir = os.path.join(props['tcltkDir'], 'bin')
+ _install_if_needed('tk', dll_install_dir, 'makefile.vc', defines)
# TIX
if 1:
- # python9.mak is available at http://svn.python.org
- os.chdir(os.path.join(ROOT, TIX, "win"))
- if clean:
- nmake("python.mak", "clean")
- nmake("python.mak", MACHINE=machine, INSTALL_DIR=dest)
- nmake("python.mak", "install", MACHINE=machine, INSTALL_DIR=dest)
+ # python.mak is available when fetched from:
+ # http://svn.python.org/external/projects/tix-8.4.3.3
+ os.chdir(os.path.join(slndir, props['tixDir'], "win"))
+ defines = dict(MACHINE=machine, DEBUG=(1 if debug else 0),
+ INSTALL_DIR=os.path.relpath(props['tcltkDir']),
+ TCL_DIR=os.path.relpath(props['tclDir']),
+ TK_DIR=os.path.relpath(props['tkDir']))
+ if target in ('clean', 'rebuild'):
+ nmake("python.mak", "clean", **defines)
+ if target in ('build', 'rebuild'):
+ nmake("python.mak", "all", **defines)
+
+ tix_dir = props['tixDir'].lstrip(props['externalsDir'])[:-2]
+ tix_dir = tix_dir.replace('-', '')
+ dll_install_dir = os.path.join(props['tcltkDir'], 'lib', tix_dir)
+ _install_if_needed('tix', dll_install_dir, 'python.mak', defines)
+
def main():
- if len(sys.argv) < 2 or sys.argv[1] not in ("Win32", "AMD64"):
- print("%s Win32|AMD64" % sys.argv[0])
- sys.exit(1)
-
- if "-c" in sys.argv:
- clean = True
- else:
- clean = False
-
- build(sys.argv[1], clean)
+ args = sys.argv[1:]
+ opts, args = getopt.getopt(args, 'cdt:', ['debug', 'target='])
+ # default settings are for a release build
+ try:
+ platform = args[0]
+ except IndexError:
+ raise SystemExit("usage: %s Win32|AMD64" % sys.argv[0])
+ # Allow both processor architecture and platform names as valid arguments
+ if platform not in ('Win32', 'x86', 'AMD64', 'x64'):
+ raise SystemExit("%s: unsupported platform '%r'" %
+ (sys.argv[0], platform))
+ debug = False
+ target = 'build'
+ for n, v in opts:
+ if n in ('-t', '--target'):
+ target = v.lower()
+ if target not in ('build', 'rebuild', 'clean'):
+ raise SystemExit("%s: don't know how to make '%s'" %
+ (sys.argv[0], v))
+ elif n in ('-d', '--debug'):
+ debug = True
+ elif n == '-c':
+ target = 'rebuild'
+ build(platform, target, debug)
if __name__ == '__main__':
diff -r 546cad3627e2 PCbuild/buildlib.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PCbuild/buildlib.py Thu Dec 05 16:21:34 2013 -0600
@@ -0,0 +1,510 @@
+"""MSVC property file parsing.
+
+This module reads MSVC property files, retrieving variable values for a given
+project in given configuration on given platform.
+"""
+
+import os
+import re
+import ast
+import winreg
+from html import parser
+
+# Regular exressions for tokenizing an MSBuild conditional expression
+_group = lambda *choices: '(' + '|'.join(choices) + ')'
+_choice = lambda *choices: '(?:' + '|'.join(choices) + ')'
+_ws = r'[ \f\t\r\n]*'
+_string = _group(r"'[^']*'")
+_floatnumber = r'[0-9]+\.[0-9]*'
+_hexadecimal = r'0x[0-9a-fA-F]+'
+_integer = r'[0-9]+'
+_number = _group(_floatnumber, _hexadecimal, _integer)
+_operator = _group(r'[<>]=?', '[!=]=')
+_keywords = _group('and', 'or')
+_special = _group(r'[!()]|\$\(')
+_name = _group(r'[a-zA-Z0-9_]+')
+_token = _choice(_string, _number, _operator, _keywords, _special, _name)
+
+_trailing_slash = re.compile(r'[\\/]\s*$').search
+def _has_trailing_slash(path):
+ return _trailing_slash(path) is not None
+
+# Fixup HTMLParser to handle valid XML (add '_' to NameStartChar)
+parser.starttagopen = re.compile('<[a-zA-Z_]')
+parser.tagfind = re.compile('([a-zA-Z_][-.a-zA-Z0-9:_]*)')
+parser.endtagfind = re.compile('([a-zA-Z_][-.a-zA-Z0-9:_]*)\s*>')
+parser.locatestarttagend = re.compile(
+ r"<[a-zA-Z_][-.a-zA-Z0-9:_]*"
+ r"(?:\s+[a-zA-Z_][-.:a-zA-Z0-9_]*\s*=\s*(['\"])[^\1]*?\1)*"
+ r"\s*")
+class Parser(parser.HTMLParser):
+
+ def __init__(self, platform=None, configuration=None, properties=None):
+ parser.HTMLParser.__init__(self)
+ self.strict = True
+ if properties is None:
+ properties = self._get_msbuild_properties(platform, configuration)
+ self.properties = properties
+
+ def _get_msbuild_properties(self, platform, configuration):
+ props = {}
+ # Initialize th properties with those from the environment
+ import nt
+ for name in nt.environ:
+ if name.isidentifier():
+ props[name] = nt.environ[name]
+ props['Platform'] = platform
+ props['Configuration'] = configuration
+ path = os.path.join(os.environ['ProgramFiles'], 'MSBuild')
+ if 'ProgramFiles(x86)' in os.environ:
+ path32 = os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild')
+ else:
+ path32 = path
+ props['MSBuildExtensionsPath'] = path
+ props['MSBuildExtensionsPath32'] = path32
+ if 'ProgramFiles(x86)' in os.environ:
+ # 64-bit platform
+ if 'ProgramW6432' in os.environ:
+ path64 = os.path.join(os.environ['ProgramW6432'], 'MSBuild')
+ else:
+ path64 = path
+ props['MSBuildExtensionsPath64'] = path64
+ props['MSBuildToolsVersion'] = '2.0'
+ return props
+
+ def _set_msbuild_file(self, path):
+ this_dir, this_file = os.path.split(path)
+ this_name, this_ext = os.path.splitext(this_file)
+ self.properties['MSBuildThisFile'] = this_file
+ self.properties['MSBuildThisFileName'] = this_name
+ self.properties['MSBuildThisFileDirectory'] = this_dir + '\\'
+ self.properties['MSBuildThisFileExtension'] = this_ext
+ self.properties['MSBuildThisFileFullPath'] = path
+
+ def _init_msbuild_tools(self):
+ version = self.properties['MSBuildToolsVersion']
+ key = 'SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\' + version
+ try:
+ hkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key)
+ except WindowsError:
+ return
+ keys, values, timestamp = winreg.QueryInfoKey(hkey)
+ for i in range(values):
+ name, value, typecode = winreg.EnumValue(hkey, i)
+ self.properties[name] = self._expand_properties(value)
+ hkey.Close()
+ self.properties['MSBuildBinPath'] = self.properties['MSBuildToolsPath']
+
+ def _parse(self, project_path):
+ #print('DEBUG: parsing',project_path)
+ with open(project_path, encoding='utf-8') as f:
+ data = f.read()
+ self._set_msbuild_file(project_path)
+ self.filename = project_path
+ self.rawdata = data
+ self.parsing_state = ['#document']
+ self.goahead(1)
+ return self.properties
+
+ def parse(self, project_path):
+ project_dir, project_file = os.path.split(project_path)
+ project_name, project_ext = os.path.splitext(project_file)
+ self.properties['MSBuildProjectFile'] = project_file
+ self.properties['MSBuildProjectName'] = project_name
+ self.properties['MSBuildProjectExtension'] = project_ext
+ self.properties['MSBuildProjectDirectory'] = project_dir + '\\'
+ self.properties['MSBuildProjectFullPath'] = project_path
+ return self._parse(project_path)
+
+ def _call_function(self, cls, member, args):
+ if cls == 'System.IO.Path':
+ if member == 'Combine':
+
+ return os.path.join(*args)
+ elif member == 'GetFullPath':
+ path, = args
+ # abspath() removes any existing trailing slash
+ addsep = _has_trailing_slash(path)
+ path = os.path.abspath(path)
+ if addsep:
+ path += os.path.sep
+ return path
+ elif member == 'GetTempPath':
+ return os.environ['TEMP']
+ elif cls == 'MSBuild':
+ if member == 'Escape':
+ repl = lambda m: '%%%02x' % ord(m.group())
+ string, = args
+ return re.sub("[%$@';?*]", repl, string)
+ elif cls == 'Microsoft.Build.Utilities.ToolLocationHelper':
+ if member == 'GetPathToStandardLibraries':
+ # This function is used for the inproc VisualBasic compiler, so
+ # the value doesn't matter for Python projects. Defined just to
+ # silence warnings.
+ return ''
+ print("WARNING: unsupported member '%s' on class '%s'" % (member, cls))
+ return ''
+
+ # The allowed optional whitespace has been determined via trial and
+ # error with the MSBuild command line.
+ _find_function = re.compile(r'\s*\[\s*([^]]+)\]::\s*([^(]+)').match
+ _find_interesting = re.compile("\$\(|\(\)|[),'`]").search
+ def _expand_function(self, string, warn=False):
+ m = self._find_function(string)
+ if m is None:
+ print("WARNING: instance methods are unsupported")
+ return ''
+ cls, member = m.groups()
+ pos = m.end()
+ end = len(string)
+ asstring = False
+ args = []
+ arg = ''
+ while pos < end:
+ m = self._find_interesting(string, pos)
+ if m:
+ i, epos = m.span()
+ c = string[i]
+ else:
+ epos = end
+ c = None
+ if c == '$':
+ # property reference
+ value, spos, epos = self._find_reference(string, pos)
+ value = self._expand_reference(value, asstring, warn)
+ if asstring:
+ arg += value
+ else:
+ arg = value
+ elif c in ("'", "`"):
+ asstring = not asstring
+ elif c in (',', ')'):
+ args.append(arg)
+ arg = ''
+ elif c == '(':
+ args = []
+ else:
+ assert False, "interesting lied"
+ pos = epos
+ value = self._call_function(cls, member, args)
+ return value
+
+ def _expand_registry(self, string, warn=False):
+ hive, sep, key = string.partition('\\')
+ key, sep, value = key.partition('@')
+ # We know the hive to exist as MSBuild gives an error for invalid
+ # values.
+ hive = getattr(winreg, hive.upper())
+ try:
+ with winreg.OpenKey(hive, key) as hkey:
+ value, typecode = winreg.QueryValueEx(hkey, value)
+ except WindowsError:
+ # It is not an error for the key to be missing
+ if warn:
+ print("WARNING: registry reference '%s' not found" % string)
+ value = ''
+ return value
+
+ def _expand_property(self, string, warn=False):
+ # property names are case-insensitive
+ name = string.lower()
+ for key in self.properties:
+ if key.lower() == name:
+ value = self.properties[key]
+ break
+ else:
+ if warn:
+ print("WARNING: property '%s' not found" % string)
+ value = ''
+ return value
+
+ _registry_ref = re.compile(r"registry:(.*)", re.IGNORECASE).match
+ def _evaluate_property(self, source, warn=False):
+ m = self._registry_ref(source)
+ if m:
+ value = self._expand_registry(m.group(1), warn)
+ elif '(' in source:
+ value = self._expand_function(source, warn)
+ else:
+ value = self._expand_property(source, warn)
+ return value
+
+ def _expand_reference(self, source, asstring=True, warn=False):
+ value = self._evaluate_property(source, warn)
+ if asstring:
+ if isinstance(value, list):
+ value = ';'.join(value)
+ else:
+ value = str(value)
+ return value
+
+ _find_varref = re.compile(r"\$\(([^)]+)\)").search
+ def _find_reference(self, string, start=0):
+ m = self._find_varref(string, start)
+ if m is None:
+ return None
+ spos, epos = m.span()
+ ref = m.group(1)
+ # Property functions contain a closing parenthesis so the
+ # simple matching pattern will fail in those cases.
+ if '(' in ref:
+ # Find the matching ')' for this reference. Note that the
+ # regex has already matched a closing parenthesis.
+ start = spos + 2
+ parens = string.count('(', start, epos)
+ while parens:
+ last = epos
+ epos = string.index(')', last)
+ parens -= 1
+ parens += string.count('(', last, epos)
+ epos += 1
+ ref = string[start:epos-1]
+ return ref, spos, epos
+
+ def _expand_properties(self, string, warn=False):
+ while True:
+ match = self._find_reference(string)
+ if match is None:
+ break
+ value, spos, epos = match
+ value = self._expand_reference(value, warn=warn)
+ string = string[:spos] + value + string[epos:]
+ return string
+
+ _find_token = re.compile(_ws + _token + _ws, re.IGNORECASE).match
+ def _translate(self, source):
+ """Tokenizes an MSBuild conditional expression as an equivalent
+ Python expression."""
+ pos, end = 0, len(source)
+ while pos < end:
+ m = self._find_token(source, pos)
+ if m is None:
+ raise RuntimeError("invalid token" + repr(source[pos:pos+1]))
+ token = m.lastindex
+ value = m.group(token)
+ epos = m.end()
+ if token == 1: # strings
+ value = self._expand_properties(value)
+ elif token == 4: # keywords
+ # Python keywords are lowercase only
+ value = value.lower()
+ elif token == 5: # specials
+ if value == '!': # logical not
+ value = 'not'
+ elif value == '$(': # property reference
+ value, spos, epos = self._find_reference(source, pos)
+ value = 'property("' + value + '")'
+ yield value
+ pos = epos
+
+ def _evaluate_ast(self, node):
+ def _boolean(value):
+ if isinstance(value, str):
+ value = (value.lower() == 'true')
+ return value
+ def _number(value):
+ if isinstance(value, str):
+ if '.' in value:
+ value = float(value)
+ elif 'x' in value or 'X' in value:
+ value = int(value, 16)
+ else:
+ value = int(value, 10)
+ return value
+ def _string(value):
+ if not isinstance(value, str):
+ value = str(value)
+ return value.lower()
+ def _convert(node):
+ if isinstance(node, ast.Str):
+ return node.s
+ elif isinstance(node, ast.Num):
+ return node.n
+ elif isinstance(node, ast.Name):
+ name = node.id.lower()
+ if name == 'true':
+ return True
+ elif name == 'false':
+ return False
+ return node.id
+ elif isinstance(node, ast.BoolOp):
+ if isinstance(node.op, ast.And):
+ for value in node.values:
+ if not _convert(value):
+ return False
+ return True
+ else:
+ for value in node.values:
+ if _convert(value):
+ return True
+ return False
+ elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not):
+ return not _convert(node.operand)
+ elif isinstance(node, ast.Compare):
+ # MSBuild restricts comparisons to just 2 operands
+ op = node.ops[0]
+ left = _convert(node.left)
+ right = _convert(node.comparators[0])
+ if isinstance(op, (ast.Eq, ast.NotEq)):
+ # string or boolean comparison (==, !=)
+ if isinstance(left, bool) or isinstance(right, bool):
+ left = _boolean(left)
+ right = _boolean(right)
+ else:
+ left = _string(left)
+ right = _string(right)
+ if isinstance(op, ast.Eq):
+ return left == right
+ else:
+ return left != right
+ else:
+ # number comparison (<, <=, >=, >)
+ left = _number(left)
+ right = _number(right)
+ if isinstance(op, ast.Lt):
+ return left < right
+ elif isinstance(op, ast.LtE):
+ return left <= right
+ elif isinstance(op, ast.GtE):
+ return left >= right
+ elif isinstance(op, ast.Gt):
+ return left > right
+ elif isinstance(node, ast.Call):
+ func = _convert(node.func).lower()
+ args = map(_convert, node.args)
+ if func == 'exists':
+ return os.path.exists(*args)
+ elif func == 'hastrailingslash':
+ return _has_trailing_slash(*args)
+ elif func == 'property':
+ return self._evaluate_property(*args)
+ raise ValueError('malformed node or string: ' + repr(node))
+ return _convert(node.body)
+
+ def _evaluate(self, cond):
+ """Evaluates a MSBuild conitional expression as a boolean."""
+ # If a conditional expression is not given, it is the same as
+ # evaluating to True.
+ if cond is None:
+ return True
+ # Convert the MSBuild condition to valid a Python expression
+ expr = ' '.join(self._translate(cond))
+ # Escape backslashes ('\') as the the strings are to be parsed
+ expr = expr.replace('\\', '\\\\')
+ node = ast.parse(expr, self.filename, 'eval')
+ return self._evaluate_ast(node)
+
+ def handle_import(self, project, condition=None, label=None):
+ if self._evaluate(condition):
+ project = self._expand_properties(project, warn=True)
+ project = os.path.join(os.path.dirname(self.filename), project)
+ if os.path.exists(project):
+ subparser = Parser(properties=self.properties)
+ subparser._parse(project)
+ # Restore the "current" filename properties
+ self._set_msbuild_file(self.filename)
+ # Ignore the endtag event for this element. There is no need for
+ # an additional parsing state as 'Import' elements cannot have any
+ # child elements per the MSBuild schema.
+ self.element_depth = 1
+
+ def handle_starttag(self, tag, attrs):
+ parsing = self.parsing_state[-1]
+ if parsing == 'propertygroup':
+ # all child elements are property name/value pairs
+ condition = None
+ for name, value in attrs:
+ if name == 'condition':
+ condition = value
+ if self._evaluate(condition):
+ rawtag = self.get_starttag_text()
+ match = parser.tagfind.search(rawtag)
+ self.property_name = match.group(1)
+ self.property_value = []
+ self.handle_data = self.property_value.append
+ self.parsing_state.append('#property')
+ else:
+ self.parsing_state.append('#ignore')
+ self.element_depth = 0
+
+ elif parsing == 'importgroup':
+ # per the MSBuild XML Schema only 'Import' elements are allowed
+ self.handle_import(**dict(attrs))
+
+ elif parsing == 'project':
+ # look for 'Import', 'ImportGroup' and 'PropertyGroup' elements
+ if tag == 'import':
+ self.handle_import(**dict(attrs))
+ else:
+ # process the attributes common to the elements being checked
+ condition = label = None
+ for name, value in attrs:
+ if name == 'condition':
+ condition = value
+ elif name == 'label':
+ label = value
+ if tag == 'importgroup' and (label == 'PropertySheets' and
+ self._evaluate(condition)):
+ parsing = tag
+ elif tag == 'propertygroup' and self._evaluate(condition):
+ parsing = tag
+ else:
+ parsing = '#ignore'
+ self.parsing_state.append(parsing)
+ self.element_depth = 0
+
+ elif parsing == '#document':
+ # look for 'Project' element
+ if tag == 'project':
+ for name, value in attrs:
+ if name == 'toolsversion':
+ self.properties['MSBuildToolsVersion'] = value
+ self._init_msbuild_tools()
+ self.parsing_state.append(tag)
+ self.element_depth = 0
+
+ else:
+ self.element_depth += 1
+
+ def handle_endtag(self, tag):
+ if self.element_depth:
+ self.element_depth -= 1
+ return
+ parsing = self.parsing_state.pop()
+ if parsing == '#property':
+ value = ''.join(self.property_value)
+ value = self._expand_properties(value, warn=False)
+ if ';' in value:
+ value = value.split(';')
+ value = [ v for v in (v.strip() for v in value) if v ]
+ else:
+ value = value.strip()
+ self.properties[self.property_name] = value
+ del self.handle_data, self.property_value, self.property_name
+
+ def handle_charref(self, name):
+ """Convert character references to their character data equivalent."""
+ try:
+ if name[0] in 'xX':
+ c = int(name[1:], 16)
+ else:
+ c = int(name, 10)
+ data = chr(c)
+ except ValueError:
+ data = '' + name + ';'
+ self.handle_data(data)
+
+ entitydefs = {'lt': '<', 'gt': '>', 'apos': "'", 'quot': '"'}
+ def handle_entityref(self, name):
+ """Convert entity references to their character data equivalent."""
+ try:
+ data = self.entitydefs[name]
+ except KeyError:
+ data = '&' + name + ';'
+ self.handle_data(data)
+
+
+def get_properties(project, platform, configuration):
+ p = Parser(platform, configuration)
+ fn = os.path.join(os.path.dirname(__file__), project + '.vcxproj')
+ return p.parse(fn)
diff -r 546cad3627e2 PCbuild/debug.props
--- a/PCbuild/debug.props Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/debug.props Thu Dec 05 16:21:34 2013 -0600
@@ -2,6 +2,7 @@
_d
+ g
$(OutDir)kill_python_d.exe
@@ -20,6 +21,9 @@
$(PyDebugExt)
+
+ $(TclTkDebugExt)
+
$(KillPythonExe)
diff -r 546cad3627e2 PCbuild/pcbuild.sln
--- a/PCbuild/pcbuild.sln Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/pcbuild.sln Thu Dec 05 16:21:34 2013 -0600
@@ -74,6 +74,8 @@
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_freeze_importlib", "_freeze_importlib.vcxproj", "{19C0C13F-47CA-4432-AFF3-799A296A4DDC}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcltk", "tcltk.vcxproj", "{F9B75318-C258-4652-BF17-CA0C492B931B}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_sha3", "_sha3.vcxproj", "{254A0C05-6696-4B08-8CB2-EF7D533AEE01}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_overlapped", "_overlapped.vcxproj", "{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}"
@@ -617,6 +619,22 @@
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.PGUpdate|x64.ActiveCfg = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|Win32.ActiveCfg = Release|Win32
{19C0C13F-47CA-4432-AFF3-799A296A4DDC}.Release|x64.ActiveCfg = Release|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Debug|Win32.Build.0 = Debug|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Debug|x64.ActiveCfg = Debug|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Debug|x64.Build.0 = Debug|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGInstrument|x64.Build.0 = PGInstrument|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.PGUpdate|x64.Build.0 = PGUpdate|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Release|Win32.ActiveCfg = Release|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Release|Win32.Build.0 = Release|Win32
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Release|x64.ActiveCfg = Release|x64
+ {F9B75318-C258-4652-BF17-CA0C492B931B}.Release|x64.Build.0 = Release|x64
{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.Debug|Win32.ActiveCfg = Debug|Win32
{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.Debug|Win32.Build.0 = Debug|Win32
{254A0C05-6696-4B08-8CB2-EF7D533AEE01}.Debug|x64.ActiveCfg = Debug|x64
@@ -665,7 +683,7 @@
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|Win32.Build.0 = Release|Win32
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|x64.ActiveCfg = Release|x64
{EB6E69DD-04BF-4543-9B92-49FAABCEAC2E}.Release|x64.Build.0 = Release|x64
- EndGlobalSection
+ EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
diff -r 546cad3627e2 PCbuild/pyproject.props
--- a/PCbuild/pyproject.props Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/pyproject.props Thu Dec 05 16:21:34 2013 -0600
@@ -5,7 +5,7 @@
$(SolutionDir)
$(SolutionDir)$(PlatformName)-temp-$(Configuration)\$(ProjectName)\
false
-
+
<_ProjectFileVersion>10.0.30319.1
<_PropertySheetDisplayName>amd64
@@ -13,7 +13,8 @@
$(SolutionDir)$(PlatformName)-temp-$(Configuration)\$(ProjectName)\
- python34$(PyDebugExt)
+ 34
+ python$(PyShortVer)$(PyDebugExt)
$(OutDir)python$(PyDebugExt).exe
$(OutDir)kill_python$(PyDebugExt).exe
..\..
@@ -21,12 +22,13 @@
$(externalsDir)\bzip2-1.0.6
$(externalsDir)\xz-5.0.5
$(externalsDir)\openssl-1.0.1e
- $(externalsDir)\tcltk
- $(externalsDir)\tcltk64
- $(tcltkDir)\lib\tcl86t.lib;$(tcltkDir)\lib\tk86t.lib
- $(tcltkDir)\lib\tcl86tg.lib;$(tcltkDir)\lib\tk86tg.lib
- $(tcltk64Dir)\lib\tcl86t.lib;$(tcltk64Dir)\lib\tk86t.lib
- $(tcltk64Dir)\lib\tcl86tg.lib;$(tcltk64Dir)\lib\tk86tg.lib
+ $(externalsDir)\tcl-8.6.1.0
+ 86t$(TclTkDebugExt)
+ $(externalsDir)\tk-8.6.1.0
+ $(tclVer)
+ $(externalsDir)\tix-8.4.3.3
+ 84$(TclTkDebugExt)
+ $(externalsDir)\tcltk-$(Platform)-py$(PyShortVer)
@@ -58,6 +60,9 @@
+
+ $(PyShortVer)
+
$(PyDllName)
@@ -82,23 +87,26 @@
$(opensslDir)
+
+ $(tclDir)
+
+
+ $(tclVer)
+
+
+ $(tkDir)
+
+
+ $(tkVer)
+
+
+ $(tixDir)
+
+
+ $(tixVer)
+
$(tcltkDir)
-
- $(tcltk64Dir)
-
-
- $(tcltkLib)
-
-
- $(tcltkLibDebug)
-
-
- $(tcltk64Lib)
-
-
- $(tcltk64LibDebug)
-
diff -r 546cad3627e2 PCbuild/readme.txt
--- a/PCbuild/readme.txt Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/readme.txt Thu Dec 05 16:21:34 2013 -0600
@@ -215,11 +215,11 @@
Homepage:
http://www.tcl.tk/
- Unlike the other external libraries listed above, Tk must be built
- separately before the _tkinter module can be built. This means that
- a pre-built Tcl/Tk installation is expected in ..\..\tcltk (tcltk64
- for 64-bit) relative to this directory. See "Getting External
- Sources" below for the easiest method to ensure Tcl/Tk is built.
+ Tcl, Tk, and Tix are built by tcltk.vcxproj, which invokes
+ build_tkinter.py, similarly to the way OpenSSL is built. It is
+ possible to clean the Tcl/Tk/Tix builds using build_tkinter.py, but
+ this is not done by the tcltk.vcxproj "clean" target to avoid
+ potentially lengthy rebuilds on the buildbots.
Getting External Sources
@@ -248,26 +248,6 @@
anyway, since that is where the solution is set to look for xz. The
same is true for all other external projects.
-The external(-amd64).bat scripts will also build a debug build of
-Tcl/Tk, but there aren't any equivalent batch files for building release
-versions of Tcl/Tk currently available. If you need to build a release
-version of Tcl/Tk, just take a look at the relevant external(-amd64).bat
-file and find the two nmake lines, then call each one without the
-'DEBUG=1' parameter, i.e.:
-
-The external-amd64.bat file contains this for tcl:
- nmake -f makefile.vc DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 clean all install
-
-So for a release build, you'd call it as:
- nmake -f makefile.vc MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 clean all install
-
-Note that the above command is called from within ..\..\tcl-8.6.1.0\win
-(relative to this directory); don't forget to build Tk as well as Tcl!
-
-This will be cleaned up in the future; http://bugs.python.org/issue15968
-tracks adding a new tcltk.vcxproj file that will build Tcl/Tk and Tix
-the same way the other external projects listed above are built.
-
Building for AMD64
------------------
diff -r 546cad3627e2 PCbuild/release.props
--- a/PCbuild/release.props Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/release.props Thu Dec 05 16:21:34 2013 -0600
@@ -2,6 +2,7 @@
+
<_ProjectFileVersion>10.0.30319.1
@@ -15,5 +16,8 @@
$(PyDebugExt)
+
+ $(TclTkDebugExt)
+
\ No newline at end of file
diff -r 546cad3627e2 PCbuild/rt.bat
--- a/PCbuild/rt.bat Thu Dec 05 22:47:19 2013 +0100
+++ b/PCbuild/rt.bat Thu Dec 05 16:21:34 2013 -0600
@@ -30,13 +30,13 @@
set suffix=
set qmode=
set dashO=
-set tcltk=tcltk
+set tcltk=tcltk-Win32-py34
:CheckOpts
if "%1"=="-O" (set dashO=-O) & shift & goto CheckOpts
if "%1"=="-q" (set qmode=yes) & shift & goto CheckOpts
if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts
-if "%1"=="-x64" (set prefix=amd64) & (set tcltk=tcltk64) & shift & goto CheckOpts
+if "%1"=="-x64" (set prefix=amd64) & (set tcltk=tcltk-x64-py34) & shift & goto CheckOpts
PATH %PATH%;%~dp0..\..\%tcltk%\bin
set exe=%prefix%\python%suffix%
diff -r 546cad3627e2 PCbuild/tcltk.vcxproj
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PCbuild/tcltk.vcxproj Thu Dec 05 16:21:34 2013 -0600
@@ -0,0 +1,140 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ PGInstrument
+ Win32
+
+
+ PGInstrument
+ x64
+
+
+ PGUpdate
+ Win32
+
+
+ PGUpdate
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {F9B75318-C258-4652-BF17-CA0C492B931B}
+ tcltk
+ MakeFileProj
+
+
+
+ Makefile
+ NotSet
+
+
+ Makefile
+ NotSet
+
+
+ Makefile
+ NotSet
+
+
+ Makefile
+ NotSet
+
+
+ Makefile
+ NotSet
+
+
+ Makefile
+ NotSet
+
+
+ Makefile
+ NotSet
+
+
+ Makefile
+ NotSet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "$(PythonExe)" "$(SolutionDir)build_tkinter.py" --debug --target=build $(Platform)
+ "$(PythonExe)" "$(SolutionDir)build_tkinter.py" --debug --target=rebuild $(Platform)
+ echo Run `"$(PythonExe)" "$(SolutionDir)build_tkinter.py" --debug --target=clean $(Platform)` to clean the Tcl/Tk/Tix build.
+
+
+ "$(PythonExe)" "$(SolutionDir)build_tkinter.py" --target=build $(Platform)
+ "$(PythonExe)" "$(SolutionDir)build_tkinter.py" --target=rebuild $(Platform)
+ echo Run `"$(PythonExe)" "$(SolutionDir)build_tkinter.py" --target=clean $(Platform)` to clean the Tcl/Tk/Tix build.
+
+
+
+
+
+ {b11d750f-cd1f-4a96-85ce-e69a5c5259f9}
+ false
+
+
+
+
+
+
diff -r 546cad3627e2 Tools/buildbot/external-amd64.bat
--- a/Tools/buildbot/external-amd64.bat Thu Dec 05 22:47:19 2013 +0100
+++ b/Tools/buildbot/external-amd64.bat Thu Dec 05 16:21:34 2013 -0600
@@ -2,20 +2,3 @@
@rem Assume we start inside the Python source directory
call "Tools\buildbot\external-common.bat"
-call "%VS100COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
-
-if not exist tcltk64\bin\tcl86tg.dll (
- cd tcl-8.6.1.0\win
- nmake -f makefile.vc DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 clean all
- nmake -f makefile.vc DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 install
- cd ..\..
-)
-
-if not exist tcltk64\bin\tk86tg.dll (
- cd tk-8.6.1.0\win
- nmake -f makefile.vc OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.6.1.0 clean
- nmake -f makefile.vc OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.6.1.0 all
- nmake -f makefile.vc OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.6.1.0 install
- cd ..\..
-)
-
diff -r 546cad3627e2 Tools/buildbot/external-common.bat
--- a/Tools/buildbot/external-common.bat Thu Dec 05 22:47:19 2013 +0100
+++ b/Tools/buildbot/external-common.bat Thu Dec 05 16:21:34 2013 -0600
@@ -15,7 +15,7 @@
@rem if exist tk-8.4.18.1 rd /s/q tk-8.4.18.1
@rem if exist db-4.4.20 rd /s/q db-4.4.20
@rem if exist openssl-1.0.1e rd /s/q openssl-1.0.1e
-@rem if exist sqlite-3.7.12 rd /s/q sqlite-3.7.12
+@rem if exist sqlite-3.7.12 rd /s/q sqlite-3.7.12
@rem bzip
if not exist bzip2-1.0.6 (
@@ -29,12 +29,13 @@
svn export http://svn.python.org/projects/external/openssl-1.0.1e
)
-@rem tcl/tk
+@rem tcl/tk/tix
if not exist tcl-8.6.1.0 (
- rd /s/q tcltk tcltk64 tcl-8.5.11.0 tk-8.5.11.0
+ rd /s/q tcltk tcltk64 tcl-8.5.11.0 tk-8.5.11.0 tix-8.4.3.2
svn export http://svn.python.org/projects/external/tcl-8.6.1.0
)
if not exist tk-8.6.1.0 svn export http://svn.python.org/projects/external/tk-8.6.1.0
+if not exist tix-8.4.3.3 svn export http://svn.python.org/projects/external/tix-8.4.3.3
@rem sqlite3
if not exist sqlite-3.8.1 (
diff -r 546cad3627e2 Tools/buildbot/external.bat
--- a/Tools/buildbot/external.bat Thu Dec 05 22:47:19 2013 +0100
+++ b/Tools/buildbot/external.bat Thu Dec 05 16:21:34 2013 -0600
@@ -2,20 +2,3 @@
@rem Assume we start inside the Python source directory
call "Tools\buildbot\external-common.bat"
-call "%VS100COMNTOOLS%\vsvars32.bat"
-
-if not exist tcltk\bin\tcl86tg.dll (
- @rem all and install need to be separate invocations, otherwise nmakehlp is not found on install
- cd tcl-8.6.1.0\win
- nmake -f makefile.vc DEBUG=1 INSTALLDIR=..\..\tcltk clean all
- nmake -f makefile.vc DEBUG=1 INSTALLDIR=..\..\tcltk install
- cd ..\..
-)
-
-if not exist tcltk\bin\tk86tg.dll (
- cd tk-8.6.1.0\win
- nmake -f makefile.vc OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.6.1.0 clean
- nmake -f makefile.vc OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.6.1.0 all
- nmake -f makefile.vc OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.6.1.0 install
- cd ..\..
-)