gh-112984 Update Windows build and installer for free-threaded builds (GH-113129)

This commit is contained in:
Steve Dower 2024-01-17 21:52:23 +00:00 committed by GitHub
parent 78fcde039a
commit f56d132deb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
76 changed files with 1437 additions and 245 deletions

View File

@ -32,6 +32,8 @@ jobs:
strategy: strategy:
matrix: matrix:
type: [x86, x64, arm64] type: [x86, x64, arm64]
env:
IncludeFreethreaded: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Build CPython installer - name: Build CPython installer

View File

@ -20,7 +20,7 @@ jobs:
- name: Display build info - name: Display build info
run: .\python.bat -m test.pythoninfo run: .\python.bat -m test.pythoninfo
- name: Tests - name: Tests
run: .\PCbuild\rt.bat -p Win32 -d -q --fast-ci run: .\PCbuild\rt.bat -p Win32 -d -q --fast-ci ${{ inputs.free-threading && '--disable-gil' || '' }}
build_win_amd64: build_win_amd64:
name: 'build and test (x64)' name: 'build and test (x64)'
@ -37,7 +37,7 @@ jobs:
- name: Display build info - name: Display build info
run: .\python.bat -m test.pythoninfo run: .\python.bat -m test.pythoninfo
- name: Tests - name: Tests
run: .\PCbuild\rt.bat -p x64 -d -q --fast-ci run: .\PCbuild\rt.bat -p x64 -d -q --fast-ci ${{ inputs.free-threading && '--disable-gil' || '' }}
build_win_arm64: build_win_arm64:
name: 'build (arm64)' name: 'build (arm64)'

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

View File

@ -307,6 +307,46 @@ settings and replace any that have been removed or modified.
"Uninstall" will remove Python entirely, with the exception of the "Uninstall" will remove Python entirely, with the exception of the
:ref:`launcher`, which has its own entry in Programs and Features. :ref:`launcher`, which has its own entry in Programs and Features.
.. _install-freethreaded-windows:
Installing Free-threaded Binaries
---------------------------------
.. versionadded:: 3.13 (Experimental)
.. note::
Everything described in this section is considered experimental,
and should be expected to change in future releases.
To install pre-built binaries with free-threading enabled (see :pep:`703`), you
should select "Customize installation". The second page of options includes the
"Download free-threaded binaries" checkbox.
.. image:: win_install_freethreaded.png
Selecting this option will download and install additional binaries to the same
location as the main Python install. The main executable is called
``python3.13t.exe``, and other binaries either receive a ``t`` suffix or a full
ABI suffix. Python source files and bundled third-party dependencies are shared
with the main install.
The free-threaded version is registered as a regular Python install with the
tag ``3.13t`` (with a ``-32`` or ``-arm64`` suffix as normal for those
platforms). This allows tools to discover it, and for the :ref:`launcher` to
support ``py.exe -3.13t``. Note that the launcher will interpret ``py.exe -3``
(or a ``python3`` shebang) as "the latest 3.x install", which will prefer the
free-threaded binaries over the regular ones, while ``py.exe -3.13`` will not.
If you use the short style of option, you may prefer to not install the
free-threaded binaries at this time.
To specify the install option at the command line, use
``Include_freethreaded=1``. See :ref:`install-layout-option` for instructions on
pre-emptively downloading the additional binaries for offline install. The
options to include debug symbols and binaries also apply to the free-threaded
builds.
Free-threaded binaries are also available :ref:`on nuget.org <windows-nuget>`.
.. _windows-store: .. _windows-store:
@ -450,9 +490,29 @@ automatically use the headers and import libraries in your build.
The package information pages on nuget.org are The package information pages on nuget.org are
`www.nuget.org/packages/python <https://www.nuget.org/packages/python>`_ `www.nuget.org/packages/python <https://www.nuget.org/packages/python>`_
for the 64-bit version and `www.nuget.org/packages/pythonx86 for the 64-bit version, `www.nuget.org/packages/pythonx86
<https://www.nuget.org/packages/pythonx86>`_ for the 32-bit version. <https://www.nuget.org/packages/pythonx86>`_ for the 32-bit version, and
`www.nuget.org/packages/pythonarm64
<https://www.nuget.org/packages/pythonarm64>`_ for the ARM64 version
Free-threaded packages
----------------------
.. versionadded:: 3.13 (Experimental)
.. note::
Everything described in this section is considered experimental,
and should be expected to change in future releases.
Packages containing free-threaded binaries are named
`python-freethreaded <https://www.nuget.org/packages/python-freethreaded>`_
for the 64-bit version, `pythonx86-freethreaded
<https://www.nuget.org/packages/pythonx86-freethreaded>`_ for the 32-bit
version, and `pythonarm64-freethreaded
<https://www.nuget.org/packages/pythonarm64-freethreaded>`_ for the ARM64
version. These packages contain both the ``python3.13t.exe`` and
``python.exe`` entry points, both of which run free threaded.
.. _windows-embeddable: .. _windows-embeddable:

View File

@ -141,7 +141,7 @@ class LoaderTest(unittest.TestCase):
def test_load_dll_with_flags(self): def test_load_dll_with_flags(self):
_sqlite3 = import_helper.import_module("_sqlite3") _sqlite3 = import_helper.import_module("_sqlite3")
src = _sqlite3.__file__ src = _sqlite3.__file__
if src.lower().endswith("_d.pyd"): if src.partition(".")[0].lower().endswith("_d"):
ext = "_d.dll" ext = "_d.dll"
else: else:
ext = ".dll" ext = ".dll"

View File

@ -19,8 +19,10 @@ import winreg
PY_EXE = "py.exe" PY_EXE = "py.exe"
DEBUG_BUILD = False
if sys.executable.casefold().endswith("_d.exe".casefold()): if sys.executable.casefold().endswith("_d.exe".casefold()):
PY_EXE = "py_d.exe" PY_EXE = "py_d.exe"
DEBUG_BUILD = True
# Registry data to create. On removal, everything beneath top-level names will # Registry data to create. On removal, everything beneath top-level names will
# be deleted. # be deleted.
@ -232,7 +234,7 @@ class RunPyMixin:
p.stdin.close() p.stdin.close()
p.wait(10) p.wait(10)
out = p.stdout.read().decode("utf-8", "replace") out = p.stdout.read().decode("utf-8", "replace")
err = p.stderr.read().decode("ascii", "replace") err = p.stderr.read().decode("ascii", "replace").replace("\uFFFD", "?")
if p.returncode != expect_returncode and support.verbose and not allow_fail: if p.returncode != expect_returncode and support.verbose and not allow_fail:
print("++ COMMAND ++") print("++ COMMAND ++")
print([self.py_exe, *args]) print([self.py_exe, *args])
@ -273,7 +275,7 @@ class RunPyMixin:
def fake_venv(self): def fake_venv(self):
venv = Path.cwd() / "Scripts" venv = Path.cwd() / "Scripts"
venv.mkdir(exist_ok=True, parents=True) venv.mkdir(exist_ok=True, parents=True)
venv_exe = (venv / Path(sys.executable).name) venv_exe = (venv / ("python_d.exe" if DEBUG_BUILD else "python.exe"))
venv_exe.touch() venv_exe.touch()
try: try:
yield venv_exe, {"VIRTUAL_ENV": str(venv.parent)} yield venv_exe, {"VIRTUAL_ENV": str(venv.parent)}
@ -521,6 +523,9 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
self.assertEqual(str(venv_exe), m.group(1)) self.assertEqual(str(venv_exe), m.group(1))
break break
else: else:
if support.verbose:
print(data["stdout"])
print(data["stderr"])
self.fail("did not find active venv path") self.fail("did not find active venv path")
data = self.run_py(["-0"], env=env) data = self.run_py(["-0"], env=env)
@ -616,25 +621,29 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
self.assertEqual("True", data["SearchInfo.oldStyleTag"]) self.assertEqual("True", data["SearchInfo.oldStyleTag"])
def test_search_path(self): def test_search_path(self):
stem = Path(sys.executable).stem exe = Path("arbitrary-exe-name.exe").absolute()
exe.touch()
self.addCleanup(exe.unlink)
with self.py_ini(TEST_PY_DEFAULTS): with self.py_ini(TEST_PY_DEFAULTS):
with self.script(f"#! /usr/bin/env {stem} -prearg") as script: with self.script(f"#! /usr/bin/env {exe.stem} -prearg") as script:
data = self.run_py( data = self.run_py(
[script, "-postarg"], [script, "-postarg"],
env={"PATH": f"{Path(sys.executable).parent};{os.getenv('PATH')}"}, env={"PATH": f"{exe.parent};{os.getenv('PATH')}"},
) )
self.assertEqual(f"{sys.executable} -prearg {script} -postarg", data["stdout"].strip()) self.assertEqual(f"{exe} -prearg {script} -postarg", data["stdout"].strip())
def test_search_path_exe(self): def test_search_path_exe(self):
# Leave the .exe on the name to ensure we don't add it a second time # Leave the .exe on the name to ensure we don't add it a second time
name = Path(sys.executable).name exe = Path("arbitrary-exe-name.exe").absolute()
exe.touch()
self.addCleanup(exe.unlink)
with self.py_ini(TEST_PY_DEFAULTS): with self.py_ini(TEST_PY_DEFAULTS):
with self.script(f"#! /usr/bin/env {name} -prearg") as script: with self.script(f"#! /usr/bin/env {exe.name} -prearg") as script:
data = self.run_py( data = self.run_py(
[script, "-postarg"], [script, "-postarg"],
env={"PATH": f"{Path(sys.executable).parent};{os.getenv('PATH')}"}, env={"PATH": f"{exe.parent};{os.getenv('PATH')}"},
) )
self.assertEqual(f"{sys.executable} -prearg {script} -postarg", data["stdout"].strip()) self.assertEqual(f"{exe} -prearg {script} -postarg", data["stdout"].strip())
def test_recursive_search_path(self): def test_recursive_search_path(self):
stem = self.get_py_exe().stem stem = self.get_py_exe().stem
@ -727,15 +736,18 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
data = self.run_py([script], expect_returncode=103) data = self.run_py([script], expect_returncode=103)
with self.fake_venv() as (venv_exe, env): with self.fake_venv() as (venv_exe, env):
# Put a real Python (ourselves) on PATH as a distraction. # Put a "normal" Python on PATH as a distraction.
# The active VIRTUAL_ENV should be preferred when the name isn't an # The active VIRTUAL_ENV should be preferred when the name isn't an
# exact match. # exact match.
env["PATH"] = f"{Path(sys.executable).parent};{os.environ['PATH']}" exe = Path(Path(venv_exe).name).absolute()
exe.touch()
self.addCleanup(exe.unlink)
env["PATH"] = f"{exe.parent};{os.environ['PATH']}"
with self.script(f'#! /usr/bin/env {stem} arg1') as script: with self.script(f'#! /usr/bin/env {stem} arg1') as script:
data = self.run_py([script], env=env) data = self.run_py([script], env=env)
self.assertEqual(data["stdout"].strip(), f"{venv_exe} arg1 {script}") self.assertEqual(data["stdout"].strip(), f"{venv_exe} arg1 {script}")
with self.script(f'#! /usr/bin/env {Path(sys.executable).stem} arg1') as script: with self.script(f'#! /usr/bin/env {exe.stem} arg1') as script:
data = self.run_py([script], env=env) data = self.run_py([script], env=env)
self.assertEqual(data["stdout"].strip(), f"{sys.executable} arg1 {script}") self.assertEqual(data["stdout"].strip(), f"{exe} arg1 {script}")

View File

@ -845,6 +845,8 @@ class ProgramsTestCase(BaseTestCase):
test_args.append('-x64') # 64-bit build test_args.append('-x64') # 64-bit build
if not support.Py_DEBUG: if not support.Py_DEBUG:
test_args.append('+d') # Release build, use python.exe test_args.append('+d') # Release build, use python.exe
if sysconfig.get_config_var("Py_GIL_DISABLED"):
test_args.append('--disable-gil')
self.run_batch(script, *test_args, *self.tests) self.run_batch(script, *test_args, *self.tests)
@unittest.skipUnless(sys.platform == 'win32', 'Windows only') @unittest.skipUnless(sys.platform == 'win32', 'Windows only')
@ -862,6 +864,8 @@ class ProgramsTestCase(BaseTestCase):
rt_args.append('-x64') # 64-bit build rt_args.append('-x64') # 64-bit build
if support.Py_DEBUG: if support.Py_DEBUG:
rt_args.append('-d') # Debug build, use python_d.exe rt_args.append('-d') # Debug build, use python_d.exe
if sysconfig.get_config_var("Py_GIL_DISABLED"):
rt_args.append('--disable-gil')
self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests) self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests)

View File

@ -223,8 +223,14 @@ class BasicTest(BaseTest):
def test_upgrade_dependencies(self): def test_upgrade_dependencies(self):
builder = venv.EnvBuilder() builder = venv.EnvBuilder()
bin_path = 'Scripts' if sys.platform == 'win32' else 'bin' bin_path = 'bin'
python_exe = os.path.split(sys.executable)[1] python_exe = os.path.split(sys.executable)[1]
if sys.platform == 'win32':
bin_path = 'Scripts'
if os.path.normcase(os.path.splitext(python_exe)[0]).endswith('_d'):
python_exe = 'python_d.exe'
else:
python_exe = 'python.exe'
with tempfile.TemporaryDirectory() as fake_env_dir: with tempfile.TemporaryDirectory() as fake_env_dir:
expect_exe = os.path.normcase( expect_exe = os.path.normcase(
os.path.join(fake_env_dir, bin_path, python_exe) os.path.join(fake_env_dir, bin_path, python_exe)
@ -283,7 +289,9 @@ class BasicTest(BaseTest):
# build environment # build environment
('is_python_build()', str(sysconfig.is_python_build())), ('is_python_build()', str(sysconfig.is_python_build())),
('get_makefile_filename()', sysconfig.get_makefile_filename()), ('get_makefile_filename()', sysconfig.get_makefile_filename()),
('get_config_h_filename()', sysconfig.get_config_h_filename())): ('get_config_h_filename()', sysconfig.get_config_h_filename()),
('get_config_var("Py_GIL_DISABLED")',
str(sysconfig.get_config_var("Py_GIL_DISABLED")))):
with self.subTest(call): with self.subTest(call):
cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
out, err = check_output(cmd, encoding='utf-8') out, err = check_output(cmd, encoding='utf-8')
@ -315,7 +323,9 @@ class BasicTest(BaseTest):
# build environment # build environment
('is_python_build()', str(sysconfig.is_python_build())), ('is_python_build()', str(sysconfig.is_python_build())),
('get_makefile_filename()', sysconfig.get_makefile_filename()), ('get_makefile_filename()', sysconfig.get_makefile_filename()),
('get_config_h_filename()', sysconfig.get_config_h_filename())): ('get_config_h_filename()', sysconfig.get_config_h_filename()),
('get_config_var("Py_GIL_DISABLED")',
str(sysconfig.get_config_var("Py_GIL_DISABLED")))):
with self.subTest(call): with self.subTest(call):
cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
out, err = check_output(cmd, encoding='utf-8') out, err = check_output(cmd, encoding='utf-8')

