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('') +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 ..\.. -)