strategy:
matrix:
type: [x86, x64, arm64]
+ env:
+ IncludeFreethreaded: true
steps:
- uses: actions/checkout@v4
- name: Build CPython installer
- 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)'
- 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)'
"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:
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:
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"
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.
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])
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)}
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)
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
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}")
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')
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)
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)
# 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')
# 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')
'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
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):
'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
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:
+ 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:
- suffixes = {'python.exe', 'python_d.exe', 'pythonw.exe', 'pythonw_d.exe'}
- base_exe = os.path.basename(context.env_exe)
- suffixes.add(base_exe)
+ 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
- for suffix in suffixes:
- src = os.path.join(dirname, suffix)
- if os.path.lexists(src):
- copier(src, os.path.join(binpath, suffix))
+ 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
"""
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[:]:
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:]
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):
--- /dev/null
+Adds free-threaded binaries to Windows installer as an optional component.
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_*")
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
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")
+ 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,
+ ])
+
+ 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.exe", new_name="python")
- yield from in_build("pythonw.exe", new_name="pythonw")
-
- yield from in_build(PYTHON_DLL_NAME)
+ yield from in_build(PYTHON_DLL_NAME)
if ns.include_launchers and ns.include_appxmanifest:
if ns.include_pip:
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"):
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:
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:
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"
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()
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()
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(
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))
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)
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"]:
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
"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"},
}
"dev",
"launchers",
"appxmanifest",
+ "alias",
+ "alias3x",
# XXX: Disabled for now "precompile",
],
},
"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": [
"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",
+ ],
},
}
#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 */
/* ------------------------------------------------------------------------*/
/* 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)
# else
# pragma comment(lib,"python313.lib")
# endif /* _DEBUG */
+# endif /* Py_GIL_DISABLED */
# endif /* _MSC_VER */
# endif /* Py_BUILD_CORE */
#endif /* MS_COREDLL */
/* 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 */
--- /dev/null
+/*
+ * 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
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<PropertyGroup Label="Configuration" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>\r
\ No newline at end of file
+</Project>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<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>
<_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>
</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>
<!--
<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>
<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>
<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>
<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'
<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.
-->
))
))</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)" />
<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>
</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>
@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>
<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" />
<Import Project="python.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
+ <TargetName>$(PyWExeName)</TargetName>
<ConfigurationType>Application</ConfigurationType>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
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,
setlocal
set pcbuild=%~dp0
+set pyname=python
set suffix=
set qmode=
set dashO=
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
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<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>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<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>
<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" />
</ResourceCompile>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\PC\launcher.c">
+ <ClCompile Include="..\PC\venvlauncher.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<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>
<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" />
</Filter>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\PC\launcher.c">
+ <ClCompile Include="..\PC\venvlauncher.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
- <TargetExt>.pyd</TargetExt>
+ <TargetExt>$(PyStdlibPydExt)</TargetExt>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
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)
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%
<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" />
<String Id="PrecompileLabel">&Precompile standard library</String>
<String Id="Include_symbolsLabel">Download debugging &symbols</String>
<String Id="Include_debugLabel">Download debu&g binaries (requires VS 2017 or later)</String>
+ <String Id="Include_freethreadedLabel">Download &free-threaded binaries (experimental)</String>
<String Id="ProgressHeader">[ActionLikeInstallation] Progress</String>
<String Id="ProgressLabel">[ActionLikeInstalling]:</String>
<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>
<?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" />
<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" />
--- /dev/null
+<?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>
\ No newline at end of file
--- /dev/null
+<?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>
\ No newline at end of file
--- /dev/null
+<?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>
--- /dev/null
+<?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>
\ No newline at end of file
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+<?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>
\ No newline at end of file
--- /dev/null
+<?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>
<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>
<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>
<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>
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.
-->
<ReleaseUri Condition="!$(ReleaseUri.EndsWith(`/`))">$(ReleaseUri)/</ReleaseUri>
</PropertyGroup>
-
+
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)common.wxs" />
<WxlTemplate Include="$(MSBuildThisFileDirectory)\*.wxl_template" Condition="$(IgnoreCommonWxlTemplates) != 'true'" />
<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>
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);
<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>
<_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"
<_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)" > "$(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>