View File

@ -139,6 +139,11 @@ class EnvBuilder:
'check that your PATH environment variable is ' 'check that your PATH environment variable is '
'correctly set.') 'correctly set.')
dirname, exename = os.path.split(os.path.abspath(executable)) dirname, exename = os.path.split(os.path.abspath(executable))
if sys.platform == 'win32':
# Always create the simplest name in the venv. It will either be a
# link back to executable, or a copy of the appropriate launcher
_d = '_d' if os.path.splitext(exename)[0].endswith('_d') else ''
exename = f'python{_d}.exe'
context.executable = executable context.executable = executable
context.python_dir = dirname context.python_dir = dirname
context.python_exe = exename context.python_exe = exename
@ -222,67 +227,26 @@ class EnvBuilder:
args = ' '.join(args) args = ' '.join(args)
f.write(f'command = {sys.executable} -m venv {args}\n') f.write(f'command = {sys.executable} -m venv {args}\n')
if os.name != 'nt': def symlink_or_copy(self, src, dst, relative_symlinks_ok=False):
def symlink_or_copy(self, src, dst, relative_symlinks_ok=False): """
""" Try symlinking a file, and if that fails, fall back to copying.
Try symlinking a file, and if that fails, fall back to copying. (Unused on Windows, because we can't just copy a failed symlink file: we
""" switch to a different set of files instead.)
force_copy = not self.symlinks """
if not force_copy: assert os.name != 'nt'
try: force_copy = not self.symlinks
if not os.path.islink(dst): # can't link to itself! if not force_copy:
if relative_symlinks_ok: try:
assert os.path.dirname(src) == os.path.dirname(dst) if not os.path.islink(dst): # can't link to itself!
os.symlink(os.path.basename(src), dst)
else:
os.symlink(src, dst)
except Exception: # may need to use a more specific exception
logger.warning('Unable to symlink %r to %r', src, dst)
force_copy = True
if force_copy:
shutil.copyfile(src, dst)
else:
def symlink_or_copy(self, src, dst, relative_symlinks_ok=False):
"""
Try symlinking a file, and if that fails, fall back to copying.
"""
bad_src = os.path.lexists(src) and not os.path.exists(src)
if self.symlinks and not bad_src and not os.path.islink(dst):
try:
if relative_symlinks_ok: if relative_symlinks_ok:
assert os.path.dirname(src) == os.path.dirname(dst) assert os.path.dirname(src) == os.path.dirname(dst)
os.symlink(os.path.basename(src), dst) os.symlink(os.path.basename(src), dst)
else: else:
os.symlink(src, dst) os.symlink(src, dst)
return except Exception: # may need to use a more specific exception
except Exception: # may need to use a more specific exception logger.warning('Unable to symlink %r to %r', src, dst)
logger.warning('Unable to symlink %r to %r', src, dst) force_copy = True
if force_copy:
# On Windows, we rewrite symlinks to our base python.exe into
# copies of venvlauncher.exe
basename, ext = os.path.splitext(os.path.basename(src))
srcfn = os.path.join(os.path.dirname(__file__),
"scripts",
"nt",
basename + ext)
# Builds or venv's from builds need to remap source file
# locations, as we do not put them into Lib/venv/scripts
if sysconfig.is_python_build() or not os.path.isfile(srcfn):
if basename.endswith('_d'):
ext = '_d' + ext
basename = basename[:-2]
if basename == 'python':
basename = 'venvlauncher'
elif basename == 'pythonw':
basename = 'venvwlauncher'
src = os.path.join(os.path.dirname(src), basename + ext)
else:
src = srcfn
if not os.path.exists(src):
if not bad_src:
logger.warning('Unable to copy %r', src)
return
shutil.copyfile(src, dst) shutil.copyfile(src, dst)
def create_git_ignore_file(self, context): def create_git_ignore_file(self, context):
@ -298,22 +262,23 @@ class EnvBuilder:
'see https://docs.python.org/3/library/venv.html\n') 'see https://docs.python.org/3/library/venv.html\n')
file.write('*\n') file.write('*\n')
def setup_python(self, context): if os.name != 'nt':
""" def setup_python(self, context):
Set up a Python executable in the environment. """
Set up a Python executable in the environment.
:param context: The information for the environment creation request :param context: The information for the environment creation request
being processed. being processed.
""" """
binpath = context.bin_path binpath = context.bin_path
path = context.env_exe path = context.env_exe
copier = self.symlink_or_copy copier = self.symlink_or_copy
dirname = context.python_dir dirname = context.python_dir
if os.name != 'nt':
copier(context.executable, path) copier(context.executable, path)
if not os.path.islink(path): if not os.path.islink(path):
os.chmod(path, 0o755) os.chmod(path, 0o755)
for suffix in ('python', 'python3', f'python3.{sys.version_info[1]}'): for suffix in ('python', 'python3',
f'python3.{sys.version_info[1]}'):
path = os.path.join(binpath, suffix) path = os.path.join(binpath, suffix)
if not os.path.exists(path): if not os.path.exists(path):
# Issue 18807: make copies if # Issue 18807: make copies if
@ -321,30 +286,105 @@ class EnvBuilder:
copier(context.env_exe, path, relative_symlinks_ok=True) copier(context.env_exe, path, relative_symlinks_ok=True)
if not os.path.islink(path): if not os.path.islink(path):
os.chmod(path, 0o755) os.chmod(path, 0o755)
else:
if self.symlinks:
# For symlinking, we need a complete copy of the root directory
# If symlinks fail, you'll get unnecessary copies of files, but
# we assume that if you've opted into symlinks on Windows then
# you know what you're doing.
suffixes = [
f for f in os.listdir(dirname) if
os.path.normcase(os.path.splitext(f)[1]) in ('.exe', '.dll')
]
if sysconfig.is_python_build():
suffixes = [
f for f in suffixes if
os.path.normcase(f).startswith(('python', 'vcruntime'))
]
else:
suffixes = {'python.exe', 'python_d.exe', 'pythonw.exe', 'pythonw_d.exe'}
base_exe = os.path.basename(context.env_exe)
suffixes.add(base_exe)
for suffix in suffixes: else:
src = os.path.join(dirname, suffix) def setup_python(self, context):
if os.path.lexists(src): """
copier(src, os.path.join(binpath, suffix)) Set up a Python executable in the environment.
:param context: The information for the environment creation request
being processed.
"""
binpath = context.bin_path
dirname = context.python_dir
exename = os.path.basename(context.env_exe)
exe_stem = os.path.splitext(exename)[0]
exe_d = '_d' if os.path.normcase(exe_stem).endswith('_d') else ''
if sysconfig.is_python_build():
scripts = dirname
else:
scripts = os.path.join(os.path.dirname(__file__),
'scripts', 'nt')
if not sysconfig.get_config_var("Py_GIL_DISABLED"):
python_exe = os.path.join(dirname, f'python{exe_d}.exe')
pythonw_exe = os.path.join(dirname, f'pythonw{exe_d}.exe')
link_sources = {
'python.exe': python_exe,
f'python{exe_d}.exe': python_exe,
'pythonw.exe': pythonw_exe,
f'pythonw{exe_d}.exe': pythonw_exe,
}
python_exe = os.path.join(scripts, f'venvlauncher{exe_d}.exe')
pythonw_exe = os.path.join(scripts, f'venvwlauncher{exe_d}.exe')
copy_sources = {
'python.exe': python_exe,
f'python{exe_d}.exe': python_exe,
'pythonw.exe': pythonw_exe,
f'pythonw{exe_d}.exe': pythonw_exe,
}
else:
exe_t = f'3.{sys.version_info[1]}t'
python_exe = os.path.join(dirname, f'python{exe_t}{exe_d}.exe')
pythonw_exe = os.path.join(dirname, f'pythonw{exe_t}{exe_d}.exe')
link_sources = {
'python.exe': python_exe,
f'python{exe_d}.exe': python_exe,
f'python{exe_t}.exe': python_exe,
f'python{exe_t}{exe_d}.exe': python_exe,
'pythonw.exe': pythonw_exe,
f'pythonw{exe_d}.exe': pythonw_exe,
f'pythonw{exe_t}.exe': pythonw_exe,
f'pythonw{exe_t}{exe_d}.exe': pythonw_exe,
}
python_exe = os.path.join(scripts, f'venvlaunchert{exe_d}.exe')
pythonw_exe = os.path.join(scripts, f'venvwlaunchert{exe_d}.exe')
copy_sources = {
'python.exe': python_exe,
f'python{exe_d}.exe': python_exe,
f'python{exe_t}.exe': python_exe,
f'python{exe_t}{exe_d}.exe': python_exe,
'pythonw.exe': pythonw_exe,
f'pythonw{exe_d}.exe': pythonw_exe,
f'pythonw{exe_t}.exe': pythonw_exe,
f'pythonw{exe_t}{exe_d}.exe': pythonw_exe,
}
do_copies = True
if self.symlinks:
do_copies = False
# For symlinking, we need all the DLLs to be available alongside
# the executables.
link_sources.update({
f: os.path.join(dirname, f) for f in os.listdir(dirname)
if os.path.normcase(f).startswith(('python', 'vcruntime'))
and os.path.normcase(os.path.splitext(f)[1]) == '.dll'
})
to_unlink = []
for dest, src in link_sources.items():
dest = os.path.join(binpath, dest)
try:
os.symlink(src, dest)
to_unlink.append(dest)
except OSError:
logger.warning('Unable to symlink %r to %r', src, dst)
do_copies = True
for f in to_unlink:
try:
os.unlink(f)
except OSError:
logger.warning('Failed to clean up symlink %r',
f)
logger.warning('Retrying with copies')
break
if do_copies:
for dest, src in copy_sources.items():
dest = os.path.join(binpath, dest)
try:
shutil.copy2(src, dest)
except OSError:
logger.warning('Unable to copy %r to %r', src, dest)
if sysconfig.is_python_build(): if sysconfig.is_python_build():
# copy init.tcl # copy init.tcl
@ -437,6 +477,14 @@ class EnvBuilder:
""" """
binpath = context.bin_path binpath = context.bin_path
plen = len(path) plen = len(path)
if os.name == 'nt':
def skip_file(f):
f = os.path.normcase(f)
return (f.startswith(('python', 'venv'))
and f.endswith(('.exe', '.pdb')))
else:
def skip_file(f):
return False
for root, dirs, files in os.walk(path): for root, dirs, files in os.walk(path):
if root == path: # at top-level, remove irrelevant dirs if root == path: # at top-level, remove irrelevant dirs
for d in dirs[:]: for d in dirs[:]:
@ -444,8 +492,7 @@ class EnvBuilder:
dirs.remove(d) dirs.remove(d)
continue # ignore files in top level continue # ignore files in top level
for f in files: for f in files:
if (os.name == 'nt' and f.startswith('python') if skip_file(f):
and f.endswith(('.exe', '.pdb'))):
continue continue
srcfile = os.path.join(root, f) srcfile = os.path.join(root, f)
suffix = root[plen:].split(os.sep)[2:] suffix = root[plen:].split(os.sep)[2:]
@ -456,20 +503,25 @@ class EnvBuilder:
if not os.path.exists(dstdir): if not os.path.exists(dstdir):
os.makedirs(dstdir) os.makedirs(dstdir)
dstfile = os.path.join(dstdir, f) dstfile = os.path.join(dstdir, f)
if os.name == 'nt' and srcfile.endswith(('.exe', '.pdb')):
shutil.copy2(srcfile, dstfile)
continue
with open(srcfile, 'rb') as f: with open(srcfile, 'rb') as f:
data = f.read() data = f.read()
if not srcfile.endswith(('.exe', '.pdb')): try:
try: new_data = (
data = data.decode('utf-8') self.replace_variables(data.decode('utf-8'), context)
data = self.replace_variables(data, context) .encode('utf-8')
data = data.encode('utf-8') )
except UnicodeError as e: except UnicodeError as e:
data = None logger.warning('unable to copy script %r, '
logger.warning('unable to copy script %r, ' 'may be binary: %s', srcfile, e)
'may be binary: %s', srcfile, e) continue
if data is not None: if new_data == data:
shutil.copy2(srcfile, dstfile)
else:
with open(dstfile, 'wb') as f: with open(dstfile, 'wb') as f:
f.write(data) f.write(new_data)
shutil.copymode(srcfile, dstfile) shutil.copymode(srcfile, dstfile)
def upgrade_dependencies(self, context): def upgrade_dependencies(self, context):

View File

@ -0,0 +1 @@
Adds free-threaded binaries to Windows installer as an optional component.

View File

