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:
matrix:
type: [x86, x64, arm64]
env:
IncludeFreethreaded: true
steps:
- uses: actions/checkout@v4
- name: Build CPython installer

View File

@ -20,7 +20,7 @@ jobs:
- name: Display build info
run: .\python.bat -m test.pythoninfo
- 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:
name: 'build and test (x64)'
@ -37,7 +37,7 @@ jobs:
- name: Display build info
run: .\python.bat -m test.pythoninfo
- 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:
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
: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:
@ -450,9 +490,29 @@ automatically use the headers and import libraries in your build.
The package information pages on nuget.org are
`www.nuget.org/packages/python <https://www.nuget.org/packages/python>`_
for the 64-bit version and `www.nuget.org/packages/pythonx86
<https://www.nuget.org/packages/pythonx86>`_ for the 32-bit version.
for the 64-bit version, `www.nuget.org/packages/pythonx86
<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:

View File

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

View File

@ -19,8 +19,10 @@ import winreg
PY_EXE = "py.exe"
DEBUG_BUILD = False
if sys.executable.casefold().endswith("_d.exe".casefold()):
PY_EXE = "py_d.exe"
DEBUG_BUILD = True
# Registry data to create. On removal, everything beneath top-level names will
# be deleted.
@ -232,7 +234,7 @@ class RunPyMixin:
p.stdin.close()
p.wait(10)
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:
print("++ COMMAND ++")
print([self.py_exe, *args])
@ -273,7 +275,7 @@ class RunPyMixin:
def fake_venv(self):
venv = Path.cwd() / "Scripts"
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()
try:
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))
break
else:
if support.verbose:
print(data["stdout"])
print(data["stderr"])
self.fail("did not find active venv path")
data = self.run_py(["-0"], env=env)
@ -616,25 +621,29 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
self.assertEqual("True", data["SearchInfo.oldStyleTag"])
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.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(
[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):
# 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.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(
[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):
stem = self.get_py_exe().stem
@ -727,15 +736,18 @@ class TestLauncher(unittest.TestCase, RunPyMixin):
data = self.run_py([script], expect_returncode=103)
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
# 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:
data = self.run_py([script], env=env)
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)
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
if not support.Py_DEBUG:
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)
@unittest.skipUnless(sys.platform == 'win32', 'Windows only')
@ -862,6 +864,8 @@ class ProgramsTestCase(BaseTestCase):
rt_args.append('-x64') # 64-bit build
if support.Py_DEBUG:
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)

View File

@ -223,8 +223,14 @@ class BasicTest(BaseTest):
def test_upgrade_dependencies(self):
builder = venv.EnvBuilder()
bin_path = 'Scripts' if sys.platform == 'win32' else 'bin'
bin_path = 'bin'
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:
expect_exe = os.path.normcase(
os.path.join(fake_env_dir, bin_path, python_exe)
@ -283,7 +289,9 @@ class BasicTest(BaseTest):
# build environment
('is_python_build()', str(sysconfig.is_python_build())),
('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):
cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
out, err = check_output(cmd, encoding='utf-8')
@ -315,7 +323,9 @@ class BasicTest(BaseTest):
# build environment
('is_python_build()', str(sysconfig.is_python_build())),
('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):
cmd[2] = 'import sysconfig; print(sysconfig.%s)' % call
out, err = check_output(cmd, encoding='utf-8')

View File

@ -139,6 +139,11 @@ class EnvBuilder:
'check that your PATH environment variable is '
'correctly set.')
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.python_dir = dirname
context.python_exe = exename
@ -222,67 +227,26 @@ class EnvBuilder:
args = ' '.join(args)
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):
"""
Try symlinking a file, and if that fails, fall back to copying.
"""
force_copy = not self.symlinks
if not force_copy:
try:
if not os.path.islink(dst): # can't link to itself!
if relative_symlinks_ok:
assert os.path.dirname(src) == os.path.dirname(dst)
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:
def symlink_or_copy(self, src, dst, relative_symlinks_ok=False):
"""
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.)
"""
assert os.name != 'nt'
force_copy = not self.symlinks
if not force_copy:
try:
if not os.path.islink(dst): # can't link to itself!
if relative_symlinks_ok:
assert os.path.dirname(src) == os.path.dirname(dst)
os.symlink(os.path.basename(src), dst)
else:
os.symlink(src, dst)
return
except Exception: # may need to use a more specific exception
logger.warning('Unable to symlink %r to %r', src, dst)
# 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
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)
def create_git_ignore_file(self, context):
@ -298,22 +262,23 @@ class EnvBuilder:
'see https://docs.python.org/3/library/venv.html\n')
file.write('*\n')
def setup_python(self, context):
"""
Set up a Python executable in the environment.
if os.name != 'nt':
def setup_python(self, context):
"""
Set up a Python executable in the environment.
:param context: The information for the environment creation request
being processed.
"""
binpath = context.bin_path
path = context.env_exe
copier = self.symlink_or_copy
dirname = context.python_dir
if os.name != 'nt':
:param context: The information for the environment creation request
being processed.
"""
binpath = context.bin_path
path = context.env_exe
copier = self.symlink_or_copy
dirname = context.python_dir
copier(context.executable, path)
if not os.path.islink(path):
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)
if not os.path.exists(path):
# Issue 18807: make copies if
@ -321,30 +286,105 @@ class EnvBuilder:
copier(context.env_exe, path, relative_symlinks_ok=True)
if not os.path.islink(path):
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:
src = os.path.join(dirname, suffix)
if os.path.lexists(src):
copier(src, os.path.join(binpath, suffix))
else:
def setup_python(self, context):
"""
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():
# copy init.tcl
@ -437,6 +477,14 @@ class EnvBuilder:
"""
binpath = context.bin_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):
if root == path: # at top-level, remove irrelevant dirs
for d in dirs[:]:
@ -444,8 +492,7 @@ class EnvBuilder:
dirs.remove(d)
continue # ignore files in top level
for f in files:
if (os.name == 'nt' and f.startswith('python')
and f.endswith(('.exe', '.pdb'))):
if skip_file(f):
continue
srcfile = os.path.join(root, f)
suffix = root[plen:].split(os.sep)[2:]
@ -456,20 +503,25 @@ class EnvBuilder:
if not os.path.exists(dstdir):
os.makedirs(dstdir)
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:
data = f.read()
if not srcfile.endswith(('.exe', '.pdb')):
try:
data = data.decode('utf-8')
data = self.replace_variables(data, context)
data = data.encode('utf-8')
except UnicodeError as e:
data = None
logger.warning('unable to copy script %r, '
'may be binary: %s', srcfile, e)
if data is not None:
try:
new_data = (
self.replace_variables(data.decode('utf-8'), context)
.encode('utf-8')
)
except UnicodeError as e:
logger.warning('unable to copy script %r, '
'may be binary: %s', srcfile, e)
continue
if new_data == data:
shutil.copy2(srcfile, dstfile)
else:
with open(dstfile, 'wb') as f:
f.write(data)
f.write(new_data)
shutil.copymode(srcfile, dstfile)
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")
EXCLUDE_FROM_PYDS = FileStemSet("python*", "pyshellext", "vcruntime*")
EXCLUDE_FROM_DLLS = FileStemSet("python*", "pyshellext", "vcruntime*")
EXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle")
EXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt")
EXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*")
@ -126,9 +126,9 @@ def get_layout(ns):
n = new_name or n
src = ns.build / f
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)
if not n.endswith("_d"):
if "_d." not in f:
n += "_d"
f = n + "." + x
yield dest + n + "." + x, src
@ -141,17 +141,45 @@ def get_layout(ns):
if lib.is_file():
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:
yield from in_build("python_uwp.exe", new_name="python{}".format(VER_DOT))
yield from in_build("pythonw_uwp.exe", new_name="pythonw{}".format(VER_DOT))
# For backwards compatibility, but we don't reference these ourselves.
yield from in_build("python_uwp.exe", new_name="python")
yield from in_build("pythonw_uwp.exe", new_name="pythonw")
else:
yield from in_build("python.exe", new_name="python")
yield from in_build("pythonw.exe", new_name="pythonw")
source = "python_uwp.exe"
sourcew = "pythonw_uwp.exe"
elif ns.include_freethreaded:
source = "python{}t.exe".format(VER_DOT)
sourcew = "pythonw{}t.exe".format(VER_DOT)
if not ns.include_alias:
alias = []
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_pip:
@ -160,7 +188,10 @@ def get_layout(ns):
yield from in_build("pythonw_uwp.exe", new_name="idle{}".format(VER_DOT))
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
for dest, src in rglob(ns.build, "vcruntime*.dll"):
@ -171,16 +202,28 @@ def get_layout(ns):
yield "LICENSE.txt", ns.build / "LICENSE.txt"
for dest, src in rglob(ns.build, ("*.pyd", "*.dll")):
if src.stem.endswith("_d") != bool(ns.debug) and src not in REQUIRED_DLLS:
continue
if src in EXCLUDE_FROM_PYDS:
continue
for dest, src in rglob(ns.build, "*.pyd"):
if ns.include_freethreaded:
if not src.match("*.cp*t-win*.pyd"):
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:
continue
if src in TCLTK_PYDS_ONLY and not ns.include_tcltk:
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/")
if ns.zip_lib:
@ -191,8 +234,12 @@ def get_layout(ns):
yield "Lib/{}".format(dest), src
if ns.include_venv:
yield from in_build("venvlauncher.exe", "Lib/venv/scripts/nt/", "python")
yield from in_build("venvwlauncher.exe", "Lib/venv/scripts/nt/", "pythonw")
if ns.include_freethreaded:
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:
@ -208,7 +255,6 @@ def get_layout(ns):
yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAME
if ns.include_dev:
for dest, src in rglob(ns.source / "Include", "**/*.h"):
yield "include/{}".format(dest), src
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.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")
if not ns.source.is_absolute():
ns.source = (Path.cwd() / ns.source).resolve()
@ -565,7 +610,12 @@ def main():
if ns.include_cat and not ns.include_cat.is_absolute():
ns.include_cat = (Path.cwd() / ns.include_cat).resolve()
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():
ns.copy = (Path.cwd() / ns.copy).resolve()
@ -574,6 +624,14 @@ def main():
if ns.catalog and not ns.catalog.is_absolute():
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)
log_info(
@ -602,6 +660,12 @@ Catalog: {ns.catalog}""",
log_warning("Assuming --include-tcltk to support --include-idle")
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:
generate_source_files(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(
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"),
arm32=("ARM", "pythonarm", "Python (ARM)"),
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"]:
@ -58,7 +62,10 @@ NUSPEC_TEMPLATE = r"""<?xml version="1.0"?>
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)
if ev:
yield k, ev

View File

@ -32,6 +32,10 @@ OPTIONS = {
"nuspec": {"help": "a python.nuspec file"},
"chm": {"help": "the CHM 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",
"launchers",
"appxmanifest",
"alias",
"alias3x",
# XXX: Disabled for now "precompile",
],
},
@ -59,9 +65,10 @@ PRESETS = {
"venv",
"props",
"nuspec",
"alias",
],
},
"iot": {"help": "Windows IoT Core", "options": ["stable", "pip"]},
"iot": {"help": "Windows IoT Core", "options": ["alias", "stable", "pip"]},
"default": {
"help": "development kit package",
"options": [
@ -74,11 +81,19 @@ PRESETS = {
"dev",
"symbols",
"html-doc",
"alias",
],
},
"embed": {
"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 /* 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 */
/* ------------------------------------------------------------------------*/
@ -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 */
# if defined(_MSC_VER)
/* So MSVC users need not specify the .lib
file in their Makefile (other compilers are
generally taken care of by distutils.) */
file in their Makefile */
# 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)
# pragma comment(lib,"python313_d.lib")
# 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
# pragma comment(lib,"python313.lib")
# endif /* _DEBUG */
# endif /* Py_GIL_DISABLED */
# endif /* _MSC_VER */
# endif /* Py_BUILD_CORE */
#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 HAVE_X509_VERIFY_PARAM_SET1_HOST 1
/* Define if you want to disable the GIL */
#undef Py_GIL_DISABLED
#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>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<TargetExt>.pyd</TargetExt>
<TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -24,6 +24,13 @@
<LinkIncremental Condition="$(Configuration) != 'Debug'">false</LinkIncremental>
</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) != ''">
<_VCToolsVersion>$([System.Version]::Parse(`$(VCToolsVersion)`).Major).$([System.Version]::Parse(`$(VCToolsVersion)`).Minor)</_VCToolsVersion>
@ -38,7 +45,7 @@
<_PlatformPreprocessorDefinition>_WIN32;</_PlatformPreprocessorDefinition>
<_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64'">_WIN64;</_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>
<ItemDefinitionGroup>
<ClCompile>
@ -158,8 +165,8 @@ public override bool Execute() {
</UsingTask>
<Target Name="KillPython" BeforeTargets="PrepareForBuild" Condition="'$(KillPython)' == 'true'">
<Message Text="Killing any running python$(PyDebugExt)$(PyTestExt).exe instances..." Importance="high" />
<KillPython FileName="$(OutDir)python$(PyDebugExt)$(PyTestExt).exe" />
<Message Text="Killing any running $(PyExeName)$(PyDebugExt)$(PyTestExt).exe instances..." Importance="high" />
<KillPython FileName="$(OutDir)$(PyExeName)$(PyDebugExt)$(PyTestExt).exe" />
</Target>
<!--

View File

@ -31,11 +31,11 @@
<ArchName Condition="'$(ArchName)' == '' and $(Platform) == 'ARM'">arm32</ArchName>
<ArchName Condition="'$(ArchName)' == '' and $(Platform) == 'ARM64'">arm64</ArchName>
<ArchName Condition="'$(ArchName)' == ''">win32</ArchName>
<!-- Root directory of the repository -->
<PySourcePath Condition="'$(PySourcePath)' == ''">$([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\))</PySourcePath>
<PySourcePath Condition="!HasTrailingSlash($(PySourcePath))">$(PySourcePath)\</PySourcePath>
<!-- Directory where build outputs are put -->
<BuildPath32 Condition="'$(Py_OutDir)' == ''">$(PySourcePath)PCbuild\win32\</BuildPath32>
<BuildPath32 Condition="'$(Py_OutDir)' != ''">$(Py_OutDir)\win32\</BuildPath32>
@ -52,7 +52,7 @@
<BuildPath Condition="'$(BuildPath)' == ''">$(PySourcePath)PCbuild\$(ArchName)\</BuildPath>
<BuildPath Condition="!HasTrailingSlash($(BuildPath))">$(BuildPath)\</BuildPath>
<BuildPath Condition="$(Configuration) == 'PGInstrument'">$(BuildPath)instrumented\</BuildPath>
<!-- VPATH definition (escaped) -->
<PyVPath Condition="$(Configuration) != 'PGInstrument'">..\\..</PyVPath>
<PyVPath Condition="$(Configuration) == 'PGInstrument'">..\\..\\..</PyVPath>
@ -84,22 +84,19 @@
<PropertyGroup>
<!-- Suffix for all binaries when building for debug -->
<PyDebugExt Condition="'$(PyDebugExt)' == '' and $(Configuration) == 'Debug'">_d</PyDebugExt>
<!-- Suffix for versions/keys when building with test markers -->
<PyTestExt Condition="$(UseTestMarker) == 'true'">-test</PyTestExt>
<!-- Suffix for versions/keys when building for particular platforms -->
<PyArchExt Condition="'$(ArchName)' == 'win32'">-32</PyArchExt>
<PyArchExt Condition="'$(ArchName)' == 'arm32'">-arm32</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 -->
<IncludeTkinter Condition="'$(IncludeTkinter)' == ''">true</IncludeTkinter>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM'" Label="ArmConfiguration">
<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
</PropertyGroup>
@ -141,7 +138,7 @@
<PropertyGroup Condition="'$(OverrideVersion)' == ''">
<!--
Read version information from Include\patchlevel.h. The following properties are set:
MajorVersionNumber - the '3' in '3.5.2a1'
MinorVersionNumber - the '5' 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) == 'GAMMA'">rc$(ReleaseSerial)</ReleaseLevelName>
</PropertyGroup>
<PropertyGroup Condition="'$(OverrideVersion)' != ''">
<!--
Override the version number when building by specifying OverrideVersion.
For example:
PCbuild\build.bat "/p:OverrideVersion=3.5.2a1"
Use the -V option to check your version is valid:
PCbuild\build.bat -V "/p:OverrideVersion=3.5.2a1"
PythonVersionNumber: 3.5.2
PythonVersion: 3.5.2a1
PythonVersionHex: 0x030502A1
Field3Value: 2101
Note that this only affects the version numbers embedded in resources and
installers, but not sys.version.
-->
@ -223,22 +220,55 @@
))
))</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) -->
<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) -->
<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 -->
<PydTag Condition="$(ArchName) == 'win32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win32</PydTag>
<PydTag Condition="$(ArchName) == 'arm32'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm32</PydTag>
<PydTag Condition="$(ArchName) == 'arm64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_arm64</PydTag>
<PydTag Condition="$(ArchName) == 'amd64'">.cp$(MajorVersionNumber)$(MinorVersionNumber)-win_amd64</PydTag>
<!-- The version number for sys.winver -->
<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 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 -->
<Target Name="ShowVersionInfo">
<Message Importance="high" Text="PythonVersionNumber: $(PythonVersionNumber)" />

View File

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

View File

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

View File

@ -73,6 +73,7 @@
<Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<TargetName>$(PyWExeName)</TargetName>
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
</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 Run the specified architecture of python (or python_d if -d
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 whatever remains (up to 9 arguments) is passed to regrtest.py.
rem For example,
@ -29,6 +30,7 @@ rem rt -u "network,largefile"
setlocal
set pcbuild=%~dp0
set pyname=python
set suffix=
set qmode=
set dashO=
@ -39,15 +41,18 @@ set exe=
if "%1"=="-O" (set dashO=-O) & shift & goto CheckOpts
if "%1"=="-q" (set qmode=yes) & shift & goto CheckOpts
if "%1"=="-d" (set suffix=_d) & shift & goto CheckOpts
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"=="-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"=="-arm32" (set prefix=%pcbuild%arm32) & 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 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%
if defined qmode goto Qmode

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -80,7 +80,7 @@
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<TargetExt>.pyd</TargetExt>
<TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</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 "--pack" (set BUILDPACK=1) && 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)
@ -44,6 +47,20 @@ if errorlevel 1 exit /B %ERRORLEVEL%
if defined BUILDARM64 call "%PCBUILD%build.bat" -p ARM64 -e %REBUILD% %BUILDTEST%
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 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="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_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>
<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="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_freethreadedLabel">Download &amp;free-threaded binaries (experimental)</String>
<String Id="ProgressHeader">[ActionLikeInstallation] Progress</String>
<String Id="ProgressLabel">[ActionLikeInstalling]:</String>

View File

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

View File

@ -82,6 +82,13 @@
<?endif ?>
<Variable Name="Include_symbols" 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="DetectedLauncher" Value="0" />
@ -104,6 +111,9 @@
<PackageGroupRef Id="exe" />
<PackageGroupRef Id="dev" />
<PackageGroupRef Id="lib" />
<?if $(var.IncludeFreethreaded)~="true" ?>
<PackageGroupRef Id="freethreaded" />
<?endif ?>
<PackageGroupRef Id="test" />
<PackageGroupRef Id="doc" />
<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" />
</Component>
<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 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>
</ComponentGroup>
</Fragment>
@ -63,10 +63,10 @@
<File Name="libssl$(var.ssltag).pdb" KeyPath="yes" />
</Component>
<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 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>
</ComponentGroup>
</Fragment>
@ -100,10 +100,10 @@
<File Name="sqlite3_d.pdb" KeyPath="yes" />
</Component>
<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 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>
</ComponentGroup>
</Fragment>

View File

@ -24,14 +24,14 @@
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
when attempting to downgrade.
By default, this is the local computer name, which will produce
installers that do not interfere with other installers. Products
that intend to bundle Python should rebuild these modules with their
own URI to avoid conflicting with the official releases.
The official releases use "https://www.python.org/$(ArchName)"
This is not the same as the DownloadUrl property used in the bundle
projects.
-->
@ -39,7 +39,7 @@
<ReleaseUri Condition="!$(ReleaseUri.EndsWith(`/`))">$(ReleaseUri)/</ReleaseUri>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)common.wxs" />
<WxlTemplate Include="$(MSBuildThisFileDirectory)\*.wxl_template" Condition="$(IgnoreCommonWxlTemplates) != 'true'" />
@ -63,13 +63,17 @@
<InstallerVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(Field3Value).0</InstallerVersion>
</PropertyGroup>
<PropertyGroup>
<IncludeFreethreaded Condition="$(IncludeFreethreaded) != 'true'">false</IncludeFreethreaded>
</PropertyGroup>
<PropertyGroup Condition="!$(BuildForRelease)">
<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>
<InstallerVersion>$(MajorVersionNumber).$(MinorVersionNumber).$(RevisionNumber).0</InstallerVersion>
</PropertyGroup>
<PropertyGroup>
<Bitness>32-bit</Bitness>
<Bitness Condition="$(Platform) == 'x64'">64-bit</Bitness>
@ -91,9 +95,12 @@
PyDebugExt=$(PyDebugExt);
PyArchExt=$(PyArchExt);
PyTestExt=$(PyTestExt);
PydTag=$(PydTag);
FreethreadedPydTag=$(FreethreadedPydTag);
OptionalFeatureName=$(OutputName);
ssltag=$(OpenSSLDLLSuffix);
Suffix32=$(PyArchExt);
IncludeFreethreaded=$(IncludeFreethreaded);
</DefineConstants>
<DefineConstants Condition="'$(CRTRedist)' != ''">
$(DefineConstants);CRTRedist=$(CRTRedist);
@ -139,7 +146,7 @@
<Error Text="Platform '$(Platform)' is not supported. Use 'x86', 'x64' or 'ARM64'."
Condition="$(Platform) != 'x86' and $(Platform) != 'x64' and $(Platform) != 'ARM64'" />
</Target>
<ItemGroup>
<_Uuid Include="CoreUpgradeCode">
<Uri>upgradecode</Uri>
@ -162,6 +169,12 @@
<_Uuid Include="PythonRegComponentGuid">
<Uri>registry/$(OutputName)</Uri>
</_Uuid>
<_Uuid Include="FreethreadedPythonExeComponentGuid" Condition="$(IncludeFreethreaded)">
<Uri>freethreaded/python.exe</Uri>
</_Uuid>
<_Uuid Include="FreethreadedPythonwExeComponentGuid" Condition="$(IncludeFreethreaded)">
<Uri>freethreaded/pythonw.exe</Uri>
</_Uuid>
</ItemGroup>
<Target Name="_GenerateGuids"
AfterTargets="PrepareForBuild"
@ -171,15 +184,15 @@
<_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>
</PropertyGroup>
<Exec Command='$(PythonForBuild) -c "$(_GenerateCommand)" &gt; "$(IntermediateOutputPath)$(OutputName)guids.txt"'
WorkingDirectory="$(MSBuildThisFileDirectory)"
IgnoreExitCode="false" />
<ReadLinesFromFile File="$(IntermediateOutputPath)$(OutputName)guids.txt">
<Output TaskParameter="Lines" ItemName="_UuidValue" />
</ReadLinesFromFile>
<PropertyGroup>
<DefineConstants>$(DefineConstants);@(_UuidValue,';');</DefineConstants>
</PropertyGroup>