@ -41,7 +41,7 @@ TCLTK_FILES_ONLY = FileNameSet("turtle.py")
VENV_DIRS_ONLY = FileNameSet("venv", "ensurepip") VENV_DIRS_ONLY = FileNameSet("venv", "ensurepip")
EXCLUDE_FROM_PYDS = FileStemSet("python*", "pyshellext", "vcruntime*") EXCLUDE_FROM_DLLS = FileStemSet("python*", "pyshellext", "vcruntime*")
EXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle") EXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle")
EXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt") EXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt")
EXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*") EXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*")
@ -126,9 +126,9 @@ def get_layout(ns):
n = new_name or n n = new_name or n
src = ns.build / f src = ns.build / f
if ns.debug and src not in REQUIRED_DLLS: if ns.debug and src not in REQUIRED_DLLS:
if not src.stem.endswith("_d"): if not "_d." in src.name:
src = src.parent / (src.stem + "_d" + src.suffix) src = src.parent / (src.stem + "_d" + src.suffix)
if not n.endswith("_d"): if "_d." not in f:
n += "_d" n += "_d"
f = n + "." + x f = n + "." + x
yield dest + n + "." + x, src yield dest + n + "." + x, src
@ -141,17 +141,45 @@ def get_layout(ns):
if lib.is_file(): if lib.is_file():
yield "libs/" + n + ".lib", lib yield "libs/" + n + ".lib", lib
source = "python.exe"
sourcew = "pythonw.exe"
alias = [
"python",
"python{}".format(VER_MAJOR) if ns.include_alias3 else "",
"python{}".format(VER_DOT) if ns.include_alias3x else "",
]
aliasw = [
"pythonw",
"pythonw{}".format(VER_MAJOR) if ns.include_alias3 else "",
"pythonw{}".format(VER_DOT) if ns.include_alias3x else "",
]
if ns.include_appxmanifest: if ns.include_appxmanifest:
yield from in_build("python_uwp.exe", new_name="python{}".format(VER_DOT)) source = "python_uwp.exe"
yield from in_build("pythonw_uwp.exe", new_name="pythonw{}".format(VER_DOT)) sourcew = "pythonw_uwp.exe"
# For backwards compatibility, but we don't reference these ourselves. elif ns.include_freethreaded:
yield from in_build("python_uwp.exe", new_name="python") source = "python{}t.exe".format(VER_DOT)
yield from in_build("pythonw_uwp.exe", new_name="pythonw") sourcew = "pythonw{}t.exe".format(VER_DOT)
else: if not ns.include_alias:
yield from in_build("python.exe", new_name="python") alias = []
yield from in_build("pythonw.exe", new_name="pythonw") aliasw = []
alias.extend([
"python{}t".format(VER_DOT),
"python{}t".format(VER_MAJOR) if ns.include_alias3 else None,
])
aliasw.extend([
"pythonw{}t".format(VER_DOT),
"pythonw{}t".format(VER_MAJOR) if ns.include_alias3 else None,
])
yield from in_build(PYTHON_DLL_NAME) for a in filter(None, alias):
yield from in_build(source, new_name=a)
for a in filter(None, aliasw):
yield from in_build(sourcew, new_name=a)
if ns.include_freethreaded:
yield from in_build(FREETHREADED_PYTHON_DLL_NAME)
else:
yield from in_build(PYTHON_DLL_NAME)
if ns.include_launchers and ns.include_appxmanifest: if ns.include_launchers and ns.include_appxmanifest:
if ns.include_pip: if ns.include_pip:
@ -160,7 +188,10 @@ def get_layout(ns):
yield from in_build("pythonw_uwp.exe", new_name="idle{}".format(VER_DOT)) yield from in_build("pythonw_uwp.exe", new_name="idle{}".format(VER_DOT))
if ns.include_stable: if ns.include_stable:
yield from in_build(PYTHON_STABLE_DLL_NAME) if ns.include_freethreaded:
yield from in_build(FREETHREADED_PYTHON_STABLE_DLL_NAME)
else:
yield from in_build(PYTHON_STABLE_DLL_NAME)
found_any = False found_any = False
for dest, src in rglob(ns.build, "vcruntime*.dll"): for dest, src in rglob(ns.build, "vcruntime*.dll"):
@ -171,16 +202,28 @@ def get_layout(ns):
yield "LICENSE.txt", ns.build / "LICENSE.txt" yield "LICENSE.txt", ns.build / "LICENSE.txt"
for dest, src in rglob(ns.build, ("*.pyd", "*.dll")): for dest, src in rglob(ns.build, "*.pyd"):
if src.stem.endswith("_d") != bool(ns.debug) and src not in REQUIRED_DLLS: if ns.include_freethreaded:
continue if not src.match("*.cp*t-win*.pyd"):
if src in EXCLUDE_FROM_PYDS: continue
continue if bool(src.match("*_d.cp*.pyd")) != bool(ns.debug):
continue
else:
if src.match("*.cp*t-win*.pyd"):
continue
if bool(src.match("*_d.pyd")) != bool(ns.debug):
continue
if src in TEST_PYDS_ONLY and not ns.include_tests: if src in TEST_PYDS_ONLY and not ns.include_tests:
continue continue
if src in TCLTK_PYDS_ONLY and not ns.include_tcltk: if src in TCLTK_PYDS_ONLY and not ns.include_tcltk:
continue continue
yield from in_build(src.name, dest="" if ns.flat_dlls else "DLLs/")
for dest, src in rglob(ns.build, "*.dll"):
if src.stem.endswith("_d") != bool(ns.debug) and src not in REQUIRED_DLLS:
continue
if src in EXCLUDE_FROM_DLLS:
continue
yield from in_build(src.name, dest="" if ns.flat_dlls else "DLLs/") yield from in_build(src.name, dest="" if ns.flat_dlls else "DLLs/")
if ns.zip_lib: if ns.zip_lib:
@ -191,8 +234,12 @@ def get_layout(ns):
yield "Lib/{}".format(dest), src yield "Lib/{}".format(dest), src
if ns.include_venv: if ns.include_venv:
yield from in_build("venvlauncher.exe", "Lib/venv/scripts/nt/", "python") if ns.include_freethreaded:
yield from in_build("venvwlauncher.exe", "Lib/venv/scripts/nt/", "pythonw") yield from in_build("venvlaunchert.exe", "Lib/venv/scripts/nt/")
yield from in_build("venvwlaunchert.exe", "Lib/venv/scripts/nt/")
else:
yield from in_build("venvlauncher.exe", "Lib/venv/scripts/nt/")
yield from in_build("venvwlauncher.exe", "Lib/venv/scripts/nt/")
if ns.include_tools: if ns.include_tools:
@ -208,7 +255,6 @@ def get_layout(ns):
yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAME yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAME
if ns.include_dev: if ns.include_dev:
for dest, src in rglob(ns.source / "Include", "**/*.h"): for dest, src in rglob(ns.source / "Include", "**/*.h"):
yield "include/{}".format(dest), src yield "include/{}".format(dest), src
yield "include/pyconfig.h", ns.build / "pyconfig.h" yield "include/pyconfig.h", ns.build / "pyconfig.h"
@ -552,7 +598,6 @@ def main():
ns.source = ns.source or (Path(__file__).resolve().parent.parent.parent) ns.source = ns.source or (Path(__file__).resolve().parent.parent.parent)
ns.build = ns.build or Path(sys.executable).parent ns.build = ns.build or Path(sys.executable).parent
ns.temp = ns.temp or Path(tempfile.mkdtemp())
ns.doc_build = ns.doc_build or (ns.source / "Doc" / "build") ns.doc_build = ns.doc_build or (ns.source / "Doc" / "build")
if not ns.source.is_absolute(): if not ns.source.is_absolute():
ns.source = (Path.cwd() / ns.source).resolve() ns.source = (Path.cwd() / ns.source).resolve()
@ -565,7 +610,12 @@ def main():
if ns.include_cat and not ns.include_cat.is_absolute(): if ns.include_cat and not ns.include_cat.is_absolute():
ns.include_cat = (Path.cwd() / ns.include_cat).resolve() ns.include_cat = (Path.cwd() / ns.include_cat).resolve()
if not ns.arch: if not ns.arch:
ns.arch = "amd64" if sys.maxsize > 2 ** 32 else "win32" if sys.winver.endswith("-arm64"):
ns.arch = "arm64"
elif sys.winver.endswith("-32"):
ns.arch = "win32"
else:
ns.arch = "amd64"
if ns.copy and not ns.copy.is_absolute(): if ns.copy and not ns.copy.is_absolute():
ns.copy = (Path.cwd() / ns.copy).resolve() ns.copy = (Path.cwd() / ns.copy).resolve()
@ -574,6 +624,14 @@ def main():
if ns.catalog and not ns.catalog.is_absolute(): if ns.catalog and not ns.catalog.is_absolute():
ns.catalog = (Path.cwd() / ns.catalog).resolve() ns.catalog = (Path.cwd() / ns.catalog).resolve()
if not ns.temp:
# Put temp on a Dev Drive for speed if we're copying to one.
# If not, the regular temp dir will have to do.
if ns.copy and getattr(os.path, "isdevdrive", lambda d: False)(ns.copy):
ns.temp = ns.copy.with_name(ns.copy.name + "_temp")
else:
ns.temp = Path(tempfile.mkdtemp())
configure_logger(ns) configure_logger(ns)
log_info( log_info(
@ -602,6 +660,12 @@ Catalog: {ns.catalog}""",
log_warning("Assuming --include-tcltk to support --include-idle") log_warning("Assuming --include-tcltk to support --include-idle")
ns.include_tcltk = True ns.include_tcltk = True
if not (ns.include_alias or ns.include_alias3 or ns.include_alias3x):
if ns.include_freethreaded:
ns.include_alias3x = True
else:
ns.include_alias = True
try: try:
generate_source_files(ns) generate_source_files(ns)
files = list(get_layout(ns)) files = list(get_layout(ns))

View File

@ -39,3 +39,6 @@ PYTHON_PTH_NAME = "python{}{}._pth".format(VER_MAJOR, VER_MINOR)
PYTHON_CHM_NAME = "python{}{}{}{}.chm".format( PYTHON_CHM_NAME = "python{}{}{}{}.chm".format(
VER_MAJOR, VER_MINOR, VER_MICRO, VER_SUFFIX VER_MAJOR, VER_MINOR, VER_MICRO, VER_SUFFIX
) )
FREETHREADED_PYTHON_DLL_NAME = "python{}{}t.dll".format(VER_MAJOR, VER_MINOR)
FREETHREADED_PYTHON_STABLE_DLL_NAME = "python{}t.dll".format(VER_MAJOR)

View File

@ -24,6 +24,10 @@ NUSPEC_PLATFORM_DATA = dict(
amd64=("64-bit", "python", "Python"), amd64=("64-bit", "python", "Python"),
arm32=("ARM", "pythonarm", "Python (ARM)"), arm32=("ARM", "pythonarm", "Python (ARM)"),
arm64=("ARM64", "pythonarm64", "Python (ARM64)"), arm64=("ARM64", "pythonarm64", "Python (ARM64)"),
win32t=("32-bit free-threaded", "pythonx86-freethreaded", "Python (32-bit, free-threaded)"),
amd64t=("64-bit free-threaded", "python-freethreaded", "Python (free-threaded)"),
arm32t=("ARM free-threaded", "pythonarm-freethreaded", "Python (ARM, free-threaded)"),
arm64t=("ARM64 free-threaded", "pythonarm64-freethreaded", "Python (ARM64, free-threaded)"),
) )
if not NUSPEC_DATA["PYTHON_VERSION"]: if not NUSPEC_DATA["PYTHON_VERSION"]:
@ -58,7 +62,10 @@ NUSPEC_TEMPLATE = r"""<?xml version="1.0"?>
def _get_nuspec_data_overrides(ns): def _get_nuspec_data_overrides(ns):
for k, v in zip(NUSPEC_PLATFORM_DATA["_keys"], NUSPEC_PLATFORM_DATA[ns.arch]): arch = ns.arch
if ns.include_freethreaded:
arch += "t"
for k, v in zip(NUSPEC_PLATFORM_DATA["_keys"], NUSPEC_PLATFORM_DATA[arch]):
ev = os.getenv("PYTHON_NUSPEC_" + k) ev = os.getenv("PYTHON_NUSPEC_" + k)
if ev: if ev:
yield k, ev yield k, ev

View File

@ -32,6 +32,10 @@ OPTIONS = {
"nuspec": {"help": "a python.nuspec file"}, "nuspec": {"help": "a python.nuspec file"},
"chm": {"help": "the CHM documentation"}, "chm": {"help": "the CHM documentation"},
"html-doc": {"help": "the HTML documentation"}, "html-doc": {"help": "the HTML documentation"},
"freethreaded": {"help": "freethreaded binaries", "not-in-all": True},
"alias": {"help": "aliased python.exe entry-point binaries"},
"alias3": {"help": "aliased python3.exe entry-point binaries"},
"alias3x": {"help": "aliased python3.x.exe entry-point binaries"},
} }
@ -47,6 +51,8 @@ PRESETS = {
"dev", "dev",
"launchers", "launchers",
"appxmanifest", "appxmanifest",
"alias",
"alias3x",
# XXX: Disabled for now "precompile", # XXX: Disabled for now "precompile",
], ],
}, },
@ -59,9 +65,10 @@ PRESETS = {
"venv", "venv",
"props", "props",
"nuspec", "nuspec",
"alias",
], ],
}, },
"iot": {"help": "Windows IoT Core", "options": ["stable", "pip"]}, "iot": {"help": "Windows IoT Core", "options": ["alias", "stable", "pip"]},
"default": { "default": {
"help": "development kit package", "help": "development kit package",
"options": [ "options": [
@ -74,11 +81,19 @@ PRESETS = {
"dev", "dev",
"symbols", "symbols",
"html-doc", "html-doc",
"alias",
], ],
}, },
"embed": { "embed": {
"help": "embeddable package", "help": "embeddable package",
"options": ["stable", "zip-lib", "flat-dlls", "underpth", "precompile"], "options": [
"alias",
"stable",
"zip-lib",
"flat-dlls",
"underpth",
"precompile",
],
}, },
} }

View File

@ -94,6 +94,9 @@ WIN32 is still required for the locale module.
#endif #endif
#endif /* Py_BUILD_CORE || Py_BUILD_CORE_BUILTIN || Py_BUILD_CORE_MODULE */ #endif /* Py_BUILD_CORE || Py_BUILD_CORE_BUILTIN || Py_BUILD_CORE_MODULE */
/* Define to 1 if you want to disable the GIL */
#undef Py_GIL_DISABLED
/* Compiler specific defines */ /* Compiler specific defines */
/* ------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------*/
@ -305,8 +308,16 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
/* not building the core - must be an ext */ /* not building the core - must be an ext */
# if defined(_MSC_VER) # if defined(_MSC_VER)
/* So MSVC users need not specify the .lib /* So MSVC users need not specify the .lib
file in their Makefile (other compilers are file in their Makefile */
generally taken care of by distutils.) */ # if defined(Py_GIL_DISABLED)
# if defined(_DEBUG)
# pragma comment(lib,"python313t_d.lib")
# elif defined(Py_LIMITED_API)
# pragma comment(lib,"python3t.lib")
# else
# pragma comment(lib,"python313t.lib")
# endif /* _DEBUG */
# else /* Py_GIL_DISABLED */
# if defined(_DEBUG) # if defined(_DEBUG)
# pragma comment(lib,"python313_d.lib") # pragma comment(lib,"python313_d.lib")
# elif defined(Py_LIMITED_API) # elif defined(Py_LIMITED_API)
@ -314,6 +325,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
# else # else
# pragma comment(lib,"python313.lib") # pragma comment(lib,"python313.lib")
# endif /* _DEBUG */ # endif /* _DEBUG */
# endif /* Py_GIL_DISABLED */
# endif /* _MSC_VER */ # endif /* _MSC_VER */
# endif /* Py_BUILD_CORE */ # endif /* Py_BUILD_CORE */
#endif /* MS_COREDLL */ #endif /* MS_COREDLL */
@ -739,7 +751,4 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
/* Define if libssl has X509_VERIFY_PARAM_set1_host and related function */ /* Define if libssl has X509_VERIFY_PARAM_set1_host and related function */
#define HAVE_X509_VERIFY_PARAM_SET1_HOST 1 #define HAVE_X509_VERIFY_PARAM_SET1_HOST 1
/* Define if you want to disable the GIL */
#undef Py_GIL_DISABLED
#endif /* !Py_CONFIG_H */ #endif /* !Py_CONFIG_H */

510
PC/venvlauncher.c Normal file
View File

@ -0,0 +1,510 @@
/*
* venv redirector for Windows
*
* This launcher looks for a nearby pyvenv.cfg to find the correct home
* directory, and then launches the original Python executable from it.
* The name of this executable is passed as argv[0].
*/
#define __STDC_WANT_LIB_EXT1__ 1
#include <windows.h>
#include <pathcch.h>
#include <fcntl.h>
#include <io.h>
#include <shlobj.h>
#include <stdio.h>
#include <stdbool.h>
#include <tchar.h>
#include <assert.h>
#define MS_WINDOWS
#include "patchlevel.h"
#define MAXLEN PATHCCH_MAX_CCH
#define MSGSIZE 1024
#define RC_NO_STD_HANDLES 100
#define RC_CREATE_PROCESS 101
#define RC_NO_PYTHON 103
#define RC_NO_MEMORY 104
#define RC_NO_VENV_CFG 106
#define RC_BAD_VENV_CFG 107
#define RC_NO_COMMANDLINE 108
#define RC_INTERNAL_ERROR 109
// This should always be defined when we build for real,
// but it's handy to have a definition for quick testing
#ifndef EXENAME
#define EXENAME L"python.exe"
#endif
#ifndef CFGNAME
#define CFGNAME L"pyvenv.cfg"
#endif
static FILE * log_fp = NULL;
void
debug(wchar_t * format, ...)
{
va_list va;
if (log_fp != NULL) {
wchar_t buffer[MAXLEN];
int r = 0;
va_start(va, format);
r = vswprintf_s(buffer, MAXLEN, format, va);
va_end(va);
if (r <= 0) {
return;
}
fwprintf(log_fp, L"%ls\n", buffer);
while (r && isspace(buffer[r])) {
buffer[r--] = L'\0';
}
if (buffer[0]) {
OutputDebugStringW(buffer);
}
}
}
void
formatWinerror(int rc, wchar_t * message, int size)
{
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
message, size, NULL);
}
void
winerror(int err, wchar_t * format, ... )
{
va_list va;
wchar_t message[MSGSIZE];
wchar_t win_message[MSGSIZE];
int len;
if (err == 0) {
err = GetLastError();
}
va_start(va, format);
len = _vsnwprintf_s(message, MSGSIZE, _TRUNCATE, format, va);
va_end(va);
formatWinerror(err, win_message, MSGSIZE);
if (len >= 0) {
_snwprintf_s(&message[len], MSGSIZE - len, _TRUNCATE, L": %ls",
win_message);
}
#if !defined(_WINDOWS)
fwprintf(stderr, L"%ls\n", message);
#else
MessageBoxW(NULL, message, L"Python venv launcher is sorry to say ...",
MB_OK);
#endif
}
void
error(wchar_t * format, ... )
{
va_list va;
wchar_t message[MSGSIZE];
va_start(va, format);
_vsnwprintf_s(message, MSGSIZE, _TRUNCATE, format, va);
va_end(va);
#if !defined(_WINDOWS)
fwprintf(stderr, L"%ls\n", message);
#else
MessageBoxW(NULL, message, L"Python venv launcher is sorry to say ...",
MB_OK);
#endif
}
bool
isEnvVarSet(const wchar_t *name)
{
/* only looking for non-empty, which means at least one character
and the null terminator */
return GetEnvironmentVariableW(name, NULL, 0) >= 2;
}
bool
join(wchar_t *buffer, size_t bufferLength, const wchar_t *fragment)
{
if (SUCCEEDED(PathCchCombineEx(buffer, bufferLength, buffer, fragment, PATHCCH_ALLOW_LONG_PATHS))) {
return true;
}
return false;
}
bool
split_parent(wchar_t *buffer, size_t bufferLength)
{
return SUCCEEDED(PathCchRemoveFileSpec(buffer, bufferLength));
}
/*
* Path calculation
*/
int
calculate_pyvenvcfg_path(wchar_t *pyvenvcfg_path, size_t maxlen)
{
if (!pyvenvcfg_path) {
error(L"invalid buffer provided");
return RC_INTERNAL_ERROR;
}
if ((DWORD)maxlen != maxlen) {
error(L"path buffer is too large");
return RC_INTERNAL_ERROR;
}
if (!GetModuleFileNameW(NULL, pyvenvcfg_path, (DWORD)maxlen)) {
winerror(GetLastError(), L"failed to read executable directory");
return RC_NO_COMMANDLINE;
}
// Remove 'python.exe' from our path
if (!split_parent(pyvenvcfg_path, maxlen)) {
error(L"failed to remove segment from '%ls'", pyvenvcfg_path);
return RC_NO_COMMANDLINE;
}
// Replace with 'pyvenv.cfg'
if (!join(pyvenvcfg_path, maxlen, CFGNAME)) {
error(L"failed to append '%ls' to '%ls'", CFGNAME, pyvenvcfg_path);
return RC_NO_MEMORY;
}
// If it exists, return
if (GetFileAttributesW(pyvenvcfg_path) != INVALID_FILE_ATTRIBUTES) {
return 0;
}
// Otherwise, remove 'pyvenv.cfg' and (probably) 'Scripts'
if (!split_parent(pyvenvcfg_path, maxlen) ||
!split_parent(pyvenvcfg_path, maxlen)) {
error(L"failed to remove segments from '%ls'", pyvenvcfg_path);
return RC_NO_COMMANDLINE;
}
// Replace 'pyvenv.cfg'
if (!join(pyvenvcfg_path, maxlen, CFGNAME)) {
error(L"failed to append '%ls' to '%ls'", CFGNAME, pyvenvcfg_path);
return RC_NO_MEMORY;
}
// If it exists, return
if (GetFileAttributesW(pyvenvcfg_path) != INVALID_FILE_ATTRIBUTES) {
return 0;
}
// Otherwise, we fail
winerror(GetLastError(), L"failed to locate %ls", CFGNAME);
return RC_NO_VENV_CFG;
}
/*
* pyvenv.cfg parsing
*/
static int
find_home_value(const char *buffer, DWORD maxlen, const char **start, DWORD *length)
{
if (!buffer || !start || !length) {
error(L"invalid find_home_value parameters()");
return 0;
}
for (const char *s = strstr(buffer, "home");
s && ((ptrdiff_t)s - (ptrdiff_t)buffer) < maxlen;
s = strstr(s + 1, "\nhome")
) {
if (*s == '\n') {
++s;
}
for (int i = 4; i > 0 && *s; --i, ++s);
while (*s && iswspace(*s)) {
++s;
}
if (*s != L'=') {
continue;
}
do {
++s;
} while (*s && iswspace(*s));
*start = s;
char *nl = strchr(s, '\n');
if (nl) {
while (nl != s && iswspace(nl[-1])) {
--nl;
}
*length = (DWORD)((ptrdiff_t)nl - (ptrdiff_t)s);
} else {
*length = (DWORD)strlen(s);
}
return 1;
}
return 0;
}
int
read_home(const wchar_t *pyvenv_cfg, wchar_t *home_path, size_t maxlen)
{
HANDLE hFile = CreateFileW(pyvenv_cfg, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
winerror(GetLastError(), L"failed to open '%ls'", pyvenv_cfg);
return RC_BAD_VENV_CFG;
}
// 8192 characters ought to be enough for anyone
// (doubled compared to the old implementation!)
char buffer[8192];
DWORD len;
if (!ReadFile(hFile, buffer, sizeof(buffer) - 1, &len, NULL)) {
winerror(GetLastError(), L"failed to read '%ls'", pyvenv_cfg);
CloseHandle(hFile);
return RC_BAD_VENV_CFG;
}
CloseHandle(hFile);
// Ensure null termination
buffer[len] = '\0';
char *home;
DWORD home_len;
if (!find_home_value(buffer, sizeof(buffer), &home, &home_len)) {
error(L"no home= specified in '%ls'", pyvenv_cfg);
return RC_BAD_VENV_CFG;
}
if ((DWORD)maxlen != maxlen) {
maxlen = 8192;
}
len = MultiByteToWideChar(CP_UTF8, 0, home, home_len, home_path, (DWORD)maxlen);
if (!len) {
winerror(GetLastError(), L"failed to decode home setting in '%ls'", pyvenv_cfg);
return RC_BAD_VENV_CFG;
}
home_path[len] = L'\0';
return 0;
}
int
locate_python(wchar_t *path, size_t maxlen)
{
if (!join(path, maxlen, EXENAME)) {
error(L"failed to append %ls to '%ls'", EXENAME, path);
return RC_NO_MEMORY;
}
if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES) {
winerror(GetLastError(), L"did not find executable at '%ls'", path);
return RC_NO_PYTHON;
}
return 0;
}
int
smuggle_path()
{
wchar_t buffer[MAXLEN];
// We could use argv[0], but that may be wrong in certain rare cases (if the
// user is doing something weird like symlinks to venv redirectors), and
// what we _really_ want is the directory of the venv. We always copy the
// redirectors, so if we've made the venv, this will be correct.
DWORD len = GetModuleFileNameW(NULL, buffer, MAXLEN);
if (!len) {
winerror(GetLastError(), L"Failed to get own executable path");
return RC_INTERNAL_ERROR;
}
buffer[len] = L'\0';
debug(L"Setting __PYVENV_LAUNCHER__ = '%s'", buffer);
if (!SetEnvironmentVariableW(L"__PYVENV_LAUNCHER__", buffer)) {
winerror(GetLastError(), L"Failed to set launcher environment");
return RC_INTERNAL_ERROR;
}
return 0;
}
/*
* Process creation
*/
static BOOL
safe_duplicate_handle(HANDLE in, HANDLE * pout, const wchar_t *name)
{
BOOL ok;
HANDLE process = GetCurrentProcess();
DWORD rc;
*pout = NULL;
ok = DuplicateHandle(process, in, process, pout, 0, TRUE,
DUPLICATE_SAME_ACCESS);
if (!ok) {
rc = GetLastError();
if (rc == ERROR_INVALID_HANDLE) {
debug(L"DuplicateHandle(%ls) returned ERROR_INVALID_HANDLE\n", name);
ok = TRUE;
}
else {
debug(L"DuplicateHandle(%ls) returned %d\n", name, rc);
}
}
return ok;
}
static BOOL WINAPI
ctrl_c_handler(DWORD code)
{
return TRUE; /* We just ignore all control events. */
}
static int
launch(const wchar_t *executable, wchar_t *cmdline)
{
HANDLE job;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
DWORD rc;
BOOL ok;
STARTUPINFOW si;
PROCESS_INFORMATION pi;
#if defined(_WINDOWS)
/*
When explorer launches a Windows (GUI) application, it displays
the "app starting" (the "pointer + hourglass") cursor for a number
of seconds, or until the app does something UI-ish (eg, creating a
window, or fetching a message). As this launcher doesn't do this
directly, that cursor remains even after the child process does these
things. We avoid that by doing a simple post+get message.
See http://bugs.python.org/issue17290
*/
MSG msg;
PostMessage(0, 0, 0, 0);
GetMessage(&msg, 0, 0, 0);
#endif
debug(L"run_child: about to run '%ls' with '%ls'\n", executable, cmdline);
job = CreateJobObject(NULL, NULL);
ok = QueryInformationJobObject(job, JobObjectExtendedLimitInformation,
&info, sizeof(info), &rc);
if (!ok || (rc != sizeof(info)) || !job) {
winerror(GetLastError(), L"Job information querying failed");
return RC_CREATE_PROCESS;
}
info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
ok = SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info,
sizeof(info));
if (!ok) {
winerror(GetLastError(), L"Job information setting failed");
return RC_CREATE_PROCESS;
}
memset(&si, 0, sizeof(si));
GetStartupInfoW(&si);
ok = safe_duplicate_handle(GetStdHandle(STD_INPUT_HANDLE), &si.hStdInput, L"stdin");
if (!ok) {
return RC_NO_STD_HANDLES;
}
ok = safe_duplicate_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si.hStdOutput, L"stdout");
if (!ok) {
return RC_NO_STD_HANDLES;
}
ok = safe_duplicate_handle(GetStdHandle(STD_ERROR_HANDLE), &si.hStdError, L"stderr");
if (!ok) {
return RC_NO_STD_HANDLES;
}
ok = SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
if (!ok) {
winerror(GetLastError(), L"control handler setting failed");
return RC_CREATE_PROCESS;
}
si.dwFlags = STARTF_USESTDHANDLES;
ok = CreateProcessW(executable, cmdline, NULL, NULL, TRUE,
0, NULL, NULL, &si, &pi);
if (!ok) {
winerror(GetLastError(), L"Unable to create process using '%ls'", cmdline);
return RC_CREATE_PROCESS;
}
AssignProcessToJobObject(job, pi.hProcess);
CloseHandle(pi.hThread);
WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE);
ok = GetExitCodeProcess(pi.hProcess, &rc);
if (!ok) {
winerror(GetLastError(), L"Failed to get exit code of process");
return RC_CREATE_PROCESS;
}
debug(L"child process exit code: %d", rc);
return rc;
}
int
process(int argc, wchar_t ** argv)
{
int exitCode;
wchar_t pyvenvcfg_path[MAXLEN];
wchar_t home_path[MAXLEN];
if (isEnvVarSet(L"PYLAUNCHER_DEBUG")) {
setvbuf(stderr, (char *)NULL, _IONBF, 0);
log_fp = stderr;
}
exitCode = calculate_pyvenvcfg_path(pyvenvcfg_path, MAXLEN);
if (exitCode) return exitCode;
exitCode = read_home(pyvenvcfg_path, home_path, MAXLEN);
if (exitCode) return exitCode;
exitCode = locate_python(home_path, MAXLEN);
if (exitCode) return exitCode;
// We do not update argv[0] to point at the target runtime, and so we do not
// pass through our original argv[0] in an environment variable.
//exitCode = smuggle_path();
//if (exitCode) return exitCode;
exitCode = launch(home_path, GetCommandLineW());
return exitCode;
}
#if defined(_WINDOWS)
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpstrCmd, int nShow)
{
return process(__argc, __wargv);
}
#else
int cdecl wmain(int argc, wchar_t ** argv)
{
return process(argc, argv);
}
#endif

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
<PropertyGroup Label="Configuration" /> <PropertyGroup Label="Configuration" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>
@ -107,4 +107,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -24,6 +24,13 @@
<LinkIncremental Condition="$(Configuration) != 'Debug'">false</LinkIncremental> <LinkIncremental Condition="$(Configuration) != 'Debug'">false</LinkIncremental>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="$(TargetExt) != ''">
<TargetNameExt>$(TargetName)$(TargetExt)</TargetNameExt>
<_TargetNameSep>$(TargetNameExt.LastIndexOf(`.`))</_TargetNameSep>
<TargetName>$(TargetNameExt.Substring(0, $(_TargetNameSep)))</TargetName>
<TargetExt>$(TargetNameExt.Substring($(_TargetNameSep)))</TargetExt>
</PropertyGroup>
<PropertyGroup Label="MSVC Bug Workarounds" Condition="$(VCToolsVersion) != ''"> <PropertyGroup Label="MSVC Bug Workarounds" Condition="$(VCToolsVersion) != ''">
<_VCToolsVersion>$([System.Version]::Parse(`$(VCToolsVersion)`).Major).$([System.Version]::Parse(`$(VCToolsVersion)`).Minor)</_VCToolsVersion> <_VCToolsVersion>$([System.Version]::Parse(`$(VCToolsVersion)`).Major).$([System.Version]::Parse(`$(VCToolsVersion)`).Minor)</_VCToolsVersion>
@ -38,7 +45,7 @@
<_PlatformPreprocessorDefinition>_WIN32;</_PlatformPreprocessorDefinition> <_PlatformPreprocessorDefinition>_WIN32;</_PlatformPreprocessorDefinition>
<_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64'">_WIN64;</_PlatformPreprocessorDefinition> <_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64'">_WIN64;</_PlatformPreprocessorDefinition>
<_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64' and $(PlatformToolset) != 'ClangCL'">_M_X64;$(_PlatformPreprocessorDefinition)</_PlatformPreprocessorDefinition> <_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64' and $(PlatformToolset) != 'ClangCL'">_M_X64;$(_PlatformPreprocessorDefinition)</_PlatformPreprocessorDefinition>
<_Py3NamePreprocessorDefinition>PY3_DLLNAME=L"$(Py3DllName)";</_Py3NamePreprocessorDefinition> <_Py3NamePreprocessorDefinition>PY3_DLLNAME=L"$(Py3DllName)$(PyDebugExt)";</_Py3NamePreprocessorDefinition>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
@ -158,8 +165,8 @@ public override bool Execute() {
</UsingTask> </UsingTask>
<Target Name="KillPython" BeforeTargets="PrepareForBuild" Condition="'$(KillPython)' == 'true'"> <Target Name="KillPython" BeforeTargets="PrepareForBuild" Condition="'$(KillPython)' == 'true'">
<Message Text="Killing any running python$(PyDebugExt)$(PyTestExt).exe instances..." Importance="high" /> <Message Text="Killing any running $(PyExeName)$(PyDebugExt)$(PyTestExt).exe instances..." Importance="high" />
<KillPython FileName="$(OutDir)python$(PyDebugExt)$(PyTestExt).exe" /> <KillPython FileName="$(OutDir)$(PyExeName)$(PyDebugExt)$(PyTestExt).exe" />
</Target> </Target>
<!-- <!--

View File

@ -31,11 +31,11 @@
<ArchName Condition="'$(ArchName)' == '' and $(Platform) == 'ARM'">arm32</ArchName> <ArchName Condition="'$(ArchName)' == '' and $(Platform) == 'ARM'">arm32</ArchName>
<ArchName Condition="'$(ArchName)' == '' and $(Platform) == 'ARM64'">arm64</ArchName> <ArchName Condition="'$(ArchName)' == '' and $(Platform) == 'ARM64'">arm64</ArchName>
<ArchName Condition="'$(ArchName)' == ''">win32</ArchName> <ArchName Condition="'$(ArchName)' == ''">win32</ArchName>
<!-- Root directory of the repository --> <!-- Root directory of the repository -->
<PySourcePath Condition="'$(PySourcePath)' == ''">$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\))</PySourcePath> <PySourcePath Condition="'$(PySourcePath)' == ''">$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\))</PySourcePath>
<PySourcePath Condition="!HasTrailingSlash($(PySourcePath))">$(PySourcePath)\</PySourcePath> <PySourcePath Condition="!HasTrailingSlash($(PySourcePath))">$(PySourcePath)\</PySourcePath>
<!-- Directory where build outputs are put --> <!-- Directory where build outputs are put -->
<BuildPath32 Condition="'$(Py_OutDir)' == ''">$(PySourcePath)PCbuild\win32\</BuildPath32> <BuildPath32 Condition="'$(Py_OutDir)' == ''">$(PySourcePath)PCbuild\win32\</BuildPath32>
<BuildPath32 Condition="'$(Py_OutDir)' != ''">$(Py_OutDir)\win32\</BuildPath32> <BuildPath32 Condition="'$(Py_OutDir)' != ''">$(Py_OutDir)\win32\</BuildPath32>
@ -52,7 +52,7 @@
<BuildPath Condition="'$(BuildPath)' == ''">$(PySourcePath)PCbuild\$(ArchName)\</BuildPath> <BuildPath Condition="'$(BuildPath)' == ''">$(PySourcePath)PCbuild\$(ArchName)\</BuildPath>
<BuildPath Condition="!HasTrailingSlash($(BuildPath))">$(BuildPath)\</BuildPath> <BuildPath Condition="!HasTrailingSlash($(BuildPath))">$(BuildPath)\</BuildPath>
<BuildPath Condition="$(Configuration) == 'PGInstrument'">$(BuildPath)instrumented\</BuildPath> <BuildPath Condition="$(Configuration) == 'PGInstrument'">$(BuildPath)instrumented\</BuildPath>
<!-- VPATH definition (escaped) --> <!-- VPATH definition (escaped) -->
<PyVPath Condition="$(Configuration) != 'PGInstrument'">..\\..</PyVPath> <PyVPath Condition="$(Configuration) != 'PGInstrument'">..\\..</PyVPath>
<PyVPath Condition="$(Configuration) == 'PGInstrument'">..\\..\\..</PyVPath> <PyVPath Condition="$(Configuration) == 'PGInstrument'">..\\..\\..</PyVPath>
@ -84,22 +84,19 @@
<PropertyGroup> <PropertyGroup>
<!-- Suffix for all binaries when building for debug --> <!-- Suffix for all binaries when building for debug -->
<PyDebugExt Condition="'$(PyDebugExt)' == '' and $(Configuration) == 'Debug'">_d</PyDebugExt> <PyDebugExt Condition="'$(PyDebugExt)' == '' and $(Configuration) == 'Debug'">_d</PyDebugExt>
<!-- Suffix for versions/keys when building with test markers --> <!-- Suffix for versions/keys when building with test markers -->
<PyTestExt Condition="$(UseTestMarker) == 'true'">-test</PyTestExt> <PyTestExt Condition="$(UseTestMarker) == 'true'">-test</PyTestExt>
<!-- Suffix for versions/keys when building for particular platforms --> <!-- Suffix for versions/keys when building for particular platforms -->
<PyArchExt Condition="'$(ArchName)' == 'win32'">-32</PyArchExt> <PyArchExt Condition="'$(ArchName)' == 'win32'">-32</PyArchExt>
<PyArchExt Condition="'$(ArchName)' == 'arm32'">-arm32</PyArchExt> <PyArchExt Condition="'$(ArchName)' == 'arm32'">-arm32</PyArchExt>
<PyArchExt Condition="'$(ArchName)' == 'arm64'">-arm64</PyArchExt> <PyArchExt Condition="'$(ArchName)' == 'arm64'">-arm64</PyArchExt>
<!-- Full path of the resulting python.exe binary -->
<PythonExe Condition="'$(PythonExe)' == ''">$(BuildPath)python$(PyDebugExt).exe</PythonExe>
<!-- Include Tkinter by default --> <!-- Include Tkinter by default -->
<IncludeTkinter Condition="'$(IncludeTkinter)' == ''">true</IncludeTkinter> <IncludeTkinter Condition="'$(IncludeTkinter)' == ''">true</IncludeTkinter>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM'" Label="ArmConfiguration"> <PropertyGroup Condition="'$(Platform)'=='ARM'" Label="ArmConfiguration">
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
</PropertyGroup> </PropertyGroup>
@ -141,7 +138,7 @@
<PropertyGroup Condition="'$(OverrideVersion)' == ''"> <PropertyGroup Condition="'$(OverrideVersion)' == ''">
<!-- <!--
Read version information from Include\patchlevel.h. The following properties are set: Read version information from Include\patchlevel.h. The following properties are set:
MajorVersionNumber - the '3' in '3.5.2a1' MajorVersionNumber - the '3' in '3.5.2a1'
MinorVersionNumber - the '5' in '3.5.2a1' MinorVersionNumber - the '5' in '3.5.2a1'
MicroVersionNumber - the '2' in '3.5.2a1' MicroVersionNumber - the '2' in '3.5.2a1'
@ -167,22 +164,22 @@
<ReleaseLevelName Condition="$(_ReleaseLevel) == 'BETA'">b$(ReleaseSerial)</ReleaseLevelName> <ReleaseLevelName Condition="$(_ReleaseLevel) == 'BETA'">b$(ReleaseSerial)</ReleaseLevelName>
<ReleaseLevelName Condition="$(_ReleaseLevel) == 'GAMMA'">rc$(ReleaseSerial)</ReleaseLevelName> <ReleaseLevelName Condition="$(_ReleaseLevel) == 'GAMMA'">rc$(ReleaseSerial)</ReleaseLevelName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(OverrideVersion)' != ''"> <PropertyGroup Condition="'$(OverrideVersion)' != ''">
<!-- <!--
Override the version number when building by specifying OverrideVersion. Override the version number when building by specifying OverrideVersion.
For example: For example:
PCbuild\build.bat "/p:OverrideVersion=3.5.2a1" PCbuild\build.bat "/p:OverrideVersion=3.5.2a1"
Use the -V option to check your version is valid: Use the -V option to check your version is valid:
PCbuild\build.bat -V "/p:OverrideVersion=3.5.2a1" PCbuild\build.bat -V "/p:OverrideVersion=3.5.2a1"
PythonVersionNumber: 3.5.2 PythonVersionNumber: 3.5.2
PythonVersion: 3.5.2a1 PythonVersion: 3.5.2a1
PythonVersionHex: 0x030502A1 PythonVersionHex: 0x030502A1
Field3Value: 2101 Field3Value: 2101
Note that this only affects the version numbers embedded in resources and Note that this only affects the version numbers embedded in resources and
installers, but not sys.version. installers, but not sys.version.
--> -->
@ -223,22 +220,55 @@
)) ))
))</Field3Value> ))</Field3Value>
<Field3Value Condition="$(UseTestMarker) == 'true'">$([msbuild]::Add($(Field3Value), 9000))</Field3Value> <Field3Value Condition="$(UseTestMarker) == 'true'">$([msbuild]::Add($(Field3Value), 9000))</Field3Value>
<!-- Name and full path of the resulting python.exe binary -->
<PyExeName Condition="$(DisableGil) == 'true'">python$(MajorVersionNumber).$(MinorVersionNumber)t</PyExeName>
<PyExeName Condition="$(PyExeName) == ''">python</PyExeName>
<PythonExe Condition="'$(PythonExe)' == ''">$(BuildPath)$(PyExeName)$(PyDebugExt).exe</PythonExe>
<PyWExeName Condition="$(DisableGil) == 'true'">pythonw$(MajorVersionNumber).$(MinorVersionNumber)t</PyWExeName>
<PyWExeName Condition="$(PyWExeName) == ''">pythonw</PyWExeName>
<!-- The name of the resulting pythonXY.dll (without the extension) --> <!-- The name of the resulting pythonXY.dll (without the extension) -->
<PyDllName>python$(MajorVersionNumber)$(MinorVersionNumber)$(PyDebugExt)</PyDllName> <PyDllName Condition="$(DisableGil) == 'true'">python$(MajorVersionNumber)$(MinorVersionNumber)t$(PyDebugExt)</PyDllName>
<PyDllName Condition="$(PyDllName) == ''">python$(MajorVersionNumber)$(MinorVersionNumber)$(PyDebugExt)</PyDllName>
<!-- The name of the resulting pythonX.dll (without the extension) --> <!-- The name of the resulting pythonX.dll (without the extension) -->
<Py3DllName>python3$(PyDebugExt)</Py3DllName> <Py3DllName Condition="$(DisableGil) == 'true'">python3t</Py3DllName>
<Py3DllName Condition="$(Py3DllName) == ''">python3</Py3DllName>
<!-- The version and platform tag to include in .pyd filenames --> <!-- The version and platform tag to include in .pyd filenames -->
<PydTag Condition="$(ArchName) == 'win32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win32</PydTag> <PydTag Condition="$(ArchName) == 'win32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win32</PydTag>
<PydTag Condition="$(ArchName) == 'arm32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm32</PydTag> <PydTag Condition="$(ArchName) == 'arm32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm32</PydTag>
<PydTag Condition="$(ArchName) == 'arm64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm64</PydTag> <PydTag Condition="$(ArchName) == 'arm64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm64</PydTag>
<PydTag Condition="$(ArchName) == 'amd64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_amd64</PydTag> <PydTag Condition="$(ArchName) == 'amd64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_amd64</PydTag>
<!-- The version number for sys.winver --> <!-- The version number for sys.winver -->
<SysWinVer>$(MajorVersionNumber).$(MinorVersionNumber)$(PyArchExt)$(PyTestExt)</SysWinVer> <SysWinVer>$(MajorVersionNumber).$(MinorVersionNumber)$(PyArchExt)$(PyTestExt)</SysWinVer>
<!-- The version and platform tag to include in .pyd filenames for freethreaded builds -->
<FreethreadedPydTag Condition="$(ArchName) == 'win32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)t-win32</FreethreadedPydTag>
<FreethreadedPydTag Condition="$(ArchName) == 'arm32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)t-win_arm32</FreethreadedPydTag>
<FreethreadedPydTag Condition="$(ArchName) == 'arm64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)t-win_arm64</FreethreadedPydTag>
<FreethreadedPydTag Condition="$(ArchName) == 'amd64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)t-win_amd64</FreethreadedPydTag>
<!-- The version number for sys.winver for freethreaded builds -->
<FreethreadedSysWinVer>$(MajorVersionNumber).$(MinorVersionNumber)t$(PyArchExt)$(PyTestExt)</FreethreadedSysWinVer>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="$(DisableGil) != 'true'">
<!-- The extension to use for standard library PYDs -->
<PyStdlibPydExt>.pyd</PyStdlibPydExt>
</PropertyGroup>
<PropertyGroup Condition="$(DisableGil) == 'true'">
<PydTag>$(FreethreadedPydTag)</PydTag>
<!-- The extension to use for standard library PYDs -->
<PyStdlibPydExt>$(PydTag).pyd</PyStdlibPydExt>
<!-- The version number for sys.winver -->
<SysWinVer>$(FreethreadedSysWinVer)</SysWinVer>
</PropertyGroup>
<!-- Displays the calculated version info --> <!-- Displays the calculated version info -->
<Target Name="ShowVersionInfo"> <Target Name="ShowVersionInfo">
<Message Importance="high" Text="PythonVersionNumber: $(PythonVersionNumber)" /> <Message Importance="high" Text="PythonVersionNumber: $(PythonVersionNumber)" />

View File

@ -72,6 +72,7 @@
<Import Project="python.props" /> <Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration"> <PropertyGroup Label="Configuration">
<TargetName>$(PyExeName)</TargetName>
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
@ -132,7 +133,7 @@
</PropertyGroup> </PropertyGroup>
<Exec Command='setlocal <Exec Command='setlocal
set PYTHONPATH=$(PySourcePath)Lib set PYTHONPATH=$(PySourcePath)Lib
"$(OutDir)python$(PyDebugExt).exe" "$(PySourcePath)PC\validate_ucrtbase.py" $(UcrtName)' ContinueOnError="true" /> "$(OutDir)$(PyExeName)$(PyDebugExt).exe" "$(PySourcePath)PC\validate_ucrtbase.py" $(UcrtName)' ContinueOnError="true" />
</Target> </Target>
<Target Name="GeneratePythonBat" AfterTargets="AfterBuild"> <Target Name="GeneratePythonBat" AfterTargets="AfterBuild">
<PropertyGroup> <PropertyGroup>
@ -145,7 +146,7 @@ set PYTHONPATH=$(PySourcePath)Lib
@echo Running $(Configuration)^|$(Platform) interpreter... @echo Running $(Configuration)^|$(Platform) interpreter...
@setlocal @setlocal
@set PYTHONHOME=$(PySourcePath) @set PYTHONHOME=$(PySourcePath)
@"$(OutDir)python$(PyDebugExt).exe" %* @"$(OutDir)$(PyExeName)$(PyDebugExt).exe" %*
</_Content> </_Content>
<_ExistingContent Condition="Exists('$(PySourcePath)python.bat')">$([System.IO.File]::ReadAllText('$(PySourcePath)python.bat'))</_ExistingContent> <_ExistingContent Condition="Exists('$(PySourcePath)python.bat')">$([System.IO.File]::ReadAllText('$(PySourcePath)python.bat'))</_ExistingContent>
</PropertyGroup> </PropertyGroup>

View File

@ -70,12 +70,12 @@
<ProjectGuid>{885D4898-D08D-4091-9C40-C700CFE3FC5A}</ProjectGuid> <ProjectGuid>{885D4898-D08D-4091-9C40-C700CFE3FC5A}</ProjectGuid>
<RootNamespace>python3dll</RootNamespace> <RootNamespace>python3dll</RootNamespace>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<TargetName>python3</TargetName>
<SupportPGO>false</SupportPGO> <SupportPGO>false</SupportPGO>
</PropertyGroup> </PropertyGroup>
<Import Project="python.props" /> <Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration"> <PropertyGroup Label="Configuration">
<TargetName>$(Py3DllName)</TargetName>
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

View File

@ -73,6 +73,7 @@
<Import Project="python.props" /> <Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration"> <PropertyGroup Label="Configuration">
<TargetName>$(PyWExeName)</TargetName>
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
</PropertyGroup> </PropertyGroup>

View File

@ -9,6 +9,7 @@ rem -q runs the tests just once, and without deleting .pyc files.
rem -p <Win32|x64|ARM|ARM64> or -win32, -x64, -arm32, -arm64 rem -p <Win32|x64|ARM|ARM64> or -win32, -x64, -arm32, -arm64
rem Run the specified architecture of python (or python_d if -d rem Run the specified architecture of python (or python_d if -d
rem was specified). If omitted, uses %PREFIX% if set or 64-bit. rem was specified). If omitted, uses %PREFIX% if set or 64-bit.
rem --disable-gil Run free-threaded build.
rem All leading instances of these switches are shifted off, and rem All leading instances of these switches are shifted off, and
rem whatever remains (up to 9 arguments) is passed to regrtest.py. rem whatever remains (up to 9 arguments) is passed to regrtest.py.
rem For example, rem For example,
@ -29,6 +30,7 @@ rem rt -u "network,largefile"
setlocal setlocal
set pcbuild=%~dp0 set pcbuild=%~dp0
set pyname=python
set suffix= set suffix=
set qmode= set qmode=
set dashO= set dashO=
@ -39,15 +41,18 @@ set exe=
if "%1"=="-O" (set dashO=-O) & shift & goto CheckOpts if "%1"=="-O" (set dashO=-O) & shift & goto CheckOpts
if "%1"=="-q" (set qmode=yes) & shift & goto CheckOpts if "%1"=="-q" (set qmode=yes) & shift & goto CheckOpts
if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts
rem HACK: Need some way to infer the version number in this script
if "%1"=="--disable-gil" (set pyname=python3.13t) & shift & goto CheckOpts
if "%1"=="-win32" (set prefix=%pcbuild%win32) & shift & goto CheckOpts if "%1"=="-win32" (set prefix=%pcbuild%win32) & shift & goto CheckOpts
if "%1"=="-x64" (set prefix=%pcbuild%amd64) & shift & goto CheckOpts if "%1"=="-x64" (set prefix=%pcbuild%amd64) & shift & goto CheckOpts
if "%1"=="-amd64" (set prefix=%pcbuild%amd64) & shift & goto CheckOpts
if "%1"=="-arm64" (set prefix=%pcbuild%arm64) & shift & goto CheckOpts if "%1"=="-arm64" (set prefix=%pcbuild%arm64) & shift & goto CheckOpts
if "%1"=="-arm32" (set prefix=%pcbuild%arm32) & shift & goto CheckOpts if "%1"=="-arm32" (set prefix=%pcbuild%arm32) & shift & goto CheckOpts
if "%1"=="-p" (call :SetPlatform %~2) & shift & shift & goto CheckOpts if "%1"=="-p" (call :SetPlatform %~2) & shift & shift & goto CheckOpts
if NOT "%1"=="" (set regrtestargs=%regrtestargs% %1) & shift & goto CheckOpts if NOT "%1"=="" (set regrtestargs=%regrtestargs% %1) & shift & goto CheckOpts
if not defined prefix set prefix=%pcbuild%amd64 if not defined prefix set prefix=%pcbuild%amd64
set exe=%prefix%\python%suffix%.exe set exe=%prefix%\%pyname%%suffix%.exe
set cmd="%exe%" %dashO% -m test %regrtestargs% set cmd="%exe%" %dashO% -m test %regrtestargs%
if defined qmode goto Qmode if defined qmode goto Qmode

View File

@ -78,7 +78,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -69,12 +69,12 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{A1A295E5-463C-437F-81CA-1F32367685DA}</ProjectGuid> <ProjectGuid>{A1A295E5-463C-437F-81CA-1F32367685DA}</ProjectGuid>
<RootNamespace>sqlite3</RootNamespace> <RootNamespace>sqlite3</RootNamespace>
<TargetExt>.pyd</TargetExt>
<SupportPGO>false</SupportPGO> <SupportPGO>false</SupportPGO>
</PropertyGroup> </PropertyGroup>
<Import Project="python.props" /> <Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration"> <PropertyGroup Label="Configuration">
<TargetExt>$(PyStdlibPydExt)</TargetExt>
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>NotSet</CharacterSet> <CharacterSet>NotSet</CharacterSet>
</PropertyGroup> </PropertyGroup>

View File

@ -79,7 +79,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -69,12 +69,13 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}</ProjectGuid> <ProjectGuid>{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}</ProjectGuid>
<RootNamespace>venvlauncher</RootNamespace> <RootNamespace>venvlauncher</RootNamespace>
<TargetName>venvlauncher</TargetName>
<SupportPGO>false</SupportPGO> <SupportPGO>false</SupportPGO>
</PropertyGroup> </PropertyGroup>
<Import Project="python.props" /> <Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration"> <PropertyGroup Label="Configuration">
<TargetName>venvlauncher</TargetName>
<TargetName Condition="$(DisableGil) == 'true'">$(TargetName)t</TargetName>
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -91,19 +92,19 @@
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<PreprocessorDefinitions>_CONSOLE;VENV_REDIRECT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>EXENAME=L"$(PyExeName)$(PyDebugExt).exe";_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>PY_ICON;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>PY_ICON;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile> </ResourceCompile>
<Link> <Link>
<AdditionalDependencies>version.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\PC\launcher.c" /> <ClCompile Include="..\PC\venvlauncher.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\PC\launcher.ico" /> <None Include="..\PC\launcher.ico" />

View File

@ -19,7 +19,7 @@
</ResourceCompile> </ResourceCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\PC\launcher.c"> <ClCompile Include="..\PC\venvlauncher.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>

View File

@ -69,12 +69,13 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}</ProjectGuid> <ProjectGuid>{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}</ProjectGuid>
<RootNamespace>venvwlauncher</RootNamespace> <RootNamespace>venvwlauncher</RootNamespace>
<TargetName>venvwlauncher</TargetName>
<SupportPGO>false</SupportPGO> <SupportPGO>false</SupportPGO>
</PropertyGroup> </PropertyGroup>
<Import Project="python.props" /> <Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration"> <PropertyGroup Label="Configuration">
<TargetName>venvwlauncher</TargetName>
<TargetName Condition="$(DisableGil) == 'true'">$(TargetName)t</TargetName>
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
@ -91,19 +92,19 @@
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<PreprocessorDefinitions>_WINDOWS;VENV_REDIRECT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>EXENAME=L"$(PyExeName)$(PyDebugExt).exe";_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>PYW_ICON;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>PYW_ICON;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile> </ResourceCompile>
<Link> <Link>
<AdditionalDependencies>version.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\PC\launcher.c" /> <ClCompile Include="..\PC\venvlauncher.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\PC\launcher.ico" /> <None Include="..\PC\launcher.ico" />

View File

@ -9,7 +9,7 @@
</Filter> </Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\PC\launcher.c"> <ClCompile Include="..\PC\venvlauncher.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -80,7 +80,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup> <PropertyGroup>
<TargetExt>.pyd</TargetExt> <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup> </PropertyGroup>
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>

View File

@ -22,6 +22,9 @@ if "%~1" EQU "--no-test-marker" (set BUILDTEST=) && shift && goto CheckOpts
if "%~1" EQU "--test-marker" (set BUILDTEST=--test-marker) && shift && goto CheckOpts if "%~1" EQU "--test-marker" (set BUILDTEST=--test-marker) && shift && goto CheckOpts
if "%~1" EQU "--pack" (set BUILDPACK=1) && shift && goto CheckOpts if "%~1" EQU "--pack" (set BUILDPACK=1) && shift && goto CheckOpts
if "%~1" EQU "-r" (set REBUILD=-r) && shift && goto CheckOpts if "%~1" EQU "-r" (set REBUILD=-r) && shift && goto CheckOpts
rem %IncludeFreethreaded% is recognised by the MSI build, but not the regular build.
rem We use it to build twice and then build the installer with its extra option
if /I "%~1" EQU "--disable-gil" (set IncludeFreethreaded=true) && shift && goto CheckOpts
if not defined BUILDX86 if not defined BUILDX64 if not defined BUILDARM64 (set BUILDX86=1) && (set BUILDX64=1) if not defined BUILDX86 if not defined BUILDX64 if not defined BUILDARM64 (set BUILDX86=1) && (set BUILDX64=1)
@ -44,6 +47,20 @@ if errorlevel 1 exit /B %ERRORLEVEL%
if defined BUILDARM64 call "%PCBUILD%build.bat" -p ARM64 -e %REBUILD% %BUILDTEST% if defined BUILDARM64 call "%PCBUILD%build.bat" -p ARM64 -e %REBUILD% %BUILDTEST%
if errorlevel 1 exit /B %ERRORLEVEL% if errorlevel 1 exit /B %ERRORLEVEL%
if /I "%IncludeFreethreaded%"=="true" (
rem Cannot "exit /B" inside an if block because %ERRORLEVEL% will be wrong.
rem We just skip everything after the first "errorlevel 1" and then exit after
if defined BUILDX86 call "%PCBUILD%build.bat" -p Win32 -d -e %REBUILD% %BUILDTEST% --disable-gil
if not errorlevel 1 if defined BUILDX86 call "%PCBUILD%build.bat" -p Win32 -e %REBUILD% %BUILDTEST% --disable-gil
if not errorlevel 1 if defined BUILDX64 call "%PCBUILD%build.bat" -p x64 -d -e %REBUILD% %BUILDTEST% --disable-gil
if not errorlevel 1 if defined BUILDX64 call "%PCBUILD%build.bat" -p x64 -e %REBUILD% %BUILDTEST% --disable-gil
if not errorlevel 1 if defined BUILDARM64 call "%PCBUILD%build.bat" -p ARM64 -d -e %REBUILD% %BUILDTEST% --disable-gil
if not errorlevel 1 if defined BUILDARM64 call "%PCBUILD%build.bat" -p ARM64 -e %REBUILD% %BUILDTEST% --disable-gil
)
if errorlevel 1 exit /B %ERRORLEVEL%
if defined BUILDDOC call "%PCBUILD%..\Doc\make.bat" html if defined BUILDDOC call "%PCBUILD%..\Doc\make.bat" html
if errorlevel 1 exit /B %ERRORLEVEL% if errorlevel 1 exit /B %ERRORLEVEL%

View File

@ -83,6 +83,7 @@
<Checkbox Name="CompileAll" X="185" Y="151" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.PrecompileLabel)</Checkbox> <Checkbox Name="CompileAll" X="185" Y="151" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.PrecompileLabel)</Checkbox>
<Checkbox Name="Include_symbols" X="185" Y="176" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_symbolsLabel)</Checkbox> <Checkbox Name="Include_symbols" X="185" Y="176" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_symbolsLabel)</Checkbox>
<Checkbox Name="Include_debug" X="185" Y="201" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_debugLabel)</Checkbox> <Checkbox Name="Include_debug" X="185" Y="201" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="no">#(loc.Include_debugLabel)</Checkbox>
<Checkbox Name="Include_freethreaded" X="185" Y="226" Width="-11" Height="24" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.Include_freethreadedLabel)</Checkbox>
<Text X="185" Y="256" Width="-11" Height="17" FontId="3">#(loc.CustomLocationLabel)</Text> <Text X="185" Y="256" Width="-11" Height="17" FontId="3">#(loc.CustomLocationLabel)</Text>
<Editbox Name="TargetDir" X="185" Y="277" Width="-101" Height="27" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" /> <Editbox Name="TargetDir" X="185" Y="277" Width="-101" Height="27" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />

View File

@ -91,6 +91,7 @@ Select Customize to review current options.</String>
<String Id="PrecompileLabel">&amp;Precompile standard library</String> <String Id="PrecompileLabel">&amp;Precompile standard library</String>
<String Id="Include_symbolsLabel">Download debugging &amp;symbols</String> <String Id="Include_symbolsLabel">Download debugging &amp;symbols</String>
<String Id="Include_debugLabel">Download debu&amp;g binaries (requires VS 2017 or later)</String> <String Id="Include_debugLabel">Download debu&amp;g binaries (requires VS 2017 or later)</String>
<String Id="Include_freethreadedLabel">Download &amp;free-threaded binaries (experimental)</String>
<String Id="ProgressHeader">[ActionLikeInstallation] Progress</String> <String Id="ProgressHeader">[ActionLikeInstallation] Progress</String>
<String Id="ProgressLabel">[ActionLikeInstalling]:</String> <String Id="ProgressLabel">[ActionLikeInstalling]:</String>

View File

@ -72,6 +72,7 @@
<Package Include="..\tcltk\tcltk*.wixproj" /> <Package Include="..\tcltk\tcltk*.wixproj" />
<Package Include="..\test\test*.wixproj" /> <Package Include="..\test\test*.wixproj" />
<Package Include="..\ucrt\ucrt*.wixproj" Condition="$(Platform) != 'ARM64'" /> <Package Include="..\ucrt\ucrt*.wixproj" Condition="$(Platform) != 'ARM64'" />
<Package Include="..\freethreaded\freethreaded*.wixproj" Condition="$(IncludeFreethreaded) == 'true'" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>

View File

@ -82,6 +82,13 @@
<?endif ?> <?endif ?>
<Variable Name="Include_symbols" Value="0" bal:Overridable="yes" /> <Variable Name="Include_symbols" Value="0" bal:Overridable="yes" />
<Variable Name="Include_debug" Value="0" bal:Overridable="yes" /> <Variable Name="Include_debug" Value="0" bal:Overridable="yes" />
<?if $(var.IncludeFreethreaded)~="true" ?>
<Variable Name="Include_freethreaded" Value="0" bal:Overridable="yes" />
<Variable Name="Include_freethreadedState" Value="enabled" />
<?else ?>
<Variable Name="Include_freethreaded" Value="0" />
<Variable Name="Include_freethreadedState" Value="disable" />
<?endif ?>
<Variable Name="LauncherOnly" Value="0" bal:Overridable="yes" /> <Variable Name="LauncherOnly" Value="0" bal:Overridable="yes" />
<Variable Name="DetectedLauncher" Value="0" /> <Variable Name="DetectedLauncher" Value="0" />
@ -104,6 +111,9 @@
<PackageGroupRef Id="exe" /> <PackageGroupRef Id="exe" />
<PackageGroupRef Id="dev" /> <PackageGroupRef Id="dev" />
<PackageGroupRef Id="lib" /> <PackageGroupRef Id="lib" />
<?if $(var.IncludeFreethreaded)~="true" ?>
<PackageGroupRef Id="freethreaded" />
<?endif ?>
<PackageGroupRef Id="test" /> <PackageGroupRef Id="test" />
<PackageGroupRef Id="doc" /> <PackageGroupRef Id="doc" />
<PackageGroupRef Id="tcltk" /> <PackageGroupRef Id="tcltk" />

View File

@ -0,0 +1,62 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<PackageGroup Id="freethreaded">
<MsiPackage Id="freethreaded_AllUsers"
SourceFile="freethreaded.msi"
Compressed="no"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and (Include_freethreaded) and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="freethreaded_AllUsers_pdb"
SourceFile="freethreaded_pdb.msi"
Compressed="no"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and (Include_freethreaded) and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="freethreaded_AllUsers_d"
SourceFile="freethreaded_d.msi"
Compressed="no"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="yes"
InstallCondition="InstallAllUsers and (Include_freethreaded) and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="freethreaded_JustForMe"
SourceFile="freethreaded.msi"
Compressed="no"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and (Include_freethreaded) and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="freethreaded_JustForMe_pdb"
SourceFile="freethreaded_pdb.msi"
Compressed="no"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and (Include_freethreaded) and Include_symbols and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
<MsiPackage Id="freethreaded_JustForMe_d"
SourceFile="freethreaded_d.msi"
Compressed="no"
DownloadUrl="$(var.DownloadUrl)"
ForcePerMachine="no"
InstallCondition="not InstallAllUsers and (Include_freethreaded) and Include_debug and not LauncherOnly">
<MsiProperty Name="TARGETDIR" Value="[TargetDir]" />
<MsiProperty Name="OPTIONALFEATURESREGISTRYKEY" Value="[OptionalFeaturesRegistryKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
</Wix>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{1B4502D5-B627-4F50-ABEA-4CC5A8E88265}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>freethreaded</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<Import Project="..\msi.props" />
<ItemGroup>
<Compile Include="freethreaded.wxs" />
<Compile Include="freethreaded_files.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
<WxlTemplate Include="*.wxl_template" />
</ItemGroup>
<Import Project="..\msi.targets" />
</Project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="500" Compressed="yes" InstallScope="perUser" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<PropertyRef Id="REGISTRYKEY" />
<Feature Id="DefaultFeature" AllowAdvertise="no" Title="!(loc.Title)" Description="!(loc.Description)">
<ComponentGroupRef Id="freethreaded_reg" Primary="yes" />
<ComponentGroupRef Id="freethreaded_exe" />
<ComponentGroupRef Id="freethreaded_lib_files" />
<ComponentGroupRef Id="freethreaded_lib_extensions" />
<ComponentRef Id="OptionalFeature" />
</Feature>
</Product>
</Wix>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{D3677DCF-098A-4398-9FA5-8E74AC37E0DF}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>freethreaded_d</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<Import Project="..\msi.props" />
<ItemGroup>
<Compile Include="freethreaded_d.wxs" />
<Compile Include="freethreaded_files.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
<WxlTemplate Include="*.wxl_template" />
</ItemGroup>
<Import Project="..\msi.targets" />
</Project>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.Title_d)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="500" Compressed="yes" InstallScope="perUser" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<Feature Id="DebugBinaries" AllowAdvertise="no" Title="!(loc.Title_d)" Description="!(loc.Description_d)">
<ComponentGroupRef Id="freethreaded_dll_d" />
<ComponentGroupRef Id="freethreaded_exe_d" />
<ComponentGroupRef Id="freethreaded_lib_extensions_d" />
<ComponentRef Id="OptionalFeature" />
</Feature>
</Product>
</Wix>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="Descriptor">Freethreaded Interpreter</String>
<String Id="ShortDescriptor">freethreaded</String>
<String Id="ShortcutName">Python {{ShortVersion}} ({{Bitness}}, freethreaded)</String>
<String Id="ShortcutDescription">Launches the !(loc.ProductName) freethreaded interpreter.</String>
<String Id="SupportUrl">https://www.python.org/</String>
</WixLocalization>

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<Property Id="FREETHREADED_REGISTRYKEY" Value="Software\Python\PythonCore\$(var.ShortVersion)t$(var.PyArchExt)$(var.PyTestExt)" />
<ComponentGroup Id="freethreaded_reg">
<Component Id="PythonRegistration" Directory="InstallDirectory" Guid="$(var.PythonRegComponentGuid)">
<RegistryKey Root="HKMU" Key="[FREETHREADED_REGISTRYKEY]">
<RegistryValue Name="DisplayName" Type="string" Value="!(loc.ShortcutName)" KeyPath="yes" />
<RegistryValue Name="SupportUrl" Type="string" Value="!(loc.SupportUrl)" KeyPath="no" />
<RegistryValue Name="Version" Type="string" Value="$(var.LongVersion)" KeyPath="no" />
<RegistryValue Name="SysVersion" Type="string" Value="$(var.ShortVersion)" KeyPath="no" />
<RegistryValue Name="SysArchitecture" Type="string" Value="$(var.PlatformArchitecture)" KeyPath="no" />
</RegistryKey>
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<DirectoryRef Id="Lib">
<Directory Id="Lib_venv__freethreaded" Name="venv">
<Directory Id="Lib_venv_scripts__freethreaded" Name="scripts">
<Directory Id="Lib_venv_scripts_nt__freethreaded" Name="nt" />
</Directory>
</Directory>
</DirectoryRef>
</Fragment>
<Fragment>
<PropertyRef Id="FREETHREADED_REGISTRYKEY" />
<ComponentGroup Id="freethreaded_exe">
<Component Id="freethreaded_python.exe" Directory="InstallDirectory" Guid="$(var.FreethreadedPythonExeComponentGuid)">
<File Name="python$(var.ShortVersion)t.exe" KeyPath="yes" />
<RegistryKey Root="HKMU" Key="[FREETHREADED_REGISTRYKEY]">
<RegistryValue Key="InstallPath" Type="string" Value="[InstallDirectory]" KeyPath="no" />
<RegistryValue Key="InstallPath" Name="ExecutablePath" Type="string" Value="[#python$(var.ShortVersion)t.exe]" KeyPath="no" />
</RegistryKey>
</Component>
<Component Id="freethreaded_pythonw.exe" Directory="InstallDirectory" Guid="$(var.FreethreadedPythonwExeComponentGuid)">
<File Name="pythonw$(var.ShortVersion)t.exe" KeyPath="yes" />
<RegistryKey Root="HKMU" Key="[FREETHREADED_REGISTRYKEY]">
<RegistryValue Key="InstallPath" Name="WindowedExecutablePath" Type="string" Value="[#pythonw$(var.ShortVersion)t.exe]" KeyPath="no" />
</RegistryKey>
</Component>
<Component Id="freethreaded_python_stable.dll" Directory="InstallDirectory" Guid="*">
<File Id="freethreaded_python_stable.dll" Name="python$(var.MajorVersionNumber)t.dll" KeyPath="yes" />
</Component>
<Component Id="freethreaded_python.dll" Directory="InstallDirectory" Guid="*">
<File Id="freethreaded_python.dll" Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber)t.dll" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="freethreaded_symbols">
<Component Id="freethreaded_python_dll.pdb" Directory="InstallDirectory" Guid="*">
<File Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber)t.pdb" KeyPath="yes" />
</Component>
<Component Id="freethreaded_python.pdb" Directory="InstallDirectory" Guid="*">
<File Name="python$(var.ShortVersion)t.pdb" />
</Component>
<Component Id="freethreaded_pythonw.pdb" Directory="InstallDirectory" Guid="*">
<File Name="pythonw$(var.ShortVersion)t.pdb" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="freethreaded_dll_d">
<Component Id="freethreaded_python_stable_d.dll" Directory="InstallDirectory" Guid="*">
<File Id="freethreaded_python_stable_d.dll" Name="python$(var.MajorVersionNumber)t_d.dll" KeyPath="yes" />
</Component>
<Component Id="freethreaded_python_d.dll" Directory="InstallDirectory" Guid="*">
<File Id="freethreaded_python_d.dll" Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber)_d.dll" KeyPath="yes" />
<File Id="freethreaded_python_d.pdb" Name="python$(var.MajorVersionNumber)$(var.MinorVersionNumber)_d.pdb" KeyPath="no" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="freethreaded_exe_d">
<Component Id="freethreaded_python_d.exe" Directory="InstallDirectory" Guid="*">
<File Name="python$(var.ShortVersion)t_d.exe" />
</Component>
<Component Id="freethreaded_python_d.pdb" Directory="InstallDirectory" Guid="*">
<File Name="python$(var.ShortVersion)t_d.pdb" />
</Component>
<Component Id="freethreaded_pythonw_d.exe" Directory="InstallDirectory" Guid="*">
<File Name="pythonw$(var.ShortVersion)t_d.exe" />
</Component>
<Component Id="freethreaded_pythonw_d.pdb" Directory="InstallDirectory" Guid="*">
<File Name="pythonw$(var.ShortVersion)t_d.pdb" />
</Component>
</ComponentGroup>
</Fragment>
<?define exts=pyexpat;select;unicodedata;winsound;_bz2;_elementtree;_socket;_ssl;_ctypes;_hashlib;_multiprocessing;_lzma;_decimal;_overlapped;_sqlite3;_asyncio;_queue;_uuid;_wmi;_zoneinfo;_testcapi;_ctypes_test;_testbuffer;_testimportmultiple;_testmultiphase;_testsinglephase;_testconsole;_testinternalcapi;_testclinic;_testclinic_limited ?>
<Fragment>
<DirectoryRef Id="Lib_venv_scripts_nt__freethreaded" />
<ComponentGroup Id="freethreaded_lib_extensions">
<?foreach ext in $(var.exts)?>
<Component Id="freethreaded_$(var.ext).pyd" Directory="DLLs" Guid="*">
<File Name="$(var.ext)$(var.FreethreadedPydTag).pyd" KeyPath="yes" />
</Component>
<?endforeach ?>
<Component Id="venvlaunchert.exe" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="venvlaunchert.exe" KeyPath="yes" />
</Component>
<Component Id="venvwlaunchert.exe" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="venvwlaunchert.exe" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<DirectoryRef Id="Lib_venv_scripts_nt__freethreaded" />
<ComponentGroup Id="freethreaded_lib_extensions_symbols">
<?foreach ext in $(var.exts)?>
<Component Id="freethreaded_$(var.ext).pdb" Directory="DLLs" Guid="*">
<File Name="$(var.ext)$(var.FreethreadedPydTag).pdb" />
</Component>
<?endforeach ?>
<Component Id="venvlaunchert.pdb" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="venvlaunchert.pdb" KeyPath="yes" />
</Component>
<Component Id="venvwlaunchert.pdb" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="venvwlaunchert.pdb" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<ComponentGroup Id="freethreaded_lib_extensions_d">
<?foreach ext in $(var.exts)?>
<Component Id="freethreaded_$(var.ext)_d.pyd" Directory="DLLs" Guid="*">
<File Name="$(var.ext)_d$(var.FreethreadedPydTag).pyd" />
</Component>
<Component Id="freethreaded_$(var.ext)_d.pdb" Directory="DLLs" Guid="*">
<File Name="$(var.ext)_d$(var.FreethreadedPydTag).pdb" />
</Component>
<?endforeach ?>
<Component Id="venvlauncher_d.exe" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="python_d.exe" Source="venvlauncher_d.exe" KeyPath="yes" />
</Component>
<Component Id="venvwlauncher_d.exe" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="pythonw_d.exe" Source="venvwlauncher_d.exe" KeyPath="yes" />
</Component>
<Component Id="venvlaunchert_d.pdb" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="venvlaunchert_d.pdb" KeyPath="yes" />
</Component>
<Component Id="venvwlaunchert_d.pdb" Directory="Lib_venv_scripts_nt__freethreaded" Guid="*">
<File Name="venvwlaunchert_d.pdb" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment>
<PropertyRef Id="FREETHREADED_REGISTRYKEY" />
<ComponentGroup Id="freethreaded_lib_files">
<Component Id="PythonPathRegistry" Directory="Lib" Guid="*">
<RegistryKey Root="HKMU" Key="[FREETHREADED_REGISTRYKEY]">
<RegistryValue Key="PythonPath" Type="string" Value="[Lib];[DLLs]" />
</RegistryKey>
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{E98E7539-64E7-4DCE-AACD-01E3ADE40EFD}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>freethreaded_pdb</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<Import Project="..\msi.props" />
<ItemGroup>
<Compile Include="freethreaded_pdb.wxs" />
<Compile Include="freethreaded_files.wxs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="*.wxl" />
<WxlTemplate Include="*.wxl_template" />
</ItemGroup>
<Import Project="..\msi.targets" />
</Project>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Language="!(loc.LCID)" Name="!(loc.TitlePdb)" Version="$(var.Version)" Manufacturer="!(loc.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="500" Compressed="yes" InstallScope="perUser" />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<PropertyRef Id="UpgradeTable" />
<Feature Id="Symbols" AllowAdvertise="no" Title="!(loc.TitlePdb)" Description="!(loc.DescriptionPdb)">
<ComponentGroupRef Id="freethreaded_symbols" />
<ComponentGroupRef Id="freethreaded_lib_extensions_symbols" />
<ComponentRef Id="OptionalFeature" />
</Feature>
</Product>
</Wix>

View File

@ -26,10 +26,10 @@
<File Name="libffi-8.dll" KeyPath="yes" /> <File Name="libffi-8.dll" KeyPath="yes" />
</Component> </Component>
<Component Id="venvlauncher.exe" Directory="Lib_venv_scripts_nt" Guid="*"> <Component Id="venvlauncher.exe" Directory="Lib_venv_scripts_nt" Guid="*">
<File Name="python.exe" Source="venvlauncher.exe" KeyPath="yes" /> <File Name="venvlauncher.exe" KeyPath="yes" />
</Component> </Component>
<Component Id="venvwlauncher.exe" Directory="Lib_venv_scripts_nt" Guid="*"> <Component Id="venvwlauncher.exe" Directory="Lib_venv_scripts_nt" Guid="*">
<File Name="pythonw.exe" Source="venvwlauncher.exe" KeyPath="yes" /> <File Name="venvwlauncher.exe" KeyPath="yes" />
</Component> </Component>
</ComponentGroup> </ComponentGroup>
</Fragment> </Fragment>
@ -63,10 +63,10 @@
<File Name="libssl$(var.ssltag).pdb" KeyPath="yes" /> <File Name="libssl$(var.ssltag).pdb" KeyPath="yes" />
</Component> </Component>
<Component Id="venvlauncher.pdb" Directory="Lib_venv_scripts_nt__pdbs" Guid="*"> <Component Id="venvlauncher.pdb" Directory="Lib_venv_scripts_nt__pdbs" Guid="*">
<File Name="python.pdb" Source="venvlauncher.pdb" KeyPath="yes" /> <File Name="venvlauncher.pdb" KeyPath="yes" />
</Component> </Component>
<Component Id="venvwlauncher.pdb" Directory="Lib_venv_scripts_nt__pdbs" Guid="*"> <Component Id="venvwlauncher.pdb" Directory="Lib_venv_scripts_nt__pdbs" Guid="*">
<File Name="pythonw.pdb" Source="venvwlauncher.pdb" KeyPath="yes" /> <File Name="venvwlauncher.pdb" KeyPath="yes" />
</Component> </Component>
</ComponentGroup> </ComponentGroup>
</Fragment> </Fragment>
@ -100,10 +100,10 @@
<File Name="sqlite3_d.pdb" KeyPath="yes" /> <File Name="sqlite3_d.pdb" KeyPath="yes" />
</Component> </Component>
<Component Id="venvlauncher_d.exe" Directory="Lib_venv_scripts_nt__d" Guid="*"> <Component Id="venvlauncher_d.exe" Directory="Lib_venv_scripts_nt__d" Guid="*">
<File Name="python_d.exe" Source="venvlauncher_d.exe" KeyPath="yes" /> <File Name="venvlauncher_d.exe" KeyPath="yes" />
</Component> </Component>
<Component Id="venvwlauncher_d.exe" Directory="Lib_venv_scripts_nt__d" Guid="*"> <Component Id="venvwlauncher_d.exe" Directory="Lib_venv_scripts_nt__d" Guid="*">
<File Name="pythonw_d.exe" Source="venvwlauncher_d.exe" KeyPath="yes" /> <File Name="venvwlauncher_d.exe" KeyPath="yes" />
</Component> </Component>
</ComponentGroup> </ComponentGroup>
</Fragment> </Fragment>

View File

@ -24,14 +24,14 @@
This URI is used to generate the various GUIDs used by the installer. This URI is used to generate the various GUIDs used by the installer.
Installers built with the same URI will upgrade each other or block Installers built with the same URI will upgrade each other or block
when attempting to downgrade. when attempting to downgrade.
By default, this is the local computer name, which will produce By default, this is the local computer name, which will produce
installers that do not interfere with other installers. Products installers that do not interfere with other installers. Products
that intend to bundle Python should rebuild these modules with their that intend to bundle Python should rebuild these modules with their
own URI to avoid conflicting with the official releases. own URI to avoid conflicting with the official releases.
The official releases use "https://www.python.org/$(ArchName)" The official releases use "https://www.python.org/$(ArchName)"
This is not the same as the DownloadUrl property used in the bundle This is not the same as the DownloadUrl property used in the bundle
projects. projects.
--> -->
@ -39,7 +39,7 @@
<ReleaseUri Condition="!$(ReleaseUri.EndsWith(`/`))">$(ReleaseUri)/</ReleaseUri> <ReleaseUri Condition="!$(ReleaseUri.EndsWith(`/`))">$(ReleaseUri)/</ReleaseUri>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)common.wxs" /> <Compile Include="$(MSBuildThisFileDirectory)common.wxs" />
<WxlTemplate Include="$(MSBuildThisFileDirectory)\*.wxl_template" Condition="$(IgnoreCommonWxlTemplates) != 'true'" /> <WxlTemplate Include="$(MSBuildThisFileDirectory)\*.wxl_template" Condition="$(IgnoreCommonWxlTemplates) != 'true'" />
@ -63,13 +63,17 @@
<InstallerVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(Field3Value).0</InstallerVersion> <InstallerVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(Field3Value).0</InstallerVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<IncludeFreethreaded Condition="$(IncludeFreethreaded) != 'true'">false</IncludeFreethreaded>
</PropertyGroup>
<PropertyGroup Condition="!$(BuildForRelease)"> <PropertyGroup Condition="!$(BuildForRelease)">
<RevisionNumber Condition="'$(RevisionNumber)' == ''">$([System.Math]::Floor($([System.DateTime]::Now.Subtract($([System.DateTime]::new(2001, 1, 1))).TotalDays)))</RevisionNumber> <RevisionNumber Condition="'$(RevisionNumber)' == ''">$([System.Math]::Floor($([System.DateTime]::Now.Subtract($([System.DateTime]::new(2001, 1, 1))).TotalDays)))</RevisionNumber>
<PythonVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)dev$(RevisionNumber)</PythonVersion> <PythonVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(MicroVersionNumber)dev$(RevisionNumber)</PythonVersion>
<InstallerVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(RevisionNumber).0</InstallerVersion> <InstallerVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(RevisionNumber).0</InstallerVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<Bitness>32-bit</Bitness> <Bitness>32-bit</Bitness>
<Bitness Condition="$(Platform) == 'x64'">64-bit</Bitness> <Bitness Condition="$(Platform) == 'x64'">64-bit</Bitness>
@ -91,9 +95,12 @@
PyDebugExt=$(PyDebugExt); PyDebugExt=$(PyDebugExt);
PyArchExt=$(PyArchExt); PyArchExt=$(PyArchExt);
PyTestExt=$(PyTestExt); PyTestExt=$(PyTestExt);
PydTag=$(PydTag);
FreethreadedPydTag=$(FreethreadedPydTag);
OptionalFeatureName=$(OutputName); OptionalFeatureName=$(OutputName);
ssltag=$(OpenSSLDLLSuffix); ssltag=$(OpenSSLDLLSuffix);
Suffix32=$(PyArchExt); Suffix32=$(PyArchExt);
IncludeFreethreaded=$(IncludeFreethreaded);
</DefineConstants> </DefineConstants>
<DefineConstants Condition="'$(CRTRedist)' != ''"> <DefineConstants Condition="'$(CRTRedist)' != ''">
$(DefineConstants);CRTRedist=$(CRTRedist); $(DefineConstants);CRTRedist=$(CRTRedist);
@ -139,7 +146,7 @@
<Error Text="Platform '$(Platform)' is not supported. Use 'x86', 'x64' or 'ARM64'." <Error Text="Platform '$(Platform)' is not supported. Use 'x86', 'x64' or 'ARM64'."
Condition="$(Platform) != 'x86' and $(Platform) != 'x64' and $(Platform) != 'ARM64'" /> Condition="$(Platform) != 'x86' and $(Platform) != 'x64' and $(Platform) != 'ARM64'" />
</Target> </Target>
<ItemGroup> <ItemGroup>
<_Uuid Include="CoreUpgradeCode"> <_Uuid Include="CoreUpgradeCode">
<Uri>upgradecode</Uri> <Uri>upgradecode</Uri>
@ -162,6 +169,12 @@
<_Uuid Include="PythonRegComponentGuid"> <_Uuid Include="PythonRegComponentGuid">
<Uri>registry/$(OutputName)</Uri> <Uri>registry/$(OutputName)</Uri>
</_Uuid> </_Uuid>
<_Uuid Include="FreethreadedPythonExeComponentGuid" Condition="$(IncludeFreethreaded)">
<Uri>freethreaded/python.exe</Uri>
</_Uuid>
<_Uuid Include="FreethreadedPythonwExeComponentGuid" Condition="$(IncludeFreethreaded)">
<Uri>freethreaded/pythonw.exe</Uri>
</_Uuid>
</ItemGroup> </ItemGroup>
<Target Name="_GenerateGuids" <Target Name="_GenerateGuids"
AfterTargets="PrepareForBuild" AfterTargets="PrepareForBuild"
@ -171,15 +184,15 @@
<_Uuids>@(_Uuid->'("%(Identity)", "$(MajorVersionNumber).$(MinorVersionNumber)/%(Uri)")',',')</_Uuids> <_Uuids>@(_Uuid->'("%(Identity)", "$(MajorVersionNumber).$(MinorVersionNumber)/%(Uri)")',',')</_Uuids>
<_GenerateCommand>import uuid; print('\n'.join('{}={}'.format(i, uuid.uuid5(uuid.UUID('c8d9733e-a70c-43ff-ab0c-e26456f11083'), '$(ReleaseUri.Replace(`{arch}`, `$(ArchName)`))' + j)) for i,j in [$(_Uuids.Replace(`"`,`'`))]))</_GenerateCommand> <_GenerateCommand>import uuid; print('\n'.join('{}={}'.format(i, uuid.uuid5(uuid.UUID('c8d9733e-a70c-43ff-ab0c-e26456f11083'), '$(ReleaseUri.Replace(`{arch}`, `$(ArchName)`))' + j)) for i,j in [$(_Uuids.Replace(`"`,`'`))]))</_GenerateCommand>
</PropertyGroup> </PropertyGroup>
<Exec Command='$(PythonForBuild) -c "$(_GenerateCommand)" &gt; "$(IntermediateOutputPath)$(OutputName)guids.txt"' <Exec Command='$(PythonForBuild) -c "$(_GenerateCommand)" &gt; "$(IntermediateOutputPath)$(OutputName)guids.txt"'
WorkingDirectory="$(MSBuildThisFileDirectory)" WorkingDirectory="$(MSBuildThisFileDirectory)"
IgnoreExitCode="false" /> IgnoreExitCode="false" />
<ReadLinesFromFile File="$(IntermediateOutputPath)$(OutputName)guids.txt"> <ReadLinesFromFile File="$(IntermediateOutputPath)$(OutputName)guids.txt">
<Output TaskParameter="Lines" ItemName="_UuidValue" /> <Output TaskParameter="Lines" ItemName="_UuidValue" />
</ReadLinesFromFile> </ReadLinesFromFile>
<PropertyGroup> <PropertyGroup>
<DefineConstants>$(DefineConstants);@(_UuidValue,';');</DefineConstants> <DefineConstants>$(DefineConstants);@(_UuidValue,';');</DefineConstants>
</PropertyGroup> </PropertyGroup>