bpo-34977: Add Windows App Store package (GH-11027)
Also adds the PC/layout script for generating layouts on Windows.
This commit is contained in:
parent
1c3de541e6
commit
0cd6391fd8
|
@ -0,0 +1,67 @@
|
||||||
|
jobs:
|
||||||
|
- job: Prebuild
|
||||||
|
displayName: Pre-build checks
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-16.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- template: ./prebuild-checks.yml
|
||||||
|
|
||||||
|
|
||||||
|
- job: Windows_Appx_Tests
|
||||||
|
displayName: Windows Appx Tests
|
||||||
|
dependsOn: Prebuild
|
||||||
|
condition: and(succeeded(), eq(dependencies.Prebuild.outputs['tests.run'], 'true'))
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: vs2017-win2016
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
win64:
|
||||||
|
arch: amd64
|
||||||
|
buildOpt: '-p x64'
|
||||||
|
testRunTitle: '$(Build.SourceBranchName)-win64-appx'
|
||||||
|
testRunPlatform: win64
|
||||||
|
maxParallel: 2
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout: self
|
||||||
|
clean: true
|
||||||
|
fetchDepth: 5
|
||||||
|
|
||||||
|
- powershell: |
|
||||||
|
# Relocate build outputs outside of source directory to make cleaning faster
|
||||||
|
Write-Host '##vso[task.setvariable variable=Py_IntDir]$(Build.BinariesDirectory)\obj'
|
||||||
|
# UNDONE: Do not build to a different directory because of broken tests
|
||||||
|
Write-Host '##vso[task.setvariable variable=Py_OutDir]$(Build.SourcesDirectory)\PCbuild'
|
||||||
|
Write-Host '##vso[task.setvariable variable=EXTERNAL_DIR]$(Build.BinariesDirectory)\externals'
|
||||||
|
displayName: Update build locations
|
||||||
|
|
||||||
|
- script: PCbuild\build.bat -e $(buildOpt)
|
||||||
|
displayName: 'Build CPython'
|
||||||
|
env:
|
||||||
|
IncludeUwp: true
|
||||||
|
|
||||||
|
- script: python.bat PC\layout -vv -s "$(Build.SourcesDirectory)" -b "$(Py_OutDir)\$(arch)" -t "$(Py_IntDir)\layout-tmp-$(arch)" --copy "$(Py_IntDir)\layout-$(arch)" --precompile --preset-appx --include-tests
|
||||||
|
displayName: 'Create APPX layout'
|
||||||
|
|
||||||
|
- script: .\python.exe -m test.pythoninfo
|
||||||
|
workingDirectory: $(Py_IntDir)\layout-$(arch)
|
||||||
|
displayName: 'Display build info'
|
||||||
|
|
||||||
|
- script: .\python.exe -m test -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0 --junit-xml="$(Build.BinariesDirectory)\test-results.xml" --tempdir "$(Py_IntDir)\tmp-$(arch)"
|
||||||
|
workingDirectory: $(Py_IntDir)\layout-$(arch)
|
||||||
|
displayName: 'Tests'
|
||||||
|
env:
|
||||||
|
PREFIX: $(Py_IntDir)\layout-$(arch)
|
||||||
|
|
||||||
|
- task: PublishTestResults@2
|
||||||
|
displayName: 'Publish Test Results'
|
||||||
|
inputs:
|
||||||
|
testResultsFiles: '$(Build.BinariesDirectory)\test-results.xml'
|
||||||
|
mergeTestResults: true
|
||||||
|
testRunTitle: $(testRunTitle)
|
||||||
|
platform: $(testRunPlatform)
|
||||||
|
condition: succeededOrFailed()
|
|
@ -13,6 +13,8 @@ steps:
|
||||||
|
|
||||||
- script: PCbuild\build.bat -e $(buildOpt)
|
- script: PCbuild\build.bat -e $(buildOpt)
|
||||||
displayName: 'Build CPython'
|
displayName: 'Build CPython'
|
||||||
|
env:
|
||||||
|
IncludeUwp: true
|
||||||
|
|
||||||
- script: python.bat -m test.pythoninfo
|
- script: python.bat -m test.pythoninfo
|
||||||
displayName: 'Display build info'
|
displayName: 'Display build info'
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
# Specific binary files
|
# Specific binary files
|
||||||
Lib/test/sndhdrdata/sndhdr.* binary
|
Lib/test/sndhdrdata/sndhdr.* binary
|
||||||
|
PC/classicAppCompat.* binary
|
||||||
|
|
||||||
# Text files that should not be subject to eol conversion
|
# Text files that should not be subject to eol conversion
|
||||||
Lib/test/cjkencodings/* -text
|
Lib/test/cjkencodings/* -text
|
||||||
|
|
|
@ -115,12 +115,16 @@ goto end
|
||||||
:build
|
:build
|
||||||
if not exist "%BUILDDIR%" mkdir "%BUILDDIR%"
|
if not exist "%BUILDDIR%" mkdir "%BUILDDIR%"
|
||||||
|
|
||||||
|
rem We ought to move NEWS to %BUILDDIR%\NEWS and point
|
||||||
|
rem Sphinx at the right location.
|
||||||
if exist ..\Misc\NEWS (
|
if exist ..\Misc\NEWS (
|
||||||
echo.Copying Misc\NEWS to build\NEWS
|
echo.Copying Misc\NEWS to build\NEWS
|
||||||
|
if not exist build mkdir build
|
||||||
copy ..\Misc\NEWS build\NEWS > nul
|
copy ..\Misc\NEWS build\NEWS > nul
|
||||||
) else if exist ..\Misc\NEWS.D (
|
) else if exist ..\Misc\NEWS.D (
|
||||||
if defined BLURB (
|
if defined BLURB (
|
||||||
echo.Merging Misc/NEWS with %BLURB%
|
echo.Merging Misc/NEWS with %BLURB%
|
||||||
|
if not exist build mkdir build
|
||||||
%BLURB% merge -f build\NEWS
|
%BLURB% merge -f build\NEWS
|
||||||
) else (
|
) else (
|
||||||
echo.No Misc/NEWS file and Blurb is not available.
|
echo.No Misc/NEWS file and Blurb is not available.
|
||||||
|
|
|
@ -12,9 +12,6 @@
|
||||||
This document aims to give an overview of Windows-specific behaviour you should
|
This document aims to give an overview of Windows-specific behaviour you should
|
||||||
know about when using Python on Microsoft Windows.
|
know about when using Python on Microsoft Windows.
|
||||||
|
|
||||||
Installing Python
|
|
||||||
=================
|
|
||||||
|
|
||||||
Unlike most Unix systems and services, Windows does not include a system
|
Unlike most Unix systems and services, Windows does not include a system
|
||||||
supported installation of Python. To make Python available, the CPython team
|
supported installation of Python. To make Python available, the CPython team
|
||||||
has compiled Windows installers (MSI packages) with every `release
|
has compiled Windows installers (MSI packages) with every `release
|
||||||
|
@ -24,15 +21,37 @@ core interpreter and library being used by a single user. The installer is also
|
||||||
able to install for all users of a single machine, and a separate ZIP file is
|
able to install for all users of a single machine, and a separate ZIP file is
|
||||||
available for application-local distributions.
|
available for application-local distributions.
|
||||||
|
|
||||||
Supported Versions
|
|
||||||
------------------
|
|
||||||
|
|
||||||
As specified in :pep:`11`, a Python release only supports a Windows platform
|
As specified in :pep:`11`, a Python release only supports a Windows platform
|
||||||
while Microsoft considers the platform under extended support. This means that
|
while Microsoft considers the platform under extended support. This means that
|
||||||
Python |version| supports Windows Vista and newer. If you require Windows XP
|
Python |version| supports Windows Vista and newer. If you require Windows XP
|
||||||
support then please install Python 3.4.
|
support then please install Python 3.4.
|
||||||
|
|
||||||
Installation Steps
|
There are a number of different installers available for Windows, each with
|
||||||
|
certain benefits and downsides.
|
||||||
|
|
||||||
|
:ref:`windows-full` contains all components and is the best option for
|
||||||
|
developers using Python for any kind of project.
|
||||||
|
|
||||||
|
:ref:`windows-store` is a simple installation of Python that is suitable for
|
||||||
|
running scripts and packages, and using IDLE or other development environments.
|
||||||
|
It requires Windows 10, but can be safely installed without corrupting other
|
||||||
|
programs. It also provides many convenient commands for launching Python and
|
||||||
|
its tools.
|
||||||
|
|
||||||
|
:ref:`windows-nuget` are lightweight installations intended for continuous
|
||||||
|
integration systems. It can be used to build Python packages or run scripts,
|
||||||
|
but is not updateable and has no user interface tools.
|
||||||
|
|
||||||
|
:ref:`windows-embeddable` is a minimal package of Python suitable for
|
||||||
|
embedding into a larger application.
|
||||||
|
|
||||||
|
|
||||||
|
.. _windows-full:
|
||||||
|
|
||||||
|
The full installer
|
||||||
|
==================
|
||||||
|
|
||||||
|
Installation steps
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
Four Python |version| installers are available for download - two each for the
|
Four Python |version| installers are available for download - two each for the
|
||||||
|
@ -264,39 +283,199 @@ settings and replace any that have been removed or modified.
|
||||||
"Uninstall" will remove Python entirely, with the exception of the
|
"Uninstall" will remove Python entirely, with the exception of the
|
||||||
:ref:`launcher`, which has its own entry in Programs and Features.
|
:ref:`launcher`, which has its own entry in Programs and Features.
|
||||||
|
|
||||||
Other Platforms
|
|
||||||
---------------
|
|
||||||
|
|
||||||
With ongoing development of Python, some platforms that used to be supported
|
.. _windows-store:
|
||||||
earlier are no longer supported (due to the lack of users or developers).
|
|
||||||
Check :pep:`11` for details on all unsupported platforms.
|
|
||||||
|
|
||||||
* `Windows CE <http://pythonce.sourceforge.net/>`_ is still supported.
|
The Microsoft Store package
|
||||||
* The `Cygwin <https://cygwin.com/>`_ installer offers to install the Python
|
===========================
|
||||||
interpreter as well (cf. `Cygwin package source
|
|
||||||
<ftp://ftp.uni-erlangen.de/pub/pc/gnuwin32/cygwin/mirrors/cygnus/
|
|
||||||
release/python>`_, `Maintainer releases
|
|
||||||
<http://www.tishler.net/jason/software/python/>`_)
|
|
||||||
|
|
||||||
See `Python for Windows <https://www.python.org/downloads/windows/>`_
|
.. versionadded:: 3.7.2
|
||||||
for detailed information about platforms with pre-compiled installers.
|
|
||||||
|
|
||||||
.. seealso::
|
.. note::
|
||||||
|
The Microsoft Store package is currently considered unstable while its
|
||||||
|
interactions with other tools and other copies of Python are evaluated.
|
||||||
|
While Python itself is stable, this installation method may change its
|
||||||
|
behavior and capabilities during Python 3.7 releases.
|
||||||
|
|
||||||
`Python on XP <http://dooling.com/index.php/2006/03/14/python-on-xp-7-minutes-to-hello-world/>`_
|
The Microsoft Store package is an easily installable Python interpreter that
|
||||||
"7 Minutes to "Hello World!""
|
is intended mainly for interactive use, for example, by students.
|
||||||
by Richard Dooling, 2006
|
|
||||||
|
|
||||||
`Installing on Windows <http://www.diveintopython.net/installing_python/windows.html>`_
|
To install the package, ensure you have the latest Windows 10 updates and
|
||||||
in "`Dive into Python: Python from novice to pro
|
search the Microsoft Store app for "Python |version|". Ensure that the app
|
||||||
<http://www.diveintopython.net/>`_"
|
you select is published by the Python Software Foundation, and install it.
|
||||||
by Mark Pilgrim, 2004,
|
|
||||||
ISBN 1-59059-356-1
|
|
||||||
|
|
||||||
`For Windows users <https://python.swaroopch.com/installation.html#installation-on-windows>`_
|
.. warning::
|
||||||
in "Installing Python"
|
Python will always be available for free on the Microsoft Store. If you
|
||||||
in "`A Byte of Python <https://python.swaroopch.com/>`_"
|
are asked to pay for it, you have not selected the correct package.
|
||||||
by Swaroop C H, 2003
|
|
||||||
|
After installation, Python may be launched by finding it in Start.
|
||||||
|
Alternatively, it will be available from any Command Prompt or PowerShell
|
||||||
|
session by typing ``python``. Further, pip and IDLE may be used by typing
|
||||||
|
``pip`` or ``idle``. IDLE can also be found in Start.
|
||||||
|
|
||||||
|
All three commands are also available with version number suffixes, for
|
||||||
|
example, as ``python3.exe`` and ``python3.x.exe`` as well as
|
||||||
|
``python.exe`` (where ``3.x`` is the specific version you want to launch,
|
||||||
|
such as |version|).
|
||||||
|
|
||||||
|
Virtual environments can be created with ``python -m venv`` and activated
|
||||||
|
and used as normal.
|
||||||
|
|
||||||
|
If you have installed another version of Python and added it to your
|
||||||
|
``PATH`` variable, it will be available as ``python.exe`` rather than the
|
||||||
|
one from the Microsoft Store. To access the new installation, use
|
||||||
|
``python3.exe`` or ``python3.x.exe``.
|
||||||
|
|
||||||
|
To remove Python, open Settings and use Apps and Features, or else find
|
||||||
|
Python in Start and right-click to select Uninstall. Uninstalling will
|
||||||
|
remove all packages you installed directly into this Python installation, but
|
||||||
|
will not remove any virtual environments
|
||||||
|
|
||||||
|
Known Issues
|
||||||
|
------------
|
||||||
|
|
||||||
|
Currently, the ``py.exe`` launcher cannot be used to start Python when it
|
||||||
|
has been installed from the Microsoft Store.
|
||||||
|
|
||||||
|
Because of restrictions on Microsoft Store apps, Python scripts may not have
|
||||||
|
full write access to shared locations such as ``TEMP`` and the registry.
|
||||||
|
Instead, it will write to a private copy. If your scripts must modify the
|
||||||
|
shared locations, you will need to install the full installer.
|
||||||
|
|
||||||
|
|
||||||
|
.. _windows-nuget:
|
||||||
|
|
||||||
|
The nuget.org packages
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. versionadded:: 3.5.2
|
||||||
|
|
||||||
|
The nuget.org package is a reduced size Python environment intended for use on
|
||||||
|
continuous integration and build systems that do not have a system-wide
|
||||||
|
install of Python. While nuget is "the package manager for .NET", it also works
|
||||||
|
perfectly fine for packages containing build-time tools.
|
||||||
|
|
||||||
|
Visit `nuget.org <https://www.nuget.org/>`_ for the most up-to-date information
|
||||||
|
on using nuget. What follows is a summary that is sufficient for Python
|
||||||
|
developers.
|
||||||
|
|
||||||
|
The ``nuget.exe`` command line tool may be downloaded directly from
|
||||||
|
``https://aka.ms/nugetclidl``, for example, using curl or PowerShell. With the
|
||||||
|
tool, the latest version of Python for 64-bit or 32-bit machines is installed
|
||||||
|
using::
|
||||||
|
|
||||||
|
nuget.exe install python -ExcludeVersion -OutputDirectory .
|
||||||
|
nuget.exe install pythonx86 -ExcludeVersion -OutputDirectory .
|
||||||
|
|
||||||
|
To select a particular version, add a ``-Version 3.x.y``. The output directory
|
||||||
|
may be changed from ``.``, and the package will be installed into a
|
||||||
|
subdirectory. By default, the subdirectory is named the same as the package,
|
||||||
|
and without the ``-ExcludeVersion`` option this name will include the specific
|
||||||
|
version installed. Inside the subdirectory is a ``tools`` directory that
|
||||||
|
contains the Python installation::
|
||||||
|
|
||||||
|
# Without -ExcludeVersion
|
||||||
|
> .\python.3.5.2\tools\python.exe -V
|
||||||
|
Python 3.5.2
|
||||||
|
|
||||||
|
# With -ExcludeVersion
|
||||||
|
> .\python\tools\python.exe -V
|
||||||
|
Python 3.5.2
|
||||||
|
|
||||||
|
In general, nuget packages are not upgradeable, and newer versions should be
|
||||||
|
installed side-by-side and referenced using the full path. Alternatively,
|
||||||
|
delete the package directory manually and install it again. Many CI systems
|
||||||
|
will do this automatically if they do not preserve files between builds.
|
||||||
|
|
||||||
|
Alongside the ``tools`` directory is a ``build\native`` directory. This
|
||||||
|
contains a MSBuild properties file ``python.props`` that can be used in a
|
||||||
|
C++ project to reference the Python install. Including the settings will
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
.. _windows-embeddable:
|
||||||
|
|
||||||
|
The embeddable package
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. versionadded:: 3.5
|
||||||
|
|
||||||
|
The embedded distribution is a ZIP file containing a minimal Python environment.
|
||||||
|
It is intended for acting as part of another application, rather than being
|
||||||
|
directly accessed by end-users.
|
||||||
|
|
||||||
|
When extracted, the embedded distribution is (almost) fully isolated from the
|
||||||
|
user's system, including environment variables, system registry settings, and
|
||||||
|
installed packages. The standard library is included as pre-compiled and
|
||||||
|
optimized ``.pyc`` files in a ZIP, and ``python3.dll``, ``python37.dll``,
|
||||||
|
``python.exe`` and ``pythonw.exe`` are all provided. Tcl/tk (including all
|
||||||
|
dependants, such as Idle), pip and the Python documentation are not included.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The embedded distribution does not include the `Microsoft C Runtime
|
||||||
|
<https://www.microsoft.com/en-us/download/details.aspx?id=48145>`_ and it is
|
||||||
|
the responsibility of the application installer to provide this. The
|
||||||
|
runtime may have already been installed on a user's system previously or
|
||||||
|
automatically via Windows Update, and can be detected by finding
|
||||||
|
``ucrtbase.dll`` in the system directory.
|
||||||
|
|
||||||
|
Third-party packages should be installed by the application installer alongside
|
||||||
|
the embedded distribution. Using pip to manage dependencies as for a regular
|
||||||
|
Python installation is not supported with this distribution, though with some
|
||||||
|
care it may be possible to include and use pip for automatic updates. In
|
||||||
|
general, third-party packages should be treated as part of the application
|
||||||
|
("vendoring") so that the developer can ensure compatibility with newer
|
||||||
|
versions before providing updates to users.
|
||||||
|
|
||||||
|
The two recommended use cases for this distribution are described below.
|
||||||
|
|
||||||
|
Python Application
|
||||||
|
------------------
|
||||||
|
|
||||||
|
An application written in Python does not necessarily require users to be aware
|
||||||
|
of that fact. The embedded distribution may be used in this case to include a
|
||||||
|
private version of Python in an install package. Depending on how transparent it
|
||||||
|
should be (or conversely, how professional it should appear), there are two
|
||||||
|
options.
|
||||||
|
|
||||||
|
Using a specialized executable as a launcher requires some coding, but provides
|
||||||
|
the most transparent experience for users. With a customized launcher, there are
|
||||||
|
no obvious indications that the program is running on Python: icons can be
|
||||||
|
customized, company and version information can be specified, and file
|
||||||
|
associations behave properly. In most cases, a custom launcher should simply be
|
||||||
|
able to call ``Py_Main`` with a hard-coded command line.
|
||||||
|
|
||||||
|
The simpler approach is to provide a batch file or generated shortcut that
|
||||||
|
directly calls the ``python.exe`` or ``pythonw.exe`` with the required
|
||||||
|
command-line arguments. In this case, the application will appear to be Python
|
||||||
|
and not its actual name, and users may have trouble distinguishing it from other
|
||||||
|
running Python processes or file associations.
|
||||||
|
|
||||||
|
With the latter approach, packages should be installed as directories alongside
|
||||||
|
the Python executable to ensure they are available on the path. With the
|
||||||
|
specialized launcher, packages can be located in other locations as there is an
|
||||||
|
opportunity to specify the search path before launching the application.
|
||||||
|
|
||||||
|
Embedding Python
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Applications written in native code often require some form of scripting
|
||||||
|
language, and the embedded Python distribution can be used for this purpose. In
|
||||||
|
general, the majority of the application is in native code, and some part will
|
||||||
|
either invoke ``python.exe`` or directly use ``python3.dll``. For either case,
|
||||||
|
extracting the embedded distribution to a subdirectory of the application
|
||||||
|
installation is sufficient to provide a loadable Python interpreter.
|
||||||
|
|
||||||
|
As with the application use, packages can be installed to any location as there
|
||||||
|
is an opportunity to specify search paths before initializing the interpreter.
|
||||||
|
Otherwise, there is no fundamental differences between using the embedded
|
||||||
|
distribution and a regular installation.
|
||||||
|
|
||||||
|
|
||||||
Alternative bundles
|
Alternative bundles
|
||||||
|
@ -441,6 +620,8 @@ appropriate version of Python. It will prefer per-user installations over
|
||||||
system-wide ones, and orders by language version rather than using the most
|
system-wide ones, and orders by language version rather than using the most
|
||||||
recently installed version.
|
recently installed version.
|
||||||
|
|
||||||
|
The launcher was originally specified in :pep:`397`.
|
||||||
|
|
||||||
Getting started
|
Getting started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -922,95 +1103,19 @@ For extension modules, consult :ref:`building-on-windows`.
|
||||||
by Trent Apted et al, 2007
|
by Trent Apted et al, 2007
|
||||||
|
|
||||||
|
|
||||||
Embedded Distribution
|
Other Platforms
|
||||||
=====================
|
|
||||||
|
|
||||||
.. versionadded:: 3.5
|
|
||||||
|
|
||||||
The embedded distribution is a ZIP file containing a minimal Python environment.
|
|
||||||
It is intended for acting as part of another application, rather than being
|
|
||||||
directly accessed by end-users.
|
|
||||||
|
|
||||||
When extracted, the embedded distribution is (almost) fully isolated from the
|
|
||||||
user's system, including environment variables, system registry settings, and
|
|
||||||
installed packages. The standard library is included as pre-compiled and
|
|
||||||
optimized ``.pyc`` files in a ZIP, and ``python3.dll``, ``python37.dll``,
|
|
||||||
``python.exe`` and ``pythonw.exe`` are all provided. Tcl/tk (including all
|
|
||||||
dependants, such as Idle), pip and the Python documentation are not included.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The embedded distribution does not include the `Microsoft C Runtime
|
|
||||||
<https://www.microsoft.com/en-us/download/details.aspx?id=48145>`_ and it is
|
|
||||||
the responsibility of the application installer to provide this. The
|
|
||||||
runtime may have already been installed on a user's system previously or
|
|
||||||
automatically via Windows Update, and can be detected by finding
|
|
||||||
``ucrtbase.dll`` in the system directory.
|
|
||||||
|
|
||||||
Third-party packages should be installed by the application installer alongside
|
|
||||||
the embedded distribution. Using pip to manage dependencies as for a regular
|
|
||||||
Python installation is not supported with this distribution, though with some
|
|
||||||
care it may be possible to include and use pip for automatic updates. In
|
|
||||||
general, third-party packages should be treated as part of the application
|
|
||||||
("vendoring") so that the developer can ensure compatibility with newer
|
|
||||||
versions before providing updates to users.
|
|
||||||
|
|
||||||
The two recommended use cases for this distribution are described below.
|
|
||||||
|
|
||||||
Python Application
|
|
||||||
------------------
|
|
||||||
|
|
||||||
An application written in Python does not necessarily require users to be aware
|
|
||||||
of that fact. The embedded distribution may be used in this case to include a
|
|
||||||
private version of Python in an install package. Depending on how transparent it
|
|
||||||
should be (or conversely, how professional it should appear), there are two
|
|
||||||
options.
|
|
||||||
|
|
||||||
Using a specialized executable as a launcher requires some coding, but provides
|
|
||||||
the most transparent experience for users. With a customized launcher, there are
|
|
||||||
no obvious indications that the program is running on Python: icons can be
|
|
||||||
customized, company and version information can be specified, and file
|
|
||||||
associations behave properly. In most cases, a custom launcher should simply be
|
|
||||||
able to call ``Py_Main`` with a hard-coded command line.
|
|
||||||
|
|
||||||
The simpler approach is to provide a batch file or generated shortcut that
|
|
||||||
directly calls the ``python.exe`` or ``pythonw.exe`` with the required
|
|
||||||
command-line arguments. In this case, the application will appear to be Python
|
|
||||||
and not its actual name, and users may have trouble distinguishing it from other
|
|
||||||
running Python processes or file associations.
|
|
||||||
|
|
||||||
With the latter approach, packages should be installed as directories alongside
|
|
||||||
the Python executable to ensure they are available on the path. With the
|
|
||||||
specialized launcher, packages can be located in other locations as there is an
|
|
||||||
opportunity to specify the search path before launching the application.
|
|
||||||
|
|
||||||
Embedding Python
|
|
||||||
----------------
|
|
||||||
|
|
||||||
Applications written in native code often require some form of scripting
|
|
||||||
language, and the embedded Python distribution can be used for this purpose. In
|
|
||||||
general, the majority of the application is in native code, and some part will
|
|
||||||
either invoke ``python.exe`` or directly use ``python3.dll``. For either case,
|
|
||||||
extracting the embedded distribution to a subdirectory of the application
|
|
||||||
installation is sufficient to provide a loadable Python interpreter.
|
|
||||||
|
|
||||||
As with the application use, packages can be installed to any location as there
|
|
||||||
is an opportunity to specify search paths before initializing the interpreter.
|
|
||||||
Otherwise, there is no fundamental differences between using the embedded
|
|
||||||
distribution and a regular installation.
|
|
||||||
|
|
||||||
Other resources
|
|
||||||
===============
|
===============
|
||||||
|
|
||||||
.. seealso::
|
With ongoing development of Python, some platforms that used to be supported
|
||||||
|
earlier are no longer supported (due to the lack of users or developers).
|
||||||
|
Check :pep:`11` for details on all unsupported platforms.
|
||||||
|
|
||||||
`Python Programming On Win32 <http://shop.oreilly.com/product/9781565926219.do>`_
|
* `Windows CE <http://pythonce.sourceforge.net/>`_ is still supported.
|
||||||
"Help for Windows Programmers"
|
* The `Cygwin <https://cygwin.com/>`_ installer offers to install the Python
|
||||||
by Mark Hammond and Andy Robinson, O'Reilly Media, 2000,
|
interpreter as well (cf. `Cygwin package source
|
||||||
ISBN 1-56592-621-8
|
<ftp://ftp.uni-erlangen.de/pub/pc/gnuwin32/cygwin/mirrors/cygnus/
|
||||||
|
release/python>`_, `Maintainer releases
|
||||||
|
<http://www.tishler.net/jason/software/python/>`_)
|
||||||
|
|
||||||
`A Python for Windows Tutorial <http://www.imladris.com/Scripts/PythonForWindows.html>`_
|
See `Python for Windows <https://www.python.org/downloads/windows/>`_
|
||||||
by Amanda Birmingham, 2004
|
for detailed information about platforms with pre-compiled installers.
|
||||||
|
|
||||||
:pep:`397` - Python launcher for Windows
|
|
||||||
The proposal for the launcher to be included in the Python distribution.
|
|
||||||
|
|
|
@ -1521,7 +1521,7 @@ class _BasePathTest(object):
|
||||||
# resolves to 'dirB/..' first before resolving to parent of dirB.
|
# resolves to 'dirB/..' first before resolving to parent of dirB.
|
||||||
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
|
self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False)
|
||||||
# Now create absolute symlinks
|
# Now create absolute symlinks
|
||||||
d = support._longpath(tempfile.mkdtemp(suffix='-dirD'))
|
d = support._longpath(tempfile.mkdtemp(suffix='-dirD', dir=os.getcwd()))
|
||||||
self.addCleanup(support.rmtree, d)
|
self.addCleanup(support.rmtree, d)
|
||||||
os.symlink(os.path.join(d), join('dirA', 'linkX'))
|
os.symlink(os.path.join(d), join('dirA', 'linkX'))
|
||||||
os.symlink(join('dirB'), os.path.join(d, 'linkY'))
|
os.symlink(join('dirB'), os.path.join(d, 'linkY'))
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Adds support for building a Windows App Store package
|
|
@ -0,0 +1 @@
|
||||||
|
<CustomCapabilityDescriptor xmlns="http://schemas.microsoft.com/appx/2016/sccd" xmlns:s="http://schemas.microsoft.com/appx/2016/sccd"><CustomCapabilities><CustomCapability Name="Microsoft.classicAppCompat_8wekyb3d8bbwe"></CustomCapability></CustomCapabilities><AuthorizedEntities><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.7_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.15_qbz5n2kfra8p0" CertificateSignatureHash="0000000000000000000000000000000000000000000000000000000000000000"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.7_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.14_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity><AuthorizedEntity AppPackageFamilyName="PythonSoftwareFoundation.Python.3.15_qbz5n2kfra8p0" CertificateSignatureHash="279cd652c4e252bfbe5217ac722205d7729ba409148cfa9e6d9e5b1cb94eaff1"></AuthorizedEntity></AuthorizedEntities></CustomCapabilityDescriptor>
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import layout
|
||||||
|
except ImportError:
|
||||||
|
# Failed to import our package, which likely means we were started directly
|
||||||
|
# Add the additional search path needed to locate our module.
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||||
|
|
||||||
|
from layout.main import main
|
||||||
|
|
||||||
|
sys.exit(int(main() or 0))
|
|
@ -0,0 +1,616 @@
|
||||||
|
"""
|
||||||
|
Generates a layout of Python for Windows from a build.
|
||||||
|
|
||||||
|
See python make_layout.py --help for usage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Started directly, so enable relative imports
|
||||||
|
__path__ = [str(Path(__file__).resolve().parent)]
|
||||||
|
|
||||||
|
from .support.appxmanifest import *
|
||||||
|
from .support.catalog import *
|
||||||
|
from .support.constants import *
|
||||||
|
from .support.filesets import *
|
||||||
|
from .support.logging import *
|
||||||
|
from .support.options import *
|
||||||
|
from .support.pip import *
|
||||||
|
from .support.props import *
|
||||||
|
|
||||||
|
BDIST_WININST_FILES_ONLY = FileNameSet("wininst-*", "bdist_wininst.py")
|
||||||
|
BDIST_WININST_STUB = "PC/layout/support/distutils.command.bdist_wininst.py"
|
||||||
|
|
||||||
|
TEST_PYDS_ONLY = FileStemSet("xxlimited", "_ctypes_test", "_test*")
|
||||||
|
TEST_DIRS_ONLY = FileNameSet("test", "tests")
|
||||||
|
|
||||||
|
IDLE_DIRS_ONLY = FileNameSet("idlelib")
|
||||||
|
|
||||||
|
TCLTK_PYDS_ONLY = FileStemSet("tcl*", "tk*", "_tkinter")
|
||||||
|
TCLTK_DIRS_ONLY = FileNameSet("tkinter", "turtledemo")
|
||||||
|
TCLTK_FILES_ONLY = FileNameSet("turtle.py")
|
||||||
|
|
||||||
|
VENV_DIRS_ONLY = FileNameSet("venv", "ensurepip")
|
||||||
|
|
||||||
|
EXCLUDE_FROM_PYDS = FileStemSet("python*", "pyshellext")
|
||||||
|
EXCLUDE_FROM_LIB = FileNameSet("*.pyc", "__pycache__", "*.pickle")
|
||||||
|
EXCLUDE_FROM_PACKAGED_LIB = FileNameSet("readme.txt")
|
||||||
|
EXCLUDE_FROM_COMPILE = FileNameSet("badsyntax_*", "bad_*")
|
||||||
|
EXCLUDE_FROM_CATALOG = FileSuffixSet(".exe", ".pyd", ".dll")
|
||||||
|
|
||||||
|
REQUIRED_DLLS = FileStemSet("libcrypto*", "libssl*")
|
||||||
|
|
||||||
|
LIB2TO3_GRAMMAR_FILES = FileNameSet("Grammar.txt", "PatternGrammar.txt")
|
||||||
|
|
||||||
|
PY_FILES = FileSuffixSet(".py")
|
||||||
|
PYC_FILES = FileSuffixSet(".pyc")
|
||||||
|
CAT_FILES = FileSuffixSet(".cat")
|
||||||
|
CDF_FILES = FileSuffixSet(".cdf")
|
||||||
|
|
||||||
|
DATA_DIRS = FileNameSet("data")
|
||||||
|
|
||||||
|
TOOLS_DIRS = FileNameSet("scripts", "i18n", "pynche", "demo", "parser")
|
||||||
|
TOOLS_FILES = FileSuffixSet(".py", ".pyw", ".txt")
|
||||||
|
|
||||||
|
|
||||||
|
def get_lib_layout(ns):
|
||||||
|
def _c(f):
|
||||||
|
if f in EXCLUDE_FROM_LIB:
|
||||||
|
return False
|
||||||
|
if f.is_dir():
|
||||||
|
if f in TEST_DIRS_ONLY:
|
||||||
|
return ns.include_tests
|
||||||
|
if f in TCLTK_DIRS_ONLY:
|
||||||
|
return ns.include_tcltk
|
||||||
|
if f in IDLE_DIRS_ONLY:
|
||||||
|
return ns.include_idle
|
||||||
|
if f in VENV_DIRS_ONLY:
|
||||||
|
return ns.include_venv
|
||||||
|
else:
|
||||||
|
if f in TCLTK_FILES_ONLY:
|
||||||
|
return ns.include_tcltk
|
||||||
|
if f in BDIST_WININST_FILES_ONLY:
|
||||||
|
return ns.include_bdist_wininst
|
||||||
|
return True
|
||||||
|
|
||||||
|
for dest, src in rglob(ns.source / "Lib", "**/*", _c):
|
||||||
|
yield dest, src
|
||||||
|
|
||||||
|
if not ns.include_bdist_wininst:
|
||||||
|
src = ns.source / BDIST_WININST_STUB
|
||||||
|
yield Path("distutils/command/bdist_wininst.py"), src
|
||||||
|
|
||||||
|
|
||||||
|
def get_tcltk_lib(ns):
|
||||||
|
if not ns.include_tcltk:
|
||||||
|
return
|
||||||
|
|
||||||
|
tcl_lib = os.getenv("TCL_LIBRARY")
|
||||||
|
if not tcl_lib or not os.path.isdir(tcl_lib):
|
||||||
|
try:
|
||||||
|
with open(ns.build / "TCL_LIBRARY.env", "r", encoding="utf-8-sig") as f:
|
||||||
|
tcl_lib = f.read().strip()
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
if not tcl_lib or not os.path.isdir(tcl_lib):
|
||||||
|
warn("Failed to find TCL_LIBRARY")
|
||||||
|
return
|
||||||
|
|
||||||
|
for dest, src in rglob(Path(tcl_lib).parent, "**/*"):
|
||||||
|
yield "tcl/{}".format(dest), src
|
||||||
|
|
||||||
|
|
||||||
|
def get_layout(ns):
|
||||||
|
def in_build(f, dest="", new_name=None):
|
||||||
|
n, _, x = f.rpartition(".")
|
||||||
|
n = new_name or n
|
||||||
|
src = ns.build / f
|
||||||
|
if ns.debug and src not in REQUIRED_DLLS:
|
||||||
|
if not src.stem.endswith("_d"):
|
||||||
|
src = src.parent / (src.stem + "_d" + src.suffix)
|
||||||
|
if not n.endswith("_d"):
|
||||||
|
n += "_d"
|
||||||
|
f = n + "." + x
|
||||||
|
yield dest + n + "." + x, src
|
||||||
|
if ns.include_symbols:
|
||||||
|
pdb = src.with_suffix(".pdb")
|
||||||
|
if pdb.is_file():
|
||||||
|
yield dest + n + ".pdb", pdb
|
||||||
|
if ns.include_dev:
|
||||||
|
lib = src.with_suffix(".lib")
|
||||||
|
if lib.is_file():
|
||||||
|
yield "libs/" + n + ".lib", lib
|
||||||
|
|
||||||
|
if ns.include_appxmanifest:
|
||||||
|
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")
|
||||||
|
|
||||||
|
yield from in_build(PYTHON_DLL_NAME)
|
||||||
|
|
||||||
|
if ns.include_launchers and ns.include_appxmanifest:
|
||||||
|
if ns.include_pip:
|
||||||
|
yield from in_build("python_uwp.exe", new_name="pip")
|
||||||
|
if ns.include_idle:
|
||||||
|
yield from in_build("pythonw_uwp.exe", new_name="idle")
|
||||||
|
|
||||||
|
if ns.include_stable:
|
||||||
|
yield from in_build(PYTHON_STABLE_DLL_NAME)
|
||||||
|
|
||||||
|
for dest, src in rglob(ns.build, "vcruntime*.dll"):
|
||||||
|
yield dest, src
|
||||||
|
|
||||||
|
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
|
||||||
|
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/")
|
||||||
|
|
||||||
|
if ns.zip_lib:
|
||||||
|
zip_name = PYTHON_ZIP_NAME
|
||||||
|
yield zip_name, ns.temp / zip_name
|
||||||
|
else:
|
||||||
|
for dest, src in get_lib_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_tools:
|
||||||
|
|
||||||
|
def _c(d):
|
||||||
|
if d.is_dir():
|
||||||
|
return d in TOOLS_DIRS
|
||||||
|
return d in TOOLS_FILES
|
||||||
|
|
||||||
|
for dest, src in rglob(ns.source / "Tools", "**/*", _c):
|
||||||
|
yield "Tools/{}".format(dest), src
|
||||||
|
|
||||||
|
if ns.include_underpth:
|
||||||
|
yield PYTHON_PTH_NAME, ns.temp / PYTHON_PTH_NAME
|
||||||
|
|
||||||
|
if ns.include_dev:
|
||||||
|
|
||||||
|
def _c(d):
|
||||||
|
if d.is_dir():
|
||||||
|
return d.name != "internal"
|
||||||
|
return True
|
||||||
|
|
||||||
|
for dest, src in rglob(ns.source / "Include", "**/*.h", _c):
|
||||||
|
yield "include/{}".format(dest), src
|
||||||
|
src = ns.source / "PC" / "pyconfig.h"
|
||||||
|
yield "include/pyconfig.h", src
|
||||||
|
|
||||||
|
for dest, src in get_tcltk_lib(ns):
|
||||||
|
yield dest, src
|
||||||
|
|
||||||
|
if ns.include_pip:
|
||||||
|
pip_dir = get_pip_dir(ns)
|
||||||
|
if not pip_dir.is_dir():
|
||||||
|
log_warning("Failed to find {} - pip will not be included", pip_dir)
|
||||||
|
else:
|
||||||
|
pkg_root = "packages/{}" if ns.zip_lib else "Lib/site-packages/{}"
|
||||||
|
for dest, src in rglob(pip_dir, "**/*"):
|
||||||
|
if src in EXCLUDE_FROM_LIB or src in EXCLUDE_FROM_PACKAGED_LIB:
|
||||||
|
continue
|
||||||
|
yield pkg_root.format(dest), src
|
||||||
|
|
||||||
|
if ns.include_chm:
|
||||||
|
for dest, src in rglob(ns.doc_build / "htmlhelp", PYTHON_CHM_NAME):
|
||||||
|
yield "Doc/{}".format(dest), src
|
||||||
|
|
||||||
|
if ns.include_html_doc:
|
||||||
|
for dest, src in rglob(ns.doc_build / "html", "**/*"):
|
||||||
|
yield "Doc/html/{}".format(dest), src
|
||||||
|
|
||||||
|
if ns.include_props:
|
||||||
|
for dest, src in get_props_layout(ns):
|
||||||
|
yield dest, src
|
||||||
|
|
||||||
|
for dest, src in get_appx_layout(ns):
|
||||||
|
yield dest, src
|
||||||
|
|
||||||
|
if ns.include_cat:
|
||||||
|
if ns.flat_dlls:
|
||||||
|
yield ns.include_cat.name, ns.include_cat
|
||||||
|
else:
|
||||||
|
yield "DLLs/{}".format(ns.include_cat.name), ns.include_cat
|
||||||
|
|
||||||
|
|
||||||
|
def _compile_one_py(src, dest, name, optimize):
|
||||||
|
import py_compile
|
||||||
|
|
||||||
|
if dest is not None:
|
||||||
|
dest = str(dest)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return Path(
|
||||||
|
py_compile.compile(
|
||||||
|
str(src),
|
||||||
|
dest,
|
||||||
|
str(name),
|
||||||
|
doraise=True,
|
||||||
|
optimize=optimize,
|
||||||
|
invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except py_compile.PyCompileError:
|
||||||
|
log_warning("Failed to compile {}", src)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _py_temp_compile(src, ns, dest_dir=None):
|
||||||
|
if not ns.precompile or src not in PY_FILES or src.parent in DATA_DIRS:
|
||||||
|
return None
|
||||||
|
|
||||||
|
dest = (dest_dir or ns.temp) / (src.stem + ".py")
|
||||||
|
return _compile_one_py(src, dest.with_suffix(".pyc"), dest, optimize=2)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_to_zip(zf, dest, src, ns):
|
||||||
|
pyc = _py_temp_compile(src, ns)
|
||||||
|
if pyc:
|
||||||
|
try:
|
||||||
|
zf.write(str(pyc), dest.with_suffix(".pyc"))
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
pyc.unlink()
|
||||||
|
except:
|
||||||
|
log_exception("Failed to delete {}", pyc)
|
||||||
|
return
|
||||||
|
|
||||||
|
if src in LIB2TO3_GRAMMAR_FILES:
|
||||||
|
from lib2to3.pgen2.driver import load_grammar
|
||||||
|
|
||||||
|
tmp = ns.temp / src.name
|
||||||
|
try:
|
||||||
|
shutil.copy(src, tmp)
|
||||||
|
load_grammar(str(tmp))
|
||||||
|
for f in ns.temp.glob(src.stem + "*.pickle"):
|
||||||
|
zf.write(str(f), str(dest.parent / f.name))
|
||||||
|
try:
|
||||||
|
f.unlink()
|
||||||
|
except:
|
||||||
|
log_exception("Failed to delete {}", f)
|
||||||
|
except:
|
||||||
|
log_exception("Failed to compile {}", src)
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
tmp.unlink()
|
||||||
|
except:
|
||||||
|
log_exception("Failed to delete {}", tmp)
|
||||||
|
|
||||||
|
zf.write(str(src), str(dest))
|
||||||
|
|
||||||
|
|
||||||
|
def generate_source_files(ns):
|
||||||
|
if ns.zip_lib:
|
||||||
|
zip_name = PYTHON_ZIP_NAME
|
||||||
|
zip_path = ns.temp / zip_name
|
||||||
|
if zip_path.is_file():
|
||||||
|
zip_path.unlink()
|
||||||
|
elif zip_path.is_dir():
|
||||||
|
log_error(
|
||||||
|
"Cannot create zip file because a directory exists by the same name"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
log_info("Generating {} in {}", zip_name, ns.temp)
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||||
|
for dest, src in get_lib_layout(ns):
|
||||||
|
_write_to_zip(zf, dest, src, ns)
|
||||||
|
|
||||||
|
if ns.include_underpth:
|
||||||
|
log_info("Generating {} in {}", PYTHON_PTH_NAME, ns.temp)
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(ns.temp / PYTHON_PTH_NAME, "w", encoding="utf-8") as f:
|
||||||
|
if ns.zip_lib:
|
||||||
|
print(PYTHON_ZIP_NAME, file=f)
|
||||||
|
if ns.include_pip:
|
||||||
|
print("packages", file=f)
|
||||||
|
else:
|
||||||
|
print("Lib", file=f)
|
||||||
|
print("Lib/site-packages", file=f)
|
||||||
|
if not ns.flat_dlls:
|
||||||
|
print("DLLs", file=f)
|
||||||
|
print(".", file=f)
|
||||||
|
print(file=f)
|
||||||
|
print("# Uncomment to run site.main() automatically", file=f)
|
||||||
|
print("#import site", file=f)
|
||||||
|
|
||||||
|
if ns.include_appxmanifest:
|
||||||
|
log_info("Generating AppxManifest.xml in {}", ns.temp)
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(ns.temp / "AppxManifest.xml", "wb") as f:
|
||||||
|
f.write(get_appxmanifest(ns))
|
||||||
|
|
||||||
|
with open(ns.temp / "_resources.xml", "wb") as f:
|
||||||
|
f.write(get_resources_xml(ns))
|
||||||
|
|
||||||
|
if ns.include_pip:
|
||||||
|
pip_dir = get_pip_dir(ns)
|
||||||
|
if not (pip_dir / "pip").is_dir():
|
||||||
|
log_info("Extracting pip to {}", pip_dir)
|
||||||
|
pip_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
extract_pip_files(ns)
|
||||||
|
|
||||||
|
if ns.include_props:
|
||||||
|
log_info("Generating {} in {}", PYTHON_PROPS_NAME, ns.temp)
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(ns.temp / PYTHON_PROPS_NAME, "wb") as f:
|
||||||
|
f.write(get_props(ns))
|
||||||
|
|
||||||
|
|
||||||
|
def _create_zip_file(ns):
|
||||||
|
if not ns.zip:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if ns.zip.is_file():
|
||||||
|
try:
|
||||||
|
ns.zip.unlink()
|
||||||
|
except OSError:
|
||||||
|
log_exception("Unable to remove {}", ns.zip)
|
||||||
|
sys.exit(8)
|
||||||
|
elif ns.zip.is_dir():
|
||||||
|
log_error("Cannot create ZIP file because {} is a directory", ns.zip)
|
||||||
|
sys.exit(8)
|
||||||
|
|
||||||
|
ns.zip.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
return zipfile.ZipFile(ns.zip, "w", zipfile.ZIP_DEFLATED)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_files(files, ns):
|
||||||
|
if ns.copy:
|
||||||
|
ns.copy.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
total = len(files)
|
||||||
|
except TypeError:
|
||||||
|
total = None
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
zip_file = _create_zip_file(ns)
|
||||||
|
try:
|
||||||
|
need_compile = []
|
||||||
|
in_catalog = []
|
||||||
|
|
||||||
|
for dest, src in files:
|
||||||
|
count += 1
|
||||||
|
if count % 10 == 0:
|
||||||
|
if total:
|
||||||
|
log_info("Processed {:>4} of {} files", count, total)
|
||||||
|
else:
|
||||||
|
log_info("Processed {} files", count)
|
||||||
|
log_debug("Processing {!s}", src)
|
||||||
|
|
||||||
|
if (
|
||||||
|
ns.precompile
|
||||||
|
and src in PY_FILES
|
||||||
|
and src not in EXCLUDE_FROM_COMPILE
|
||||||
|
and src.parent not in DATA_DIRS
|
||||||
|
and os.path.normcase(str(dest)).startswith(os.path.normcase("Lib"))
|
||||||
|
):
|
||||||
|
if ns.copy:
|
||||||
|
need_compile.append((dest, ns.copy / dest))
|
||||||
|
else:
|
||||||
|
(ns.temp / "Lib" / dest).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copy2(src, ns.temp / "Lib" / dest)
|
||||||
|
need_compile.append((dest, ns.temp / "Lib" / dest))
|
||||||
|
|
||||||
|
if src not in EXCLUDE_FROM_CATALOG:
|
||||||
|
in_catalog.append((src.name, src))
|
||||||
|
|
||||||
|
if ns.copy:
|
||||||
|
log_debug("Copy {} -> {}", src, ns.copy / dest)
|
||||||
|
(ns.copy / dest).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
try:
|
||||||
|
shutil.copy2(src, ns.copy / dest)
|
||||||
|
except shutil.SameFileError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if ns.zip:
|
||||||
|
log_debug("Zip {} into {}", src, ns.zip)
|
||||||
|
zip_file.write(src, str(dest))
|
||||||
|
|
||||||
|
if need_compile:
|
||||||
|
for dest, src in need_compile:
|
||||||
|
compiled = [
|
||||||
|
_compile_one_py(src, None, dest, optimize=0),
|
||||||
|
_compile_one_py(src, None, dest, optimize=1),
|
||||||
|
_compile_one_py(src, None, dest, optimize=2),
|
||||||
|
]
|
||||||
|
for c in compiled:
|
||||||
|
if not c:
|
||||||
|
continue
|
||||||
|
cdest = Path(dest).parent / Path(c).relative_to(src.parent)
|
||||||
|
if ns.zip:
|
||||||
|
log_debug("Zip {} into {}", c, ns.zip)
|
||||||
|
zip_file.write(c, str(cdest))
|
||||||
|
in_catalog.append((cdest.name, cdest))
|
||||||
|
|
||||||
|
if ns.catalog:
|
||||||
|
# Just write out the CDF now. Compilation and signing is
|
||||||
|
# an extra step
|
||||||
|
log_info("Generating {}", ns.catalog)
|
||||||
|
ns.catalog.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
write_catalog(ns.catalog, in_catalog)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if zip_file:
|
||||||
|
zip_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("-v", help="Increase verbosity", action="count")
|
||||||
|
parser.add_argument(
|
||||||
|
"-s",
|
||||||
|
"--source",
|
||||||
|
metavar="dir",
|
||||||
|
help="The directory containing the repository root",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-b", "--build", metavar="dir", help="Specify the build directory", type=Path
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--doc-build",
|
||||||
|
metavar="dir",
|
||||||
|
help="Specify the docs build directory",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--copy",
|
||||||
|
metavar="directory",
|
||||||
|
help="The name of the directory to copy an extracted layout to",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--zip",
|
||||||
|
metavar="file",
|
||||||
|
help="The ZIP file to write all files to",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--catalog",
|
||||||
|
metavar="file",
|
||||||
|
help="The CDF file to write catalog entries to",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--log",
|
||||||
|
metavar="file",
|
||||||
|
help="Write all operations to the specified file",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--temp",
|
||||||
|
metavar="file",
|
||||||
|
help="A temporary working directory",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d", "--debug", help="Include debug build", action="store_true"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-p",
|
||||||
|
"--precompile",
|
||||||
|
help="Include .pyc files instead of .py",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-z", "--zip-lib", help="Include library in a ZIP file", action="store_true"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--flat-dlls", help="Does not create a DLLs directory", action="store_true"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--include-all",
|
||||||
|
help="Include all optional components",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--include-cat",
|
||||||
|
metavar="file",
|
||||||
|
help="Specify the catalog file to include",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
for opt, help in get_argparse_options():
|
||||||
|
parser.add_argument(opt, help=help, action="store_true")
|
||||||
|
|
||||||
|
ns = parser.parse_args()
|
||||||
|
update_presets(ns)
|
||||||
|
|
||||||
|
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 not ns.build.is_absolute():
|
||||||
|
ns.build = (Path.cwd() / ns.build).resolve()
|
||||||
|
if not ns.temp.is_absolute():
|
||||||
|
ns.temp = (Path.cwd() / ns.temp).resolve()
|
||||||
|
if not ns.doc_build.is_absolute():
|
||||||
|
ns.doc_build = (Path.cwd() / ns.doc_build).resolve()
|
||||||
|
if ns.include_cat and not ns.include_cat.is_absolute():
|
||||||
|
ns.include_cat = (Path.cwd() / ns.include_cat).resolve()
|
||||||
|
|
||||||
|
if ns.copy and not ns.copy.is_absolute():
|
||||||
|
ns.copy = (Path.cwd() / ns.copy).resolve()
|
||||||
|
if ns.zip and not ns.zip.is_absolute():
|
||||||
|
ns.zip = (Path.cwd() / ns.zip).resolve()
|
||||||
|
if ns.catalog and not ns.catalog.is_absolute():
|
||||||
|
ns.catalog = (Path.cwd() / ns.catalog).resolve()
|
||||||
|
|
||||||
|
configure_logger(ns)
|
||||||
|
|
||||||
|
log_info(
|
||||||
|
"""OPTIONS
|
||||||
|
Source: {ns.source}
|
||||||
|
Build: {ns.build}
|
||||||
|
Temp: {ns.temp}
|
||||||
|
|
||||||
|
Copy to: {ns.copy}
|
||||||
|
Zip to: {ns.zip}
|
||||||
|
Catalog: {ns.catalog}""",
|
||||||
|
ns=ns,
|
||||||
|
)
|
||||||
|
|
||||||
|
if ns.include_idle and not ns.include_tcltk:
|
||||||
|
log_warning("Assuming --include-tcltk to support --include-idle")
|
||||||
|
ns.include_tcltk = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
generate_source_files(ns)
|
||||||
|
files = list(get_layout(ns))
|
||||||
|
copy_files(files, ns)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
log_info("Interrupted by Ctrl+C")
|
||||||
|
return 3
|
||||||
|
except SystemExit:
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
log_exception("Unhandled error")
|
||||||
|
|
||||||
|
if error_was_logged():
|
||||||
|
log_error("Errors occurred.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(int(main() or 0))
|
|
@ -0,0 +1,487 @@
|
||||||
|
"""
|
||||||
|
File generation for APPX/MSIX manifests.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import ctypes
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pathlib import Path, PureWindowsPath
|
||||||
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
|
from .constants import *
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
|
||||||
|
|
||||||
|
def public(f):
|
||||||
|
__all__.append(f.__name__)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
APPX_DATA = dict(
|
||||||
|
Name="PythonSoftwareFoundation.Python.{}".format(VER_DOT),
|
||||||
|
Version="{}.{}.{}.0".format(VER_MAJOR, VER_MINOR, VER_FIELD3),
|
||||||
|
Publisher=os.getenv(
|
||||||
|
"APPX_DATA_PUBLISHER", "CN=4975D53F-AA7E-49A5-8B49-EA4FDC1BB66B"
|
||||||
|
),
|
||||||
|
DisplayName="Python {}".format(VER_DOT),
|
||||||
|
Description="The Python {} runtime and console.".format(VER_DOT),
|
||||||
|
ProcessorArchitecture="x64" if IS_X64 else "x86",
|
||||||
|
)
|
||||||
|
|
||||||
|
PYTHON_VE_DATA = dict(
|
||||||
|
DisplayName="Python {}".format(VER_DOT),
|
||||||
|
Description="Python interactive console",
|
||||||
|
Square150x150Logo="_resources/pythonx150.png",
|
||||||
|
Square44x44Logo="_resources/pythonx44.png",
|
||||||
|
BackgroundColor="transparent",
|
||||||
|
)
|
||||||
|
|
||||||
|
PYTHONW_VE_DATA = dict(
|
||||||
|
DisplayName="Python {} (Windowed)".format(VER_DOT),
|
||||||
|
Description="Python windowed app launcher",
|
||||||
|
Square150x150Logo="_resources/pythonwx150.png",
|
||||||
|
Square44x44Logo="_resources/pythonwx44.png",
|
||||||
|
BackgroundColor="transparent",
|
||||||
|
AppListEntry="none",
|
||||||
|
)
|
||||||
|
|
||||||
|
PIP_VE_DATA = dict(
|
||||||
|
DisplayName="pip (Python {})".format(VER_DOT),
|
||||||
|
Description="pip package manager for Python {}".format(VER_DOT),
|
||||||
|
Square150x150Logo="_resources/pythonx150.png",
|
||||||
|
Square44x44Logo="_resources/pythonx44.png",
|
||||||
|
BackgroundColor="transparent",
|
||||||
|
AppListEntry="none",
|
||||||
|
)
|
||||||
|
|
||||||
|
IDLE_VE_DATA = dict(
|
||||||
|
DisplayName="IDLE (Python {})".format(VER_DOT),
|
||||||
|
Description="IDLE editor for Python {}".format(VER_DOT),
|
||||||
|
Square150x150Logo="_resources/pythonwx150.png",
|
||||||
|
Square44x44Logo="_resources/pythonwx44.png",
|
||||||
|
BackgroundColor="transparent",
|
||||||
|
)
|
||||||
|
|
||||||
|
APPXMANIFEST_NS = {
|
||||||
|
"": "http://schemas.microsoft.com/appx/manifest/foundation/windows10",
|
||||||
|
"m": "http://schemas.microsoft.com/appx/manifest/foundation/windows10",
|
||||||
|
"uap": "http://schemas.microsoft.com/appx/manifest/uap/windows10",
|
||||||
|
"rescap": "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities",
|
||||||
|
"rescap4": "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/4",
|
||||||
|
"desktop4": "http://schemas.microsoft.com/appx/manifest/desktop/windows10/4",
|
||||||
|
"desktop6": "http://schemas.microsoft.com/appx/manifest/desktop/windows10/6",
|
||||||
|
"uap3": "http://schemas.microsoft.com/appx/manifest/uap/windows10/3",
|
||||||
|
"uap4": "http://schemas.microsoft.com/appx/manifest/uap/windows10/4",
|
||||||
|
"uap5": "http://schemas.microsoft.com/appx/manifest/uap/windows10/5",
|
||||||
|
}
|
||||||
|
|
||||||
|
APPXMANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||||
|
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||||
|
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||||
|
xmlns:rescap4="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/4"
|
||||||
|
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
|
||||||
|
xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4"
|
||||||
|
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5">
|
||||||
|
<Identity Name=""
|
||||||
|
Version=""
|
||||||
|
Publisher=""
|
||||||
|
ProcessorArchitecture="" />
|
||||||
|
<Properties>
|
||||||
|
<DisplayName></DisplayName>
|
||||||
|
<PublisherDisplayName>Python Software Foundation</PublisherDisplayName>
|
||||||
|
<Description></Description>
|
||||||
|
<Logo>_resources/pythonx50.png</Logo>
|
||||||
|
</Properties>
|
||||||
|
<Resources>
|
||||||
|
<Resource Language="en-US" />
|
||||||
|
</Resources>
|
||||||
|
<Dependencies>
|
||||||
|
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="" />
|
||||||
|
</Dependencies>
|
||||||
|
<Capabilities>
|
||||||
|
<rescap:Capability Name="runFullTrust"/>
|
||||||
|
</Capabilities>
|
||||||
|
<Applications>
|
||||||
|
</Applications>
|
||||||
|
<Extensions>
|
||||||
|
</Extensions>
|
||||||
|
</Package>"""
|
||||||
|
|
||||||
|
|
||||||
|
RESOURCES_XML_TEMPLATE = r"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<!--This file is input for makepri.exe. It should be excluded from the final package.-->
|
||||||
|
<resources targetOsVersion="10.0.0" majorVersion="1">
|
||||||
|
<packaging>
|
||||||
|
<autoResourcePackage qualifier="Language"/>
|
||||||
|
<autoResourcePackage qualifier="Scale"/>
|
||||||
|
<autoResourcePackage qualifier="DXFeatureLevel"/>
|
||||||
|
</packaging>
|
||||||
|
<index root="\" startIndexAt="\">
|
||||||
|
<default>
|
||||||
|
<qualifier name="Language" value="en-US"/>
|
||||||
|
<qualifier name="Contrast" value="standard"/>
|
||||||
|
<qualifier name="Scale" value="100"/>
|
||||||
|
<qualifier name="HomeRegion" value="001"/>
|
||||||
|
<qualifier name="TargetSize" value="256"/>
|
||||||
|
<qualifier name="LayoutDirection" value="LTR"/>
|
||||||
|
<qualifier name="Theme" value="dark"/>
|
||||||
|
<qualifier name="AlternateForm" value=""/>
|
||||||
|
<qualifier name="DXFeatureLevel" value="DX9"/>
|
||||||
|
<qualifier name="Configuration" value=""/>
|
||||||
|
<qualifier name="DeviceFamily" value="Universal"/>
|
||||||
|
<qualifier name="Custom" value=""/>
|
||||||
|
</default>
|
||||||
|
<indexer-config type="folder" foldernameAsQualifier="true" filenameAsQualifier="true" qualifierDelimiter="$"/>
|
||||||
|
<indexer-config type="resw" convertDotsToSlashes="true" initialPath=""/>
|
||||||
|
<indexer-config type="resjson" initialPath=""/>
|
||||||
|
<indexer-config type="PRI"/>
|
||||||
|
</index>
|
||||||
|
</resources>"""
|
||||||
|
|
||||||
|
|
||||||
|
SCCD_FILENAME = "PC/classicAppCompat.sccd"
|
||||||
|
|
||||||
|
REGISTRY = {
|
||||||
|
"HKCU\\Software\\Python\\PythonCore": {
|
||||||
|
VER_DOT: {
|
||||||
|
"DisplayName": APPX_DATA["DisplayName"],
|
||||||
|
"SupportUrl": "https://www.python.org/",
|
||||||
|
"SysArchitecture": "64bit" if IS_X64 else "32bit",
|
||||||
|
"SysVersion": VER_DOT,
|
||||||
|
"Version": "{}.{}.{}".format(VER_MAJOR, VER_MINOR, VER_MICRO),
|
||||||
|
"InstallPath": {
|
||||||
|
# I have no idea why the trailing spaces are needed, but they seem to be needed.
|
||||||
|
"": "[{AppVPackageRoot}][ ]",
|
||||||
|
"ExecutablePath": "[{AppVPackageRoot}]python.exe[ ]",
|
||||||
|
"WindowedExecutablePath": "[{AppVPackageRoot}]pythonw.exe[ ]",
|
||||||
|
},
|
||||||
|
"Help": {
|
||||||
|
"Main Python Documentation": {
|
||||||
|
"_condition": lambda ns: ns.include_chm,
|
||||||
|
"": "[{{AppVPackageRoot}}]Doc\\{}[ ]".format(
|
||||||
|
PYTHON_CHM_NAME
|
||||||
|
),
|
||||||
|
},
|
||||||
|
"Local Python Documentation": {
|
||||||
|
"_condition": lambda ns: ns.include_html_doc,
|
||||||
|
"": "[{AppVPackageRoot}]Doc\\html\\index.html[ ]",
|
||||||
|
},
|
||||||
|
"Online Python Documentation": {
|
||||||
|
"": "https://docs.python.org/{}".format(VER_DOT)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Idle": {
|
||||||
|
"_condition": lambda ns: ns.include_idle,
|
||||||
|
"": "[{AppVPackageRoot}]Lib\\idlelib\\idle.pyw[ ]",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_packagefamilyname(name, publisher_id):
|
||||||
|
class PACKAGE_ID(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
("reserved", ctypes.c_uint32),
|
||||||
|
("processorArchitecture", ctypes.c_uint32),
|
||||||
|
("version", ctypes.c_uint64),
|
||||||
|
("name", ctypes.c_wchar_p),
|
||||||
|
("publisher", ctypes.c_wchar_p),
|
||||||
|
("resourceId", ctypes.c_wchar_p),
|
||||||
|
("publisherId", ctypes.c_wchar_p),
|
||||||
|
]
|
||||||
|
_pack_ = 4
|
||||||
|
|
||||||
|
pid = PACKAGE_ID(0, 0, 0, name, publisher_id, None, None)
|
||||||
|
result = ctypes.create_unicode_buffer(256)
|
||||||
|
result_len = ctypes.c_uint32(256)
|
||||||
|
r = ctypes.windll.kernel32.PackageFamilyNameFromId(
|
||||||
|
pid, ctypes.byref(result_len), result
|
||||||
|
)
|
||||||
|
if r:
|
||||||
|
raise OSError(r, "failed to get package family name")
|
||||||
|
return result.value[: result_len.value]
|
||||||
|
|
||||||
|
|
||||||
|
def _fixup_sccd(ns, sccd, new_hash=None):
|
||||||
|
if not new_hash:
|
||||||
|
return sccd
|
||||||
|
|
||||||
|
NS = dict(s="http://schemas.microsoft.com/appx/2016/sccd")
|
||||||
|
with open(sccd, "rb") as f:
|
||||||
|
xml = ET.parse(f)
|
||||||
|
|
||||||
|
pfn = get_packagefamilyname(APPX_DATA["Name"], APPX_DATA["Publisher"])
|
||||||
|
|
||||||
|
ae = xml.find("s:AuthorizedEntities", NS)
|
||||||
|
ae.clear()
|
||||||
|
|
||||||
|
e = ET.SubElement(ae, ET.QName(NS["s"], "AuthorizedEntity"))
|
||||||
|
e.set("AppPackageFamilyName", pfn)
|
||||||
|
e.set("CertificateSignatureHash", new_hash)
|
||||||
|
|
||||||
|
for e in xml.findall("s:Catalog", NS):
|
||||||
|
e.text = "FFFF"
|
||||||
|
|
||||||
|
sccd = ns.temp / sccd.name
|
||||||
|
sccd.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(sccd, "wb") as f:
|
||||||
|
xml.write(f, encoding="utf-8")
|
||||||
|
|
||||||
|
return sccd
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def get_appx_layout(ns):
|
||||||
|
if not ns.include_appxmanifest:
|
||||||
|
return
|
||||||
|
|
||||||
|
yield "AppxManifest.xml", ns.temp / "AppxManifest.xml"
|
||||||
|
yield "_resources.xml", ns.temp / "_resources.xml"
|
||||||
|
icons = ns.source / "PC" / "icons"
|
||||||
|
yield "_resources/pythonx44.png", icons / "pythonx44.png"
|
||||||
|
yield "_resources/pythonx44$targetsize-44_altform-unplated.png", icons / "pythonx44.png"
|
||||||
|
yield "_resources/pythonx50.png", icons / "pythonx50.png"
|
||||||
|
yield "_resources/pythonx50$targetsize-50_altform-unplated.png", icons / "pythonx50.png"
|
||||||
|
yield "_resources/pythonx150.png", icons / "pythonx150.png"
|
||||||
|
yield "_resources/pythonx150$targetsize-150_altform-unplated.png", icons / "pythonx150.png"
|
||||||
|
yield "_resources/pythonwx44.png", icons / "pythonwx44.png"
|
||||||
|
yield "_resources/pythonwx44$targetsize-44_altform-unplated.png", icons / "pythonwx44.png"
|
||||||
|
yield "_resources/pythonwx150.png", icons / "pythonwx150.png"
|
||||||
|
yield "_resources/pythonwx150$targetsize-150_altform-unplated.png", icons / "pythonwx150.png"
|
||||||
|
sccd = ns.source / SCCD_FILENAME
|
||||||
|
if sccd.is_file():
|
||||||
|
# This should only be set for side-loading purposes.
|
||||||
|
sccd = _fixup_sccd(ns, sccd, os.getenv("APPX_DATA_SHA256"))
|
||||||
|
yield sccd.name, sccd
|
||||||
|
|
||||||
|
|
||||||
|
def find_or_add(xml, element, attr=None, always_add=False):
|
||||||
|
if always_add:
|
||||||
|
e = None
|
||||||
|
else:
|
||||||
|
q = element
|
||||||
|
if attr:
|
||||||
|
q += "[@{}='{}']".format(*attr)
|
||||||
|
e = xml.find(q, APPXMANIFEST_NS)
|
||||||
|
if e is None:
|
||||||
|
prefix, _, name = element.partition(":")
|
||||||
|
name = ET.QName(APPXMANIFEST_NS[prefix or ""], name)
|
||||||
|
e = ET.SubElement(xml, name)
|
||||||
|
if attr:
|
||||||
|
e.set(*attr)
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def _get_app(xml, appid):
|
||||||
|
if appid:
|
||||||
|
app = xml.find(
|
||||||
|
"m:Applications/m:Application[@Id='{}']".format(appid), APPXMANIFEST_NS
|
||||||
|
)
|
||||||
|
if app is None:
|
||||||
|
raise LookupError(appid)
|
||||||
|
else:
|
||||||
|
app = xml
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
def add_visual(xml, appid, data):
|
||||||
|
app = _get_app(xml, appid)
|
||||||
|
e = find_or_add(app, "uap:VisualElements")
|
||||||
|
for i in data.items():
|
||||||
|
e.set(*i)
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def add_alias(xml, appid, alias, subsystem="windows"):
|
||||||
|
app = _get_app(xml, appid)
|
||||||
|
e = find_or_add(app, "m:Extensions")
|
||||||
|
e = find_or_add(e, "uap5:Extension", ("Category", "windows.appExecutionAlias"))
|
||||||
|
e = find_or_add(e, "uap5:AppExecutionAlias")
|
||||||
|
e.set(ET.QName(APPXMANIFEST_NS["desktop4"], "Subsystem"), subsystem)
|
||||||
|
e = find_or_add(e, "uap5:ExecutionAlias", ("Alias", alias))
|
||||||
|
|
||||||
|
|
||||||
|
def add_file_type(xml, appid, name, suffix, parameters='"%1"'):
|
||||||
|
app = _get_app(xml, appid)
|
||||||
|
e = find_or_add(app, "m:Extensions")
|
||||||
|
e = find_or_add(e, "uap3:Extension", ("Category", "windows.fileTypeAssociation"))
|
||||||
|
e = find_or_add(e, "uap3:FileTypeAssociation", ("Name", name))
|
||||||
|
e.set("Parameters", parameters)
|
||||||
|
e = find_or_add(e, "uap:SupportedFileTypes")
|
||||||
|
if isinstance(suffix, str):
|
||||||
|
suffix = [suffix]
|
||||||
|
for s in suffix:
|
||||||
|
ET.SubElement(e, ET.QName(APPXMANIFEST_NS["uap"], "FileType")).text = s
|
||||||
|
|
||||||
|
|
||||||
|
def add_application(
|
||||||
|
ns, xml, appid, executable, aliases, visual_element, subsystem, file_types
|
||||||
|
):
|
||||||
|
node = xml.find("m:Applications", APPXMANIFEST_NS)
|
||||||
|
suffix = "_d.exe" if ns.debug else ".exe"
|
||||||
|
app = ET.SubElement(
|
||||||
|
node,
|
||||||
|
ET.QName(APPXMANIFEST_NS[""], "Application"),
|
||||||
|
{
|
||||||
|
"Id": appid,
|
||||||
|
"Executable": executable + suffix,
|
||||||
|
"EntryPoint": "Windows.FullTrustApplication",
|
||||||
|
ET.QName(APPXMANIFEST_NS["desktop4"], "SupportsMultipleInstances"): "true",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if visual_element:
|
||||||
|
add_visual(app, None, visual_element)
|
||||||
|
for alias in aliases:
|
||||||
|
add_alias(app, None, alias + suffix, subsystem)
|
||||||
|
if file_types:
|
||||||
|
add_file_type(app, None, *file_types)
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
def _get_registry_entries(ns, root="", d=None):
|
||||||
|
r = root if root else PureWindowsPath("")
|
||||||
|
if d is None:
|
||||||
|
d = REGISTRY
|
||||||
|
for key, value in d.items():
|
||||||
|
if key == "_condition":
|
||||||
|
continue
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
cond = value.get("_condition")
|
||||||
|
if cond and not cond(ns):
|
||||||
|
continue
|
||||||
|
fullkey = r
|
||||||
|
for part in PureWindowsPath(key).parts:
|
||||||
|
fullkey /= part
|
||||||
|
if len(fullkey.parts) > 1:
|
||||||
|
yield str(fullkey), None, None
|
||||||
|
yield from _get_registry_entries(ns, fullkey, value)
|
||||||
|
elif len(r.parts) > 1:
|
||||||
|
yield str(r), key, value
|
||||||
|
|
||||||
|
|
||||||
|
def add_registry_entries(ns, xml):
|
||||||
|
e = find_or_add(xml, "m:Extensions")
|
||||||
|
e = find_or_add(e, "rescap4:Extension")
|
||||||
|
e.set("Category", "windows.classicAppCompatKeys")
|
||||||
|
e.set("EntryPoint", "Windows.FullTrustApplication")
|
||||||
|
e = ET.SubElement(e, ET.QName(APPXMANIFEST_NS["rescap4"], "ClassicAppCompatKeys"))
|
||||||
|
for name, valuename, value in _get_registry_entries(ns):
|
||||||
|
k = ET.SubElement(
|
||||||
|
e, ET.QName(APPXMANIFEST_NS["rescap4"], "ClassicAppCompatKey")
|
||||||
|
)
|
||||||
|
k.set("Name", name)
|
||||||
|
if value:
|
||||||
|
k.set("ValueName", valuename)
|
||||||
|
k.set("Value", value)
|
||||||
|
k.set("ValueType", "REG_SZ")
|
||||||
|
|
||||||
|
|
||||||
|
def disable_registry_virtualization(xml):
|
||||||
|
e = find_or_add(xml, "m:Properties")
|
||||||
|
e = find_or_add(e, "desktop6:RegistryWriteVirtualization")
|
||||||
|
e.text = "disabled"
|
||||||
|
e = find_or_add(xml, "m:Capabilities")
|
||||||
|
e = find_or_add(e, "rescap:Capability", ("Name", "unvirtualizedResources"))
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def get_appxmanifest(ns):
|
||||||
|
for k, v in APPXMANIFEST_NS.items():
|
||||||
|
ET.register_namespace(k, v)
|
||||||
|
ET.register_namespace("", APPXMANIFEST_NS["m"])
|
||||||
|
|
||||||
|
xml = ET.parse(io.StringIO(APPXMANIFEST_TEMPLATE))
|
||||||
|
NS = APPXMANIFEST_NS
|
||||||
|
QN = ET.QName
|
||||||
|
|
||||||
|
node = xml.find("m:Identity", NS)
|
||||||
|
for k in node.keys():
|
||||||
|
value = APPX_DATA.get(k)
|
||||||
|
if value:
|
||||||
|
node.set(k, value)
|
||||||
|
|
||||||
|
for node in xml.find("m:Properties", NS):
|
||||||
|
value = APPX_DATA.get(node.tag.rpartition("}")[2])
|
||||||
|
if value:
|
||||||
|
node.text = value
|
||||||
|
|
||||||
|
winver = sys.getwindowsversion()[:3]
|
||||||
|
if winver < (10, 0, 17763):
|
||||||
|
winver = 10, 0, 17763
|
||||||
|
find_or_add(xml, "m:Dependencies/m:TargetDeviceFamily").set(
|
||||||
|
"MaxVersionTested", "{}.{}.{}.0".format(*winver)
|
||||||
|
)
|
||||||
|
|
||||||
|
if winver > (10, 0, 17763):
|
||||||
|
disable_registry_virtualization(xml)
|
||||||
|
|
||||||
|
app = add_application(
|
||||||
|
ns,
|
||||||
|
xml,
|
||||||
|
"Python",
|
||||||
|
"python",
|
||||||
|
["python", "python{}".format(VER_MAJOR), "python{}".format(VER_DOT)],
|
||||||
|
PYTHON_VE_DATA,
|
||||||
|
"console",
|
||||||
|
("python.file", [".py"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
add_application(
|
||||||
|
ns,
|
||||||
|
xml,
|
||||||
|
"PythonW",
|
||||||
|
"pythonw",
|
||||||
|
["pythonw", "pythonw{}".format(VER_MAJOR), "pythonw{}".format(VER_DOT)],
|
||||||
|
PYTHONW_VE_DATA,
|
||||||
|
"windows",
|
||||||
|
("python.windowedfile", [".pyw"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
if ns.include_pip and ns.include_launchers:
|
||||||
|
add_application(
|
||||||
|
ns,
|
||||||
|
xml,
|
||||||
|
"Pip",
|
||||||
|
"pip",
|
||||||
|
["pip", "pip{}".format(VER_MAJOR), "pip{}".format(VER_DOT)],
|
||||||
|
PIP_VE_DATA,
|
||||||
|
"console",
|
||||||
|
("python.wheel", [".whl"], 'install "%1"'),
|
||||||
|
)
|
||||||
|
|
||||||
|
if ns.include_idle and ns.include_launchers:
|
||||||
|
add_application(
|
||||||
|
ns,
|
||||||
|
xml,
|
||||||
|
"Idle",
|
||||||
|
"idle",
|
||||||
|
["idle", "idle{}".format(VER_MAJOR), "idle{}".format(VER_DOT)],
|
||||||
|
IDLE_VE_DATA,
|
||||||
|
"windows",
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (ns.source / SCCD_FILENAME).is_file():
|
||||||
|
add_registry_entries(ns, xml)
|
||||||
|
node = xml.find("m:Capabilities", NS)
|
||||||
|
node = ET.SubElement(node, QN(NS["uap4"], "CustomCapability"))
|
||||||
|
node.set("Name", "Microsoft.classicAppCompat_8wekyb3d8bbwe")
|
||||||
|
|
||||||
|
buffer = io.BytesIO()
|
||||||
|
xml.write(buffer, encoding="utf-8", xml_declaration=True)
|
||||||
|
return buffer.getbuffer()
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def get_resources_xml(ns):
|
||||||
|
return RESOURCES_XML_TEMPLATE.encode("utf-8")
|
|
@ -0,0 +1,44 @@
|
||||||
|
"""
|
||||||
|
File generation for catalog signing non-binary contents.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
__all__ = ["PYTHON_CAT_NAME", "PYTHON_CDF_NAME"]
|
||||||
|
|
||||||
|
|
||||||
|
def public(f):
|
||||||
|
__all__.append(f.__name__)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
PYTHON_CAT_NAME = "python.cat"
|
||||||
|
PYTHON_CDF_NAME = "python.cdf"
|
||||||
|
|
||||||
|
|
||||||
|
CATALOG_TEMPLATE = r"""[CatalogHeader]
|
||||||
|
Name={target.stem}.cat
|
||||||
|
ResultDir={target.parent}
|
||||||
|
PublicVersion=1
|
||||||
|
CatalogVersion=2
|
||||||
|
HashAlgorithms=SHA256
|
||||||
|
PageHashes=false
|
||||||
|
EncodingType=
|
||||||
|
|
||||||
|
[CatalogFiles]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def can_sign(file):
|
||||||
|
return file.is_file() and file.stat().st_size
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def write_catalog(target, files):
|
||||||
|
with target.open("w", encoding="utf-8") as cat:
|
||||||
|
cat.write(CATALOG_TEMPLATE.format(target=target))
|
||||||
|
cat.writelines("<HASH>{}={}\n".format(n, f) for n, f in files if can_sign(f))
|
|
@ -0,0 +1,28 @@
|
||||||
|
"""
|
||||||
|
Constants for generating the layout.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4 = struct.pack(">i", sys.hexversion)
|
||||||
|
VER_FIELD3 = VER_MICRO << 8 | VER_FIELD4
|
||||||
|
VER_NAME = {"alpha": "a", "beta": "b", "rc": "rc"}.get(
|
||||||
|
sys.version_info.releaselevel, ""
|
||||||
|
)
|
||||||
|
VER_SERIAL = sys.version_info.serial if VER_NAME else ""
|
||||||
|
VER_DOT = "{}.{}".format(VER_MAJOR, VER_MINOR)
|
||||||
|
|
||||||
|
PYTHON_DLL_NAME = "python{}{}.dll".format(VER_MAJOR, VER_MINOR)
|
||||||
|
PYTHON_STABLE_DLL_NAME = "python{}.dll".format(VER_MAJOR)
|
||||||
|
PYTHON_ZIP_NAME = "python{}{}.zip".format(VER_MAJOR, VER_MINOR)
|
||||||
|
PYTHON_PTH_NAME = "python{}{}._pth".format(VER_MAJOR, VER_MINOR)
|
||||||
|
|
||||||
|
PYTHON_CHM_NAME = "python{}{}{}{}{}.chm".format(
|
||||||
|
VER_MAJOR, VER_MINOR, VER_MICRO, VER_NAME, VER_SERIAL
|
||||||
|
)
|
||||||
|
|
||||||
|
IS_X64 = sys.maxsize > 2 ** 32
|
|
@ -0,0 +1,25 @@
|
||||||
|
"""distutils.command.bdist_wininst
|
||||||
|
|
||||||
|
Suppress the 'bdist_wininst' command, while still allowing
|
||||||
|
setuptools to import it without breaking."""
|
||||||
|
|
||||||
|
from distutils.core import Command
|
||||||
|
from distutils.errors import DistutilsPlatformError
|
||||||
|
|
||||||
|
|
||||||
|
class bdist_wininst(Command):
|
||||||
|
description = "create an executable installer for MS Windows"
|
||||||
|
|
||||||
|
# Marker for tests that we have the unsupported bdist_wininst
|
||||||
|
_unsupported = True
|
||||||
|
|
||||||
|
def initialize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
raise DistutilsPlatformError(
|
||||||
|
"bdist_wininst is not supported in this Python distribution"
|
||||||
|
)
|
|
@ -0,0 +1,100 @@
|
||||||
|
"""
|
||||||
|
File sets and globbing helper for make_layout.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
class FileStemSet:
|
||||||
|
def __init__(self, *patterns):
|
||||||
|
self._names = set()
|
||||||
|
self._prefixes = []
|
||||||
|
self._suffixes = []
|
||||||
|
for p in map(os.path.normcase, patterns):
|
||||||
|
if p.endswith("*"):
|
||||||
|
self._prefixes.append(p[:-1])
|
||||||
|
elif p.startswith("*"):
|
||||||
|
self._suffixes.append(p[1:])
|
||||||
|
else:
|
||||||
|
self._names.add(p)
|
||||||
|
|
||||||
|
def _make_name(self, f):
|
||||||
|
return os.path.normcase(f.stem)
|
||||||
|
|
||||||
|
def __contains__(self, f):
|
||||||
|
bn = self._make_name(f)
|
||||||
|
return (
|
||||||
|
bn in self._names
|
||||||
|
or any(map(bn.startswith, self._prefixes))
|
||||||
|
or any(map(bn.endswith, self._suffixes))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FileNameSet(FileStemSet):
|
||||||
|
def _make_name(self, f):
|
||||||
|
return os.path.normcase(f.name)
|
||||||
|
|
||||||
|
|
||||||
|
class FileSuffixSet:
|
||||||
|
def __init__(self, *patterns):
|
||||||
|
self._names = set()
|
||||||
|
self._prefixes = []
|
||||||
|
self._suffixes = []
|
||||||
|
for p in map(os.path.normcase, patterns):
|
||||||
|
if p.startswith("*."):
|
||||||
|
self._names.add(p[1:])
|
||||||
|
elif p.startswith("*"):
|
||||||
|
self._suffixes.append(p[1:])
|
||||||
|
elif p.endswith("*"):
|
||||||
|
self._prefixes.append(p[:-1])
|
||||||
|
elif p.startswith("."):
|
||||||
|
self._names.add(p)
|
||||||
|
else:
|
||||||
|
self._names.add("." + p)
|
||||||
|
|
||||||
|
def _make_name(self, f):
|
||||||
|
return os.path.normcase(f.suffix)
|
||||||
|
|
||||||
|
def __contains__(self, f):
|
||||||
|
bn = self._make_name(f)
|
||||||
|
return (
|
||||||
|
bn in self._names
|
||||||
|
or any(map(bn.startswith, self._prefixes))
|
||||||
|
or any(map(bn.endswith, self._suffixes))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _rglob(root, pattern, condition):
|
||||||
|
dirs = [root]
|
||||||
|
recurse = pattern[:3] in {"**/", "**\\"}
|
||||||
|
if recurse:
|
||||||
|
pattern = pattern[3:]
|
||||||
|
|
||||||
|
while dirs:
|
||||||
|
d = dirs.pop(0)
|
||||||
|
if recurse:
|
||||||
|
dirs.extend(
|
||||||
|
filter(
|
||||||
|
condition, (type(root)(f2) for f2 in os.scandir(d) if f2.is_dir())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
yield from (
|
||||||
|
(f.relative_to(root), f)
|
||||||
|
for f in d.glob(pattern)
|
||||||
|
if f.is_file() and condition(f)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _return_true(f):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def rglob(root, patterns, condition=None):
|
||||||
|
if isinstance(patterns, tuple):
|
||||||
|
for p in patterns:
|
||||||
|
yield from _rglob(root, p, condition or _return_true)
|
||||||
|
else:
|
||||||
|
yield from _rglob(root, patterns, condition or _return_true)
|
|
@ -0,0 +1,93 @@
|
||||||
|
"""
|
||||||
|
Logging support for make_layout.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
|
||||||
|
LOG = None
|
||||||
|
HAS_ERROR = False
|
||||||
|
|
||||||
|
|
||||||
|
def public(f):
|
||||||
|
__all__.append(f.__name__)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def configure_logger(ns):
|
||||||
|
global LOG
|
||||||
|
if LOG:
|
||||||
|
return
|
||||||
|
|
||||||
|
LOG = logging.getLogger("make_layout")
|
||||||
|
LOG.level = logging.DEBUG
|
||||||
|
|
||||||
|
if ns.v:
|
||||||
|
s_level = max(logging.ERROR - ns.v * 10, logging.DEBUG)
|
||||||
|
f_level = max(logging.WARNING - ns.v * 10, logging.DEBUG)
|
||||||
|
else:
|
||||||
|
s_level = logging.ERROR
|
||||||
|
f_level = logging.INFO
|
||||||
|
|
||||||
|
handler = logging.StreamHandler(sys.stdout)
|
||||||
|
handler.setFormatter(logging.Formatter("{levelname:8s} {message}", style="{"))
|
||||||
|
handler.setLevel(s_level)
|
||||||
|
LOG.addHandler(handler)
|
||||||
|
|
||||||
|
if ns.log:
|
||||||
|
handler = logging.FileHandler(ns.log, encoding="utf-8", delay=True)
|
||||||
|
handler.setFormatter(
|
||||||
|
logging.Formatter("[{asctime}]{levelname:8s}: {message}", style="{")
|
||||||
|
)
|
||||||
|
handler.setLevel(f_level)
|
||||||
|
LOG.addHandler(handler)
|
||||||
|
|
||||||
|
|
||||||
|
class BraceMessage:
|
||||||
|
def __init__(self, fmt, *args, **kwargs):
|
||||||
|
self.fmt = fmt
|
||||||
|
self.args = args
|
||||||
|
self.kwargs = kwargs
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.fmt.format(*self.args, **self.kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def log_debug(msg, *args, **kwargs):
|
||||||
|
return LOG.debug(BraceMessage(msg, *args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def log_info(msg, *args, **kwargs):
|
||||||
|
return LOG.info(BraceMessage(msg, *args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def log_warning(msg, *args, **kwargs):
|
||||||
|
return LOG.warning(BraceMessage(msg, *args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def log_error(msg, *args, **kwargs):
|
||||||
|
global HAS_ERROR
|
||||||
|
HAS_ERROR = True
|
||||||
|
return LOG.error(BraceMessage(msg, *args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def log_exception(msg, *args, **kwargs):
|
||||||
|
global HAS_ERROR
|
||||||
|
HAS_ERROR = True
|
||||||
|
return LOG.exception(BraceMessage(msg, *args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def error_was_logged():
|
||||||
|
return HAS_ERROR
|
|
@ -0,0 +1,122 @@
|
||||||
|
"""
|
||||||
|
List of optional components.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
|
||||||
|
|
||||||
|
def public(f):
|
||||||
|
__all__.append(f.__name__)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONS = {
|
||||||
|
"stable": {"help": "stable ABI stub"},
|
||||||
|
"pip": {"help": "pip"},
|
||||||
|
"distutils": {"help": "distutils"},
|
||||||
|
"tcltk": {"help": "Tcl, Tk and tkinter"},
|
||||||
|
"idle": {"help": "Idle"},
|
||||||
|
"tests": {"help": "test suite"},
|
||||||
|
"tools": {"help": "tools"},
|
||||||
|
"venv": {"help": "venv"},
|
||||||
|
"dev": {"help": "headers and libs"},
|
||||||
|
"symbols": {"help": "symbols"},
|
||||||
|
"bdist-wininst": {"help": "bdist_wininst support"},
|
||||||
|
"underpth": {"help": "a python._pth file", "not-in-all": True},
|
||||||
|
"launchers": {"help": "specific launchers"},
|
||||||
|
"appxmanifest": {"help": "an appxmanifest"},
|
||||||
|
"props": {"help": "a python.props file"},
|
||||||
|
"chm": {"help": "the CHM documentation"},
|
||||||
|
"html-doc": {"help": "the HTML documentation"},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PRESETS = {
|
||||||
|
"appx": {
|
||||||
|
"help": "APPX package",
|
||||||
|
"options": [
|
||||||
|
"stable",
|
||||||
|
"pip",
|
||||||
|
"distutils",
|
||||||
|
"tcltk",
|
||||||
|
"idle",
|
||||||
|
"venv",
|
||||||
|
"dev",
|
||||||
|
"launchers",
|
||||||
|
"appxmanifest",
|
||||||
|
# XXX: Disabled for now "precompile",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"nuget": {
|
||||||
|
"help": "nuget package",
|
||||||
|
"options": ["stable", "pip", "distutils", "dev", "props"],
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"help": "development kit package",
|
||||||
|
"options": [
|
||||||
|
"stable",
|
||||||
|
"pip",
|
||||||
|
"distutils",
|
||||||
|
"tcltk",
|
||||||
|
"idle",
|
||||||
|
"tests",
|
||||||
|
"tools",
|
||||||
|
"venv",
|
||||||
|
"dev",
|
||||||
|
"symbols",
|
||||||
|
"bdist-wininst",
|
||||||
|
"chm",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"embed": {
|
||||||
|
"help": "embeddable package",
|
||||||
|
"options": ["stable", "zip-lib", "flat-dlls", "underpth", "precompile"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def get_argparse_options():
|
||||||
|
for opt, info in OPTIONS.items():
|
||||||
|
help = "When specified, includes {}".format(info["help"])
|
||||||
|
if info.get("not-in-all"):
|
||||||
|
help = "{}. Not affected by --include-all".format(help)
|
||||||
|
|
||||||
|
yield "--include-{}".format(opt), help
|
||||||
|
|
||||||
|
for opt, info in PRESETS.items():
|
||||||
|
help = "When specified, includes default options for {}".format(info["help"])
|
||||||
|
yield "--preset-{}".format(opt), help
|
||||||
|
|
||||||
|
|
||||||
|
def ns_get(ns, key, default=False):
|
||||||
|
return getattr(ns, key.replace("-", "_"), default)
|
||||||
|
|
||||||
|
|
||||||
|
def ns_set(ns, key, value=True):
|
||||||
|
k1 = key.replace("-", "_")
|
||||||
|
k2 = "include_{}".format(k1)
|
||||||
|
if hasattr(ns, k2):
|
||||||
|
setattr(ns, k2, value)
|
||||||
|
elif hasattr(ns, k1):
|
||||||
|
setattr(ns, k1, value)
|
||||||
|
else:
|
||||||
|
raise AttributeError("no argument named '{}'".format(k1))
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def update_presets(ns):
|
||||||
|
for preset, info in PRESETS.items():
|
||||||
|
if ns_get(ns, "preset-{}".format(preset)):
|
||||||
|
for opt in info["options"]:
|
||||||
|
ns_set(ns, opt)
|
||||||
|
|
||||||
|
if ns.include_all:
|
||||||
|
for opt in OPTIONS:
|
||||||
|
if OPTIONS[opt].get("not-in-all"):
|
||||||
|
continue
|
||||||
|
ns_set(ns, opt)
|
|
@ -0,0 +1,79 @@
|
||||||
|
"""
|
||||||
|
Extraction and file list generation for pip.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "Steve Dower <steve.dower@python.org>"
|
||||||
|
__version__ = "3.8"
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
|
|
||||||
|
|
||||||
|
def public(f):
|
||||||
|
__all__.append(f.__name__)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def get_pip_dir(ns):
|
||||||
|
if ns.copy:
|
||||||
|
if ns.zip_lib:
|
||||||
|
return ns.copy / "packages"
|
||||||
|
return ns.copy / "Lib" / "site-packages"
|
||||||
|
else:
|
||||||
|
return ns.temp / "packages"
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def extract_pip_files(ns):
|
||||||
|
dest = get_pip_dir(ns)
|
||||||
|
dest.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
src = ns.source / "Lib" / "ensurepip" / "_bundled"
|
||||||
|
|
||||||
|
ns.temp.mkdir(parents=True, exist_ok=True)
|
||||||
|
wheels = [shutil.copy(whl, ns.temp) for whl in src.glob("*.whl")]
|
||||||
|
search_path = os.pathsep.join(wheels)
|
||||||
|
if os.environ.get("PYTHONPATH"):
|
||||||
|
search_path += ";" + os.environ["PYTHONPATH"]
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["PYTHONPATH"] = search_path
|
||||||
|
|
||||||
|
output = subprocess.check_output(
|
||||||
|
[
|
||||||
|
sys.executable,
|
||||||
|
"-m",
|
||||||
|
"pip",
|
||||||
|
"--no-color",
|
||||||
|
"install",
|
||||||
|
"pip",
|
||||||
|
"setuptools",
|
||||||
|
"--upgrade",
|
||||||
|
"--target",
|
||||||
|
str(dest),
|
||||||
|
"--no-index",
|
||||||
|
"--no-cache-dir",
|
||||||
|
"-f",
|
||||||
|
str(src),
|
||||||
|
"--only-binary",
|
||||||
|
":all:",
|
||||||
|
],
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.rmtree(dest / "bin")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for file in wheels:
|
||||||
|
try:
|
||||||
|
os.remove(file)
|
||||||
|
except OSError:
|
||||||
|
pass
|
|
@ -0,0 +1,110 @@
|
||||||
|
"""
|
||||||
|
Provides .props file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from .constants import *
|
||||||
|
|
||||||
|
__all__ = ["PYTHON_PROPS_NAME"]
|
||||||
|
|
||||||
|
|
||||||
|
def public(f):
|
||||||
|
__all__.append(f.__name__)
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
PYTHON_PROPS_NAME = "python.props"
|
||||||
|
|
||||||
|
PROPS_DATA = {
|
||||||
|
"PYTHON_TAG": VER_DOT,
|
||||||
|
"PYTHON_VERSION": os.getenv("PYTHON_NUSPEC_VERSION"),
|
||||||
|
"PYTHON_PLATFORM": os.getenv("PYTHON_PROPS_PLATFORM"),
|
||||||
|
"PYTHON_TARGET": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
if not PROPS_DATA["PYTHON_VERSION"]:
|
||||||
|
if VER_NAME:
|
||||||
|
PROPS_DATA["PYTHON_VERSION"] = "{}.{}-{}{}".format(
|
||||||
|
VER_DOT, VER_MICRO, VER_NAME, VER_SERIAL
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
PROPS_DATA["PYTHON_VERSION"] = "{}.{}".format(VER_DOT, VER_MICRO)
|
||||||
|
|
||||||
|
if not PROPS_DATA["PYTHON_PLATFORM"]:
|
||||||
|
PROPS_DATA["PYTHON_PLATFORM"] = "x64" if IS_X64 else "Win32"
|
||||||
|
|
||||||
|
PROPS_DATA["PYTHON_TARGET"] = "_GetPythonRuntimeFilesDependsOn{}{}_{}".format(
|
||||||
|
VER_MAJOR, VER_MINOR, PROPS_DATA["PYTHON_PLATFORM"]
|
||||||
|
)
|
||||||
|
|
||||||
|
PROPS_TEMPLATE = r"""<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Condition="$(Platform) == '{PYTHON_PLATFORM}'">
|
||||||
|
<PythonHome Condition="$(Configuration) == 'Debug'">$([msbuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), "python_d.exe")</PythonHome>
|
||||||
|
<PythonHome Condition="$(PythonHome) == ''">$([msbuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), "python.exe")</PythonHome>
|
||||||
|
<PythonInclude>$(PythonHome)\include</PythonInclude>
|
||||||
|
<PythonLibs>$(PythonHome)\libs</PythonLibs>
|
||||||
|
<PythonTag>{PYTHON_TAG}</PythonTag>
|
||||||
|
<PythonVersion>{PYTHON_VERSION}</PythonVersion>
|
||||||
|
|
||||||
|
<IncludePythonExe Condition="$(IncludePythonExe) == ''">true</IncludePythonExe>
|
||||||
|
<IncludeDistutils Condition="$(IncludeDistutils) == ''">false</IncludeDistutils>
|
||||||
|
<IncludeLib2To3 Condition="$(IncludeLib2To3) == ''">false</IncludeLib2To3>
|
||||||
|
<IncludeVEnv Condition="$(IncludeVEnv) == ''">false</IncludeVEnv>
|
||||||
|
|
||||||
|
<GetPythonRuntimeFilesDependsOn>{PYTHON_TARGET};$(GetPythonRuntimeFilesDependsOn)</GetPythonRuntimeFilesDependsOn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="$(Platform) == '{PYTHON_PLATFORM}'">
|
||||||
|
<ClCompile>
|
||||||
|
<AdditionalIncludeDirectories>$(PythonInclude);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalLibraryDirectories>$(PythonLibs);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
|
||||||
|
<Target Name="GetPythonRuntimeFiles" Returns="@(PythonRuntime)" DependsOnTargets="$(GetPythonRuntimeFilesDependsOn)" />
|
||||||
|
|
||||||
|
<Target Name="{PYTHON_TARGET}" Returns="@(PythonRuntime)">
|
||||||
|
<ItemGroup>
|
||||||
|
<_PythonRuntimeExe Include="$(PythonHome)\python*.dll" />
|
||||||
|
<_PythonRuntimeExe Include="$(PythonHome)\python*.exe" Condition="$(IncludePythonExe) == 'true'" />
|
||||||
|
<_PythonRuntimeExe>
|
||||||
|
<Link>%(Filename)%(Extension)</Link>
|
||||||
|
</_PythonRuntimeExe>
|
||||||
|
<_PythonRuntimeDlls Include="$(PythonHome)\DLLs\*.pyd" />
|
||||||
|
<_PythonRuntimeDlls Include="$(PythonHome)\DLLs\*.dll" />
|
||||||
|
<_PythonRuntimeDlls>
|
||||||
|
<Link>DLLs\%(Filename)%(Extension)</Link>
|
||||||
|
</_PythonRuntimeDlls>
|
||||||
|
<_PythonRuntimeLib Include="$(PythonHome)\Lib\**\*" Exclude="$(PythonHome)\Lib\**\*.pyc;$(PythonHome)\Lib\site-packages\**\*" />
|
||||||
|
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\distutils\**\*" Condition="$(IncludeDistutils) != 'true'" />
|
||||||
|
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\lib2to3\**\*" Condition="$(IncludeLib2To3) != 'true'" />
|
||||||
|
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\ensurepip\**\*" Condition="$(IncludeVEnv) != 'true'" />
|
||||||
|
<_PythonRuntimeLib Remove="$(PythonHome)\Lib\venv\**\*" Condition="$(IncludeVEnv) != 'true'" />
|
||||||
|
<_PythonRuntimeLib>
|
||||||
|
<Link>Lib\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||||
|
</_PythonRuntimeLib>
|
||||||
|
<PythonRuntime Include="@(_PythonRuntimeExe);@(_PythonRuntimeDlls);@(_PythonRuntimeLib)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Message Importance="low" Text="Collected Python runtime from $(PythonHome):%0D%0A@(PythonRuntime->' %(Link)','%0D%0A')" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def get_props_layout(ns):
|
||||||
|
if ns.include_all or ns.include_props:
|
||||||
|
yield "python.props", ns.temp / "python.props"
|
||||||
|
|
||||||
|
|
||||||
|
@public
|
||||||
|
def get_props(ns):
|
||||||
|
# TODO: Filter contents of props file according to included/excluded items
|
||||||
|
props = PROPS_TEMPLATE.format_map(PROPS_DATA)
|
||||||
|
return props.encode("utf-8")
|
|
@ -7,6 +7,11 @@
|
||||||
#include <winuser.h>
|
#include <winuser.h>
|
||||||
1 RT_MANIFEST "python.manifest"
|
1 RT_MANIFEST "python.manifest"
|
||||||
|
|
||||||
|
#if defined(PY_ICON)
|
||||||
|
1 ICON DISCARDABLE "icons\python.ico"
|
||||||
|
#elif defined(PYW_ICON)
|
||||||
|
1 ICON DISCARDABLE "icons\pythonw.ico"
|
||||||
|
#else
|
||||||
1 ICON DISCARDABLE "icons\launcher.ico"
|
1 ICON DISCARDABLE "icons\launcher.ico"
|
||||||
2 ICON DISCARDABLE "icons\py.ico"
|
2 ICON DISCARDABLE "icons\py.ico"
|
||||||
3 ICON DISCARDABLE "icons\pyc.ico"
|
3 ICON DISCARDABLE "icons\pyc.ico"
|
||||||
|
@ -14,6 +19,7 @@
|
||||||
5 ICON DISCARDABLE "icons\python.ico"
|
5 ICON DISCARDABLE "icons\python.ico"
|
||||||
6 ICON DISCARDABLE "icons\pythonw.ico"
|
6 ICON DISCARDABLE "icons\pythonw.ico"
|
||||||
7 ICON DISCARDABLE "icons\setup.ico"
|
7 ICON DISCARDABLE "icons\setup.ico"
|
||||||
|
#endif
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
/* Main program when embedded in a UWP application on Windows */
|
||||||
|
|
||||||
|
#include "Python.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
|
||||||
|
#ifdef PYTHON_UWP_SUPPORTED
|
||||||
|
#include <winrt\Windows.ApplicationModel.h>
|
||||||
|
#include <winrt\Windows.Storage.h>
|
||||||
|
#else
|
||||||
|
#include <string>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PYTHONW
|
||||||
|
#ifdef _DEBUG
|
||||||
|
const wchar_t *PROGNAME = L"pythonw_d.exe";
|
||||||
|
#else
|
||||||
|
const wchar_t *PROGNAME = L"pythonw.exe";
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef _DEBUG
|
||||||
|
const wchar_t *PROGNAME = L"python_d.exe";
|
||||||
|
#else
|
||||||
|
const wchar_t *PROGNAME = L"python.exe";
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_user_base()
|
||||||
|
{
|
||||||
|
#ifdef PYTHON_UWP_SUPPORTED
|
||||||
|
wchar_t envBuffer[2048];
|
||||||
|
try {
|
||||||
|
const auto appData = winrt::Windows::Storage::ApplicationData::Current();
|
||||||
|
if (appData) {
|
||||||
|
const auto localCache = appData.LocalCacheFolder();
|
||||||
|
if (localCache) {
|
||||||
|
auto path = localCache.Path();
|
||||||
|
if (!path.empty() &&
|
||||||
|
!wcscpy_s(envBuffer, path.c_str()) &&
|
||||||
|
!wcscat_s(envBuffer, L"\\local-packages")
|
||||||
|
) {
|
||||||
|
_wputenv_s(L"PYTHONUSERBASE", envBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const wchar_t *
|
||||||
|
get_argv0(const wchar_t *argv0)
|
||||||
|
{
|
||||||
|
#ifdef PYTHON_UWP_SUPPORTED
|
||||||
|
winrt::hstring installPath;
|
||||||
|
#else
|
||||||
|
std::wstring installPath;
|
||||||
|
#endif
|
||||||
|
const wchar_t *launcherPath;
|
||||||
|
wchar_t *buffer;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
launcherPath = _wgetenv(L"__PYVENV_LAUNCHER__");
|
||||||
|
if (launcherPath && launcherPath[0]) {
|
||||||
|
len = wcslen(launcherPath) + 1;
|
||||||
|
buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
|
||||||
|
if (!buffer) {
|
||||||
|
Py_FatalError("out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (wcscpy_s(buffer, len, launcherPath)) {
|
||||||
|
Py_FatalError("failed to copy to buffer");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PYTHON_UWP_SUPPORTED
|
||||||
|
try {
|
||||||
|
const auto package = winrt::Windows::ApplicationModel::Package::Current();
|
||||||
|
if (package) {
|
||||||
|
const auto install = package.InstalledLocation();
|
||||||
|
if (install) {
|
||||||
|
installPath = install.Path();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!installPath.empty()) {
|
||||||
|
len = installPath.size() + wcslen(PROGNAME) + 2;
|
||||||
|
} else {
|
||||||
|
len = wcslen(argv0) + wcslen(PROGNAME) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = (wchar_t *)malloc(sizeof(wchar_t) * len);
|
||||||
|
if (!buffer) {
|
||||||
|
Py_FatalError("out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!installPath.empty()) {
|
||||||
|
if (wcscpy_s(buffer, len, installPath.c_str())) {
|
||||||
|
Py_FatalError("failed to copy to buffer");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (wcscat_s(buffer, len, L"\\")) {
|
||||||
|
Py_FatalError("failed to concatenate backslash");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (wcscpy_s(buffer, len, argv0)) {
|
||||||
|
Py_FatalError("failed to copy argv[0]");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *name = wcsrchr(buffer, L'\\');
|
||||||
|
if (name) {
|
||||||
|
name[1] = L'\0';
|
||||||
|
} else {
|
||||||
|
buffer[0] = L'\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcscat_s(buffer, len, PROGNAME)) {
|
||||||
|
Py_FatalError("failed to concatenate program name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static wchar_t *
|
||||||
|
get_process_name()
|
||||||
|
{
|
||||||
|
DWORD bufferLen = MAX_PATH;
|
||||||
|
DWORD len = bufferLen;
|
||||||
|
wchar_t *r = NULL;
|
||||||
|
|
||||||
|
while (!r) {
|
||||||
|
r = (wchar_t *)malloc(bufferLen * sizeof(wchar_t));
|
||||||
|
if (!r) {
|
||||||
|
Py_FatalError("out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
len = GetModuleFileNameW(NULL, r, bufferLen);
|
||||||
|
if (len == 0) {
|
||||||
|
free((void *)r);
|
||||||
|
return NULL;
|
||||||
|
} else if (len == bufferLen &&
|
||||||
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
free(r);
|
||||||
|
r = NULL;
|
||||||
|
bufferLen *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wmain(int argc, wchar_t **argv)
|
||||||
|
{
|
||||||
|
const wchar_t **new_argv;
|
||||||
|
int new_argc;
|
||||||
|
const wchar_t *exeName;
|
||||||
|
|
||||||
|
new_argc = argc;
|
||||||
|
new_argv = (const wchar_t**)malloc(sizeof(wchar_t *) * (argc + 2));
|
||||||
|
if (new_argv == NULL) {
|
||||||
|
Py_FatalError("out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
exeName = get_process_name();
|
||||||
|
|
||||||
|
new_argv[0] = get_argv0(exeName ? exeName : argv[0]);
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
new_argv[i] = argv[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
set_user_base();
|
||||||
|
|
||||||
|
if (exeName) {
|
||||||
|
const wchar_t *p = wcsrchr(exeName, L'\\');
|
||||||
|
if (p) {
|
||||||
|
const wchar_t *moduleName = NULL;
|
||||||
|
if (*p++ == L'\\') {
|
||||||
|
if (wcsnicmp(p, L"pip", 3) == 0) {
|
||||||
|
moduleName = L"pip";
|
||||||
|
_wputenv_s(L"PIP_USER", L"true");
|
||||||
|
}
|
||||||
|
else if (wcsnicmp(p, L"idle", 4) == 0) {
|
||||||
|
moduleName = L"idlelib";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleName) {
|
||||||
|
new_argc += 2;
|
||||||
|
for (int i = argc; i >= 1; --i) {
|
||||||
|
new_argv[i + 2] = new_argv[i];
|
||||||
|
}
|
||||||
|
new_argv[1] = L"-m";
|
||||||
|
new_argv[2] = moduleName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Override program_full_path from here so that
|
||||||
|
sys.executable is set correctly. */
|
||||||
|
_Py_SetProgramFullPath(new_argv[0]);
|
||||||
|
|
||||||
|
int result = Py_Main(new_argc, (wchar_t **)new_argv);
|
||||||
|
|
||||||
|
free((void *)exeName);
|
||||||
|
free((void *)new_argv);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PYTHONW
|
||||||
|
|
||||||
|
int WINAPI wWinMain(
|
||||||
|
HINSTANCE hInstance, /* handle to current instance */
|
||||||
|
HINSTANCE hPrevInstance, /* handle to previous instance */
|
||||||
|
LPWSTR lpCmdLine, /* pointer to command line */
|
||||||
|
int nCmdShow /* show state of window */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return wmain(__argc, __wargv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,146 @@
|
||||||
|
# Overview
|
||||||
|
|
||||||
|
NOTE: This file requires more content.
|
||||||
|
|
||||||
|
Since Python 3.7.2, releases have been made through the Microsoft Store
|
||||||
|
to allow easy installation on Windows 10.0.17763.0 and later.
|
||||||
|
|
||||||
|
# Building
|
||||||
|
|
||||||
|
To build the store package, the PC/layout script should be used.
|
||||||
|
Execute the directory with the build of Python to package, and pass
|
||||||
|
"-h" for full command-line options.
|
||||||
|
|
||||||
|
To sideload test builds, you will need a local certificate.
|
||||||
|
Instructions are available at
|
||||||
|
https://docs.microsoft.com/windows/uwp/packaging/create-certificate-package-signing.
|
||||||
|
|
||||||
|
After exporting your certificate, you will need the subject name and
|
||||||
|
SHA256 hash. The `certutil -dump <cert file>` command will display this
|
||||||
|
information.
|
||||||
|
|
||||||
|
To build for sideloading, use these commands in PowerShell:
|
||||||
|
|
||||||
|
```
|
||||||
|
$env:APPX_DATA_PUBLISHER=<your certificate subject name>
|
||||||
|
$env:APPX_DATA_SHA256=<your certificate SHA256>
|
||||||
|
$env:SigningCertificateFile=<your certificate file>
|
||||||
|
|
||||||
|
python PC/layout --copy <layout directory> --include-appxmanifest
|
||||||
|
Tools/msi/make_appx.ps1 <layout directory> python.msix -sign
|
||||||
|
|
||||||
|
Add-AppxPackage python.msix
|
||||||
|
```
|
||||||
|
|
||||||
|
(Note that only the last command requires PowerShell, and the others
|
||||||
|
can be used from Command Prompt. You can also double-click to install
|
||||||
|
the final package.)
|
||||||
|
|
||||||
|
To build for publishing to the Store, use these commands:
|
||||||
|
|
||||||
|
```
|
||||||
|
$env:APPX_DATA_PUBLISHER = $null
|
||||||
|
$env:APPX_DATA_SHA256 = $null
|
||||||
|
|
||||||
|
python PC/layout --copy <layout directory> --preset-appxmanifest --precompile
|
||||||
|
Tools/msi/make_appx.ps1 <layout directory> python.msix
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this package cannot be installed locally. It may only be
|
||||||
|
added to a submission for the store.
|
||||||
|
|
||||||
|
|
||||||
|
# Submission Metadata
|
||||||
|
|
||||||
|
This file contains the text that we use to fill out the store listing
|
||||||
|
for the Microsoft Store. It needs to be entered manually when creating
|
||||||
|
a new submission via the dashboard at
|
||||||
|
https://partner.microsoft.com/dashboard.
|
||||||
|
|
||||||
|
We keep it here for convenience and to allow it to be updated via pull
|
||||||
|
requests.
|
||||||
|
|
||||||
|
## Title
|
||||||
|
|
||||||
|
Python 3.8
|
||||||
|
|
||||||
|
## Short Title
|
||||||
|
|
||||||
|
Python
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Python is an easy to learn, powerful programming language. It has efficient high-level data structures and a simple but effective approach to object-oriented programming. Python’s elegant syntax and dynamic typing, together with its interpreted nature, make it an ideal language for scripting and rapid application development in many areas on most platforms.
|
||||||
|
|
||||||
|
The Python interpreter and the extensive standard library are freely available in source or binary form for all major platforms from the Python Web site, https://www.python.org/, and may be freely distributed. The same site also contains distributions of and pointers to many free third party Python modules, programs and tools, and additional documentation.
|
||||||
|
|
||||||
|
The Python interpreter is easily extended with new functions and data types implemented in C or C++ (or other languages callable from C). Python is also suitable as an extension language for customizable applications.
|
||||||
|
|
||||||
|
## ShortDescription
|
||||||
|
|
||||||
|
The Python 3.8 interpreter and runtime.
|
||||||
|
|
||||||
|
## Copyright Trademark Information
|
||||||
|
|
||||||
|
(c) Python Software Foundation
|
||||||
|
|
||||||
|
## Additional License Terms
|
||||||
|
|
||||||
|
Visit https://docs.python.org/3.8/license.html for latest license terms.
|
||||||
|
|
||||||
|
PSF LICENSE AGREEMENT FOR PYTHON 3.8
|
||||||
|
|
||||||
|
1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and
|
||||||
|
the Individual or Organization ("Licensee") accessing and otherwise using Python
|
||||||
|
3.8 software in source or binary form and its associated documentation.
|
||||||
|
|
||||||
|
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||||
|
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||||
|
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||||
|
distribute, and otherwise use Python 3.8 alone or in any derivative
|
||||||
|
version, provided, however, that PSF's License Agreement and PSF's notice of
|
||||||
|
copyright, i.e., "Copyright © 2001-2018 Python Software Foundation; All Rights
|
||||||
|
Reserved" are retained in Python 3.8 alone or in any derivative version
|
||||||
|
prepared by Licensee.
|
||||||
|
|
||||||
|
3. In the event Licensee prepares a derivative work that is based on or
|
||||||
|
incorporates Python 3.8 or any part thereof, and wants to make the
|
||||||
|
derivative work available to others as provided herein, then Licensee hereby
|
||||||
|
agrees to include in any such work a brief summary of the changes made to Python
|
||||||
|
3.8.
|
||||||
|
|
||||||
|
4. PSF is making Python 3.8 available to Licensee on an "AS IS" basis.
|
||||||
|
PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
|
||||||
|
EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
|
||||||
|
WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE
|
||||||
|
USE OF PYTHON 3.8 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
|
||||||
|
|
||||||
|
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.8
|
||||||
|
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
|
||||||
|
MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 3.8, OR ANY DERIVATIVE
|
||||||
|
THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||||
|
|
||||||
|
6. This License Agreement will automatically terminate upon a material breach of
|
||||||
|
its terms and conditions.
|
||||||
|
|
||||||
|
7. Nothing in this License Agreement shall be deemed to create any relationship
|
||||||
|
of agency, partnership, or joint venture between PSF and Licensee. This License
|
||||||
|
Agreement does not grant permission to use PSF trademarks or trade name in a
|
||||||
|
trademark sense to endorse or promote products or services of Licensee, or any
|
||||||
|
third party.
|
||||||
|
|
||||||
|
8. By copying, installing or otherwise using Python 3.8, Licensee agrees
|
||||||
|
to be bound by the terms and conditions of this License Agreement.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Easy to install Python runtime
|
||||||
|
* Supported by core CPython team
|
||||||
|
* Find Python, Pip and Idle on PATH
|
||||||
|
|
||||||
|
## Search Terms
|
||||||
|
|
||||||
|
* Python
|
||||||
|
* Scripting
|
||||||
|
* Interpreter
|
||||||
|
|
|
@ -95,4 +95,10 @@
|
||||||
<Target Name="_CleanTclTkDLL" BeforeTargets="Clean">
|
<Target Name="_CleanTclTkDLL" BeforeTargets="Clean">
|
||||||
<Delete Files="@(_TclTkDLL->'$(OutDir)%(Filename)%(Extension)')" />
|
<Delete Files="@(_TclTkDLL->'$(OutDir)%(Filename)%(Extension)')" />
|
||||||
</Target>
|
</Target>
|
||||||
|
<Target Name="_WriteTCL_LIBRARY" Outputs="$(OutDir)TCL_LIBRARY.env" AfterTargets="Build">
|
||||||
|
<WriteLinesToFile File="$(OutDir)TCL_LIBRARY.env" Lines="$(tcltkdir)\lib\tcl$(TclMajorVersion).$(TclMinorVersion)" Encoding="utf-8" Overwrite="true" />
|
||||||
|
</Target>
|
||||||
|
<Target Name="_CleanTCL_LIBRARY" BeforeTargets="Clean">
|
||||||
|
<Delete Files="$(OutDir)TCL_LIBRARY.env" />
|
||||||
|
</Target>
|
||||||
</Project>
|
</Project>
|
|
@ -29,6 +29,16 @@
|
||||||
@where msbuild > "%TEMP%\msbuild.loc" 2> nul && set /P MSBUILD= < "%TEMP%\msbuild.loc" & del "%TEMP%\msbuild.loc"
|
@where msbuild > "%TEMP%\msbuild.loc" 2> nul && set /P MSBUILD= < "%TEMP%\msbuild.loc" & del "%TEMP%\msbuild.loc"
|
||||||
@if exist "%MSBUILD%" set MSBUILD="%MSBUILD%" & (set _Py_MSBuild_Source=PATH) & goto :found
|
@if exist "%MSBUILD%" set MSBUILD="%MSBUILD%" & (set _Py_MSBuild_Source=PATH) & goto :found
|
||||||
|
|
||||||
|
@rem VS 2017 and later provide vswhere.exe, which can be used
|
||||||
|
@if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto :skip_vswhere
|
||||||
|
@set _Py_MSBuild_Root=
|
||||||
|
@for /F "tokens=*" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -property installationPath -latest') DO @(set _Py_MSBuild_Root=%%i\MSBuild)
|
||||||
|
@if not defined _Py_MSBuild_Root goto :skip_vswhere
|
||||||
|
@for %%j in (Current 15.0) DO @if exist "%_Py_MSBuild_Root%\%%j\Bin\msbuild.exe" (set MSBUILD="%_Py_MSBuild_Root%\%%j\Bin\msbuild.exe")
|
||||||
|
@set _Py_MSBuild_Root=
|
||||||
|
@if defined MSBUILD @if exist %MSBUILD% (set _Py_MSBuild_Source=Visual Studio installation) & goto :found
|
||||||
|
:skip_vswhere
|
||||||
|
|
||||||
@rem VS 2017 sets exactly one install as the "main" install, so we may find MSBuild in there.
|
@rem VS 2017 sets exactly one install as the "main" install, so we may find MSBuild in there.
|
||||||
@reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 15.0 /reg:32 >nul 2>nul
|
@reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 15.0 /reg:32 >nul 2>nul
|
||||||
@if NOT ERRORLEVEL 1 @for /F "tokens=1,2*" %%i in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 15.0 /reg:32') DO @(
|
@if NOT ERRORLEVEL 1 @for /F "tokens=1,2*" %%i in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v 15.0 /reg:32') DO @(
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<IncludeTests Condition="'$(IncludeTest)' == ''">true</IncludeTests>
|
<IncludeTests Condition="'$(IncludeTest)' == ''">true</IncludeTests>
|
||||||
<IncludeSSL Condition="'$(IncludeSSL)' == ''">true</IncludeSSL>
|
<IncludeSSL Condition="'$(IncludeSSL)' == ''">true</IncludeSSL>
|
||||||
<IncludeTkinter Condition="'$(IncludeTkinter)' == ''">true</IncludeTkinter>
|
<IncludeTkinter Condition="'$(IncludeTkinter)' == ''">true</IncludeTkinter>
|
||||||
|
<IncludeUwp Condition="'$(IncludeUwp)' == ''">false</IncludeUwp>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
|
@ -52,6 +53,8 @@
|
||||||
<ExtensionModules Include="_asyncio;_contextvars;_ctypes;_decimal;_elementtree;_msi;_multiprocessing;_overlapped;pyexpat;_queue;select;unicodedata;winsound" />
|
<ExtensionModules Include="_asyncio;_contextvars;_ctypes;_decimal;_elementtree;_msi;_multiprocessing;_overlapped;pyexpat;_queue;select;unicodedata;winsound" />
|
||||||
<!-- Extension modules that require external sources -->
|
<!-- Extension modules that require external sources -->
|
||||||
<ExternalModules Include="_bz2;_lzma;_sqlite3" />
|
<ExternalModules Include="_bz2;_lzma;_sqlite3" />
|
||||||
|
<!-- venv launchers -->
|
||||||
|
<Projects Include="venvlauncher.vcxproj;venvwlauncher.vcxproj" />
|
||||||
<!-- _ssl will build _socket as well, which may cause conflicts in parallel builds -->
|
<!-- _ssl will build _socket as well, which may cause conflicts in parallel builds -->
|
||||||
<ExtensionModules Include="_socket" Condition="!$(IncludeSSL) or !$(IncludeExternals)" />
|
<ExtensionModules Include="_socket" Condition="!$(IncludeSSL) or !$(IncludeExternals)" />
|
||||||
<ExternalModules Include="_ssl;_hashlib" Condition="$(IncludeSSL)" />
|
<ExternalModules Include="_ssl;_hashlib" Condition="$(IncludeSSL)" />
|
||||||
|
@ -70,6 +73,7 @@
|
||||||
<Projects2 Include="_freeze_importlib.vcxproj" />
|
<Projects2 Include="_freeze_importlib.vcxproj" />
|
||||||
<!-- python[w].exe -->
|
<!-- python[w].exe -->
|
||||||
<Projects2 Include="python.vcxproj;pythonw.vcxproj" />
|
<Projects2 Include="python.vcxproj;pythonw.vcxproj" />
|
||||||
|
<Projects2 Include="python_uwp.vcxproj;pythonw_uwp.vcxproj" Condition="$(IncludeUwp)" />
|
||||||
<!-- venv[w]launcher.exe -->
|
<!-- venv[w]launcher.exe -->
|
||||||
<Projects2 Include="venvlauncher.vcxproj;venvwlauncher.vcxproj" />
|
<Projects2 Include="venvlauncher.vcxproj;venvwlauncher.vcxproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -93,6 +93,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_queue", "_queue.vcxproj",
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblzma", "liblzma.vcxproj", "{12728250-16EC-4DC6-94D7-E21DD88947F8}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblzma", "liblzma.vcxproj", "{12728250-16EC-4DC6-94D7-E21DD88947F8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python_uwp", "python_uwp.vcxproj", "{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "venvlauncher", "venvlauncher.vcxproj", "{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "venvwlauncher", "venvwlauncher.vcxproj", "{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pythonw_uwp", "pythonw_uwp.vcxproj", "{AB603547-1E2A-45B3-9E09-B04596006393}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
@ -693,6 +701,70 @@ Global
|
||||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.Build.0 = Release|Win32
|
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|Win32.Build.0 = Release|Win32
|
||||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.ActiveCfg = Release|x64
|
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.ActiveCfg = Release|x64
|
||||||
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.Build.0 = Release|x64
|
{12728250-16EC-4DC6-94D7-E21DD88947F8}.Release|x64.Build.0 = Release|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGInstrument|x64.Build.0 = PGInstrument|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.PGUpdate|x64.Build.0 = PGUpdate|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}.Release|x64.Build.0 = Release|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGInstrument|x64.Build.0 = PGInstrument|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.PGUpdate|x64.Build.0 = PGUpdate|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{494BAC80-A60C-43A9-99E7-ACB691CE2C4D}.Release|x64.Build.0 = Release|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGInstrument|x64.Build.0 = PGInstrument|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.PGUpdate|x64.Build.0 = PGUpdate|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{FDB84CBB-2FB6-47C8-A2D6-091E0833239D}.Release|x64.Build.0 = Release|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|Win32.Build.0 = PGInstrument|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|x64.ActiveCfg = PGInstrument|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGInstrument|x64.Build.0 = PGInstrument|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|Win32.Build.0 = PGUpdate|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|x64.ActiveCfg = PGUpdate|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.PGUpdate|x64.Build.0 = PGUpdate|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{AB603547-1E2A-45B3-9E09-B04596006393}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGInstrument|Win32">
|
||||||
|
<Configuration>PGInstrument</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGInstrument|x64">
|
||||||
|
<Configuration>PGInstrument</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGUpdate|Win32">
|
||||||
|
<Configuration>PGUpdate</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGUpdate|x64">
|
||||||
|
<Configuration>PGUpdate</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{9DE9E23D-C8D4-4817-92A9-920A8B1FE5FF}</ProjectGuid>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="python.props" />
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="pyproject.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalOptions>/EHsc /std:c++17 %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>windowsapp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\PC\pycon.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="..\PC\python_exe.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\PC\python_uwp.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="pythoncore.vcxproj">
|
||||||
|
<Project>{cf7ac3d1-e2df-41d2-bea6-1e2556cdea26}</Project>
|
||||||
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
|
@ -479,4 +479,19 @@
|
||||||
<Target Name="_WarnAboutZlib" BeforeTargets="PrepareForBuild" Condition="!$(IncludeExternals)">
|
<Target Name="_WarnAboutZlib" BeforeTargets="PrepareForBuild" Condition="!$(IncludeExternals)">
|
||||||
<Warning Text="Not including zlib is not a supported configuration." />
|
<Warning Text="Not including zlib is not a supported configuration." />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<VCRedistDir>$(VCInstallDir)\Redist\MSVC\$(VCToolsRedistVersion)\</VCRedistDir>
|
||||||
|
<VCRedistDir Condition="$(Platform) == 'Win32'">$(VCRedistDir)x86\</VCRedistDir>
|
||||||
|
<VCRedistDir Condition="$(Platform) != 'Win32'">$(VCRedistDir)$(Platform)\</VCRedistDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup Condition="$(VCInstallDir) != ''">
|
||||||
|
<VCRuntimeDLL Include="$(VCRedistDir)\**\vcruntime*.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Target Name="_CopyVCRuntime" AfterTargets="Build" Inputs="@(VCRuntimeDLL)" Outputs="$(OutDir)%(Filename)%(Extension)">
|
||||||
|
<Copy SourceFiles="%(VCRuntimeDLL.FullPath)" DestinationFolder="$(OutDir)" />
|
||||||
|
</Target>
|
||||||
|
<Target Name="_CleanVCRuntime" AfterTargets="Clean">
|
||||||
|
<Delete Files="@(VCRuntimeDLL->'$(OutDir)%(Filename)%(Extension)')" />
|
||||||
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGInstrument|Win32">
|
||||||
|
<Configuration>PGInstrument</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGInstrument|x64">
|
||||||
|
<Configuration>PGInstrument</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGUpdate|Win32">
|
||||||
|
<Configuration>PGUpdate</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="PGUpdate|x64">
|
||||||
|
<Configuration>PGUpdate</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{AB603547-1E2A-45B3-9E09-B04596006393}</ProjectGuid>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="python.props" />
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="pyproject.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<ClCompile>
|
||||||
|
<PreprocessorDefinitions>PYTHONW;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalOptions>/EHsc /std:c++17 %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>windowsapp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\PC\pyconw.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="..\PC\pythonw_exe.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\PC\python_uwp.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="pythoncore.vcxproj">
|
||||||
|
<Project>{cf7ac3d1-e2df-41d2-bea6-1e2556cdea26}</Project>
|
||||||
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
|
@ -37,6 +37,7 @@ set BUILDX64=
|
||||||
set TARGET=Rebuild
|
set TARGET=Rebuild
|
||||||
set TESTTARGETDIR=
|
set TESTTARGETDIR=
|
||||||
set PGO=-m test -q --pgo
|
set PGO=-m test -q --pgo
|
||||||
|
set BUILDMSI=1
|
||||||
set BUILDNUGET=1
|
set BUILDNUGET=1
|
||||||
set BUILDZIP=1
|
set BUILDZIP=1
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ if "%1" EQU "--pgo" (set PGO=%~2) && shift && shift && goto CheckOpts
|
||||||
if "%1" EQU "--skip-pgo" (set PGO=) && shift && goto CheckOpts
|
if "%1" EQU "--skip-pgo" (set PGO=) && shift && goto CheckOpts
|
||||||
if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts
|
if "%1" EQU "--skip-nuget" (set BUILDNUGET=) && shift && goto CheckOpts
|
||||||
if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts
|
if "%1" EQU "--skip-zip" (set BUILDZIP=) && shift && goto CheckOpts
|
||||||
|
if "%1" EQU "--skip-msi" (set BUILDMSI=) && shift && goto CheckOpts
|
||||||
|
|
||||||
if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1
|
if "%1" NEQ "" echo Invalid option: "%1" && exit /B 1
|
||||||
|
|
||||||
|
@ -174,10 +176,12 @@ if "%OUTDIR_PLAT%" EQU "win32" (
|
||||||
)
|
)
|
||||||
|
|
||||||
set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI%
|
set BUILDOPTS=/p:Platform=%1 /p:BuildForRelease=true /p:DownloadUrl=%DOWNLOAD_URL% /p:DownloadUrlBase=%DOWNLOAD_URL_BASE% /p:ReleaseUri=%RELEASE_URI%
|
||||||
%MSBUILD% "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true
|
if defined BUILDMSI (
|
||||||
if errorlevel 1 exit /B
|
%MSBUILD% "%D%bundle\releaselocal.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=true
|
||||||
%MSBUILD% "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false
|
if errorlevel 1 exit /B
|
||||||
if errorlevel 1 exit /B
|
%MSBUILD% "%D%bundle\releaseweb.wixproj" /t:Rebuild %BUILDOPTS% %CERTOPTS% /p:RebuildAll=false
|
||||||
|
if errorlevel 1 exit /B
|
||||||
|
)
|
||||||
|
|
||||||
if defined BUILDZIP (
|
if defined BUILDZIP (
|
||||||
%MSBUILD% "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% /p:OutputPath="%BUILD%en-us"
|
%MSBUILD% "%D%make_zip.proj" /t:Build %BUILDOPTS% %CERTOPTS% /p:OutputPath="%BUILD%en-us"
|
||||||
|
@ -214,6 +218,7 @@ echo --skip-build (-B) Do not build Python (just do the installers)
|
||||||
echo --skip-doc (-D) Do not build documentation
|
echo --skip-doc (-D) Do not build documentation
|
||||||
echo --pgo Specify PGO command for x64 installers
|
echo --pgo Specify PGO command for x64 installers
|
||||||
echo --skip-pgo Build x64 installers without using PGO
|
echo --skip-pgo Build x64 installers without using PGO
|
||||||
|
echo --skip-msi Do not build executable/MSI packages
|
||||||
echo --skip-nuget Do not build Nuget packages
|
echo --skip-nuget Do not build Nuget packages
|
||||||
echo --skip-zip Do not build embeddable package
|
echo --skip-zip Do not build embeddable package
|
||||||
echo --download Specify the full download URL for MSIs
|
echo --download Specify the full download URL for MSIs
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
<#
|
||||||
|
.Synopsis
|
||||||
|
Compiles and signs an APPX package
|
||||||
|
.Description
|
||||||
|
Given the file listing, ensures all the contents are signed
|
||||||
|
and builds and signs the final package.
|
||||||
|
.Parameter mapfile
|
||||||
|
The location on disk of the text mapping file.
|
||||||
|
.Parameter msix
|
||||||
|
The path and name to store the APPX/MSIX.
|
||||||
|
.Parameter sign
|
||||||
|
When set, signs the APPX/MSIX. Packages to be published to
|
||||||
|
the store should not be signed.
|
||||||
|
.Parameter description
|
||||||
|
Description to embed in the signature (optional).
|
||||||
|
.Parameter certname
|
||||||
|
The name of the certificate to sign with (optional).
|
||||||
|
.Parameter certsha1
|
||||||
|
The SHA1 hash of the certificate to sign with (optional).
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][string]$layout,
|
||||||
|
[Parameter(Mandatory=$true)][string]$msix,
|
||||||
|
[switch]$sign,
|
||||||
|
[string]$description,
|
||||||
|
[string]$certname,
|
||||||
|
[string]$certsha1,
|
||||||
|
[string]$certfile
|
||||||
|
)
|
||||||
|
|
||||||
|
$tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent;
|
||||||
|
Import-Module $tools\sdktools.psm1 -WarningAction SilentlyContinue -Force
|
||||||
|
|
||||||
|
Set-Alias makeappx (Find-Tool "makeappx.exe") -Scope Script
|
||||||
|
Set-Alias makepri (Find-Tool "makepri.exe") -Scope Script
|
||||||
|
|
||||||
|
$msixdir = Split-Path $msix -Parent
|
||||||
|
if ($msixdir) {
|
||||||
|
$msixdir = (mkdir -Force $msixdir).FullName
|
||||||
|
} else {
|
||||||
|
$msixdir = Get-Location
|
||||||
|
}
|
||||||
|
$msix = Join-Path $msixdir (Split-Path $msix -Leaf)
|
||||||
|
|
||||||
|
pushd $layout
|
||||||
|
try {
|
||||||
|
if (Test-Path resources.pri) {
|
||||||
|
del resources.pri
|
||||||
|
}
|
||||||
|
$name = ([xml](gc AppxManifest.xml)).Package.Identity.Name
|
||||||
|
makepri new /pr . /mn AppxManifest.xml /in $name /cf _resources.xml /of _resources.pri /mf appx /o
|
||||||
|
if (-not $? -or -not (Test-Path _resources.map.txt)) {
|
||||||
|
throw "makepri step failed"
|
||||||
|
}
|
||||||
|
$lines = gc _resources.map.txt
|
||||||
|
$lines | ?{ -not ($_ -match '"_resources[\w\.]+?"') } | Out-File _resources.map.txt -Encoding utf8
|
||||||
|
makeappx pack /f _resources.map.txt /m AppxManifest.xml /o /p $msix
|
||||||
|
if (-not $?) {
|
||||||
|
throw "makeappx step failed"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sign) {
|
||||||
|
Sign-File -certname $certname -certsha1 $certsha1 -certfile $certfile -description $description -files $msix
|
||||||
|
|
||||||
|
if (-not $?) {
|
||||||
|
throw "Package signing failed"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<#
|
||||||
|
.Synopsis
|
||||||
|
Compiles and signs a catalog file.
|
||||||
|
.Description
|
||||||
|
Given the CDF definition file, builds and signs a catalog.
|
||||||
|
.Parameter catalog
|
||||||
|
The path to the catalog definition file to compile and
|
||||||
|
sign. It is assumed that the .cat file will be the same
|
||||||
|
name with a new extension.
|
||||||
|
.Parameter description
|
||||||
|
The description to add to the signature (optional).
|
||||||
|
.Parameter certname
|
||||||
|
The name of the certificate to sign with (optional).
|
||||||
|
.Parameter certsha1
|
||||||
|
The SHA1 hash of the certificate to sign with (optional).
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][string]$catalog,
|
||||||
|
[string]$description,
|
||||||
|
[string]$certname,
|
||||||
|
[string]$certsha1,
|
||||||
|
[string]$certfile
|
||||||
|
)
|
||||||
|
|
||||||
|
$tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent;
|
||||||
|
Import-Module $tools\sdktools.psm1 -WarningAction SilentlyContinue -Force
|
||||||
|
|
||||||
|
Set-Alias MakeCat (Find-Tool "makecat.exe") -Scope Script
|
||||||
|
|
||||||
|
MakeCat $catalog
|
||||||
|
if (-not $?) {
|
||||||
|
throw "Catalog compilation failed"
|
||||||
|
}
|
||||||
|
Sign-File -certname $certname -certsha1 $certsha1 -certfile $certfile -description $description -files @($catalog -replace 'cdf$', 'cat')
|
|
@ -15,11 +15,12 @@
|
||||||
<TargetExt>.zip</TargetExt>
|
<TargetExt>.zip</TargetExt>
|
||||||
<TargetPath>$(OutputPath)\$(TargetName)$(TargetExt)</TargetPath>
|
<TargetPath>$(OutputPath)\$(TargetName)$(TargetExt)</TargetPath>
|
||||||
<CleanCommand>rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)"</CleanCommand>
|
<CleanCommand>rmdir /q/s "$(IntermediateOutputPath)\zip_$(ArchName)"</CleanCommand>
|
||||||
<Arguments>"$(PythonExe)" "$(MSBuildThisFileDirectory)\make_zip.py"</Arguments>
|
<Arguments>"$(PythonExe)" "$(PySourcePath)PC\layout"</Arguments>
|
||||||
<Arguments>$(Arguments) -e -o "$(TargetPath)" -t "$(IntermediateOutputPath)\zip_$(ArchName)" -b "$(BuildPath.TrimEnd(`\`))"</Arguments>
|
<Arguments>$(Arguments) -b "$(BuildPath.TrimEnd(`\`))" -s "$(PySourcePath.TrimEnd(`\`))"</Arguments>
|
||||||
<Environment>set DOC_FILENAME=python$(PythonVersion).chm</Environment>
|
<Arguments>$(Arguments) -t "$(IntermediateOutputPath)\zip_$(ArchName)"</Arguments>
|
||||||
|
<Arguments>$(Arguments) --zip "$(TargetPath)"</Arguments>
|
||||||
|
<Arguments>$(Arguments) --precompile --zip-lib --include-underpth --include-stable --flat-dlls</Arguments>
|
||||||
<Environment>$(Environment)%0D%0Aset PYTHONPATH=$(PySourcePath)Lib</Environment>
|
<Environment>$(Environment)%0D%0Aset PYTHONPATH=$(PySourcePath)Lib</Environment>
|
||||||
<Environment Condition="Exists($(CRTRedist))">$(Environment)%0D%0Aset VCREDIST_PATH=$(CRTRedist)\$(Platform)</Environment>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="_Build">
|
<Target Name="_Build">
|
||||||
|
|
|
@ -1,250 +0,0 @@
|
||||||
import argparse
|
|
||||||
import py_compile
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import shutil
|
|
||||||
import stat
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
from itertools import chain
|
|
||||||
from pathlib import Path
|
|
||||||
from zipfile import ZipFile, ZIP_DEFLATED
|
|
||||||
|
|
||||||
|
|
||||||
TKTCL_RE = re.compile(r'^(_?tk|tcl).+\.(pyd|dll)', re.IGNORECASE)
|
|
||||||
DEBUG_RE = re.compile(r'_d\.(pyd|dll|exe|pdb|lib)$', re.IGNORECASE)
|
|
||||||
PYTHON_DLL_RE = re.compile(r'python\d\d?\.dll$', re.IGNORECASE)
|
|
||||||
|
|
||||||
DEBUG_FILES = {
|
|
||||||
'_ctypes_test',
|
|
||||||
'_testbuffer',
|
|
||||||
'_testcapi',
|
|
||||||
'_testconsole',
|
|
||||||
'_testimportmultiple',
|
|
||||||
'_testmultiphase',
|
|
||||||
'xxlimited',
|
|
||||||
'python3_dstub',
|
|
||||||
}
|
|
||||||
|
|
||||||
EXCLUDE_FROM_LIBRARY = {
|
|
||||||
'__pycache__',
|
|
||||||
'idlelib',
|
|
||||||
'pydoc_data',
|
|
||||||
'site-packages',
|
|
||||||
'tkinter',
|
|
||||||
'turtledemo',
|
|
||||||
}
|
|
||||||
|
|
||||||
EXCLUDE_FROM_EMBEDDABLE_LIBRARY = {
|
|
||||||
'ensurepip',
|
|
||||||
'venv',
|
|
||||||
}
|
|
||||||
|
|
||||||
EXCLUDE_FILE_FROM_LIBRARY = {
|
|
||||||
'bdist_wininst.py',
|
|
||||||
}
|
|
||||||
|
|
||||||
EXCLUDE_FILE_FROM_LIBS = {
|
|
||||||
'liblzma',
|
|
||||||
'python3stub',
|
|
||||||
}
|
|
||||||
|
|
||||||
EXCLUDED_FILES = {
|
|
||||||
'pyshellext',
|
|
||||||
}
|
|
||||||
|
|
||||||
def is_not_debug(p):
|
|
||||||
if DEBUG_RE.search(p.name):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if TKTCL_RE.search(p.name):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return p.stem.lower() not in DEBUG_FILES and p.stem.lower() not in EXCLUDED_FILES
|
|
||||||
|
|
||||||
def is_not_debug_or_python(p):
|
|
||||||
return is_not_debug(p) and not PYTHON_DLL_RE.search(p.name)
|
|
||||||
|
|
||||||
def include_in_lib(p):
|
|
||||||
name = p.name.lower()
|
|
||||||
if p.is_dir():
|
|
||||||
if name in EXCLUDE_FROM_LIBRARY:
|
|
||||||
return False
|
|
||||||
if name == 'test' and p.parts[-2].lower() == 'lib':
|
|
||||||
return False
|
|
||||||
if name in {'test', 'tests'} and p.parts[-3].lower() == 'lib':
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
if name in EXCLUDE_FILE_FROM_LIBRARY:
|
|
||||||
return False
|
|
||||||
|
|
||||||
suffix = p.suffix.lower()
|
|
||||||
return suffix not in {'.pyc', '.pyo', '.exe'}
|
|
||||||
|
|
||||||
def include_in_embeddable_lib(p):
|
|
||||||
if p.is_dir() and p.name.lower() in EXCLUDE_FROM_EMBEDDABLE_LIBRARY:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return include_in_lib(p)
|
|
||||||
|
|
||||||
def include_in_libs(p):
|
|
||||||
if not is_not_debug(p):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return p.stem.lower() not in EXCLUDE_FILE_FROM_LIBS
|
|
||||||
|
|
||||||
def include_in_tools(p):
|
|
||||||
if p.is_dir() and p.name.lower() in {'scripts', 'i18n', 'pynche', 'demo', 'parser'}:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return p.suffix.lower() in {'.py', '.pyw', '.txt'}
|
|
||||||
|
|
||||||
BASE_NAME = 'python{0.major}{0.minor}'.format(sys.version_info)
|
|
||||||
|
|
||||||
FULL_LAYOUT = [
|
|
||||||
('/', '$build', 'python.exe', is_not_debug),
|
|
||||||
('/', '$build', 'pythonw.exe', is_not_debug),
|
|
||||||
('/', '$build', 'python{}.dll'.format(sys.version_info.major), is_not_debug),
|
|
||||||
('/', '$build', '{}.dll'.format(BASE_NAME), is_not_debug),
|
|
||||||
('DLLs/', '$build', '*.pyd', is_not_debug),
|
|
||||||
('DLLs/', '$build', '*.dll', is_not_debug_or_python),
|
|
||||||
('include/', 'include', '*.h', None),
|
|
||||||
('include/', 'PC', 'pyconfig.h', None),
|
|
||||||
('Lib/', 'Lib', '**/*', include_in_lib),
|
|
||||||
('libs/', '$build', '*.lib', include_in_libs),
|
|
||||||
('Tools/', 'Tools', '**/*', include_in_tools),
|
|
||||||
]
|
|
||||||
|
|
||||||
EMBED_LAYOUT = [
|
|
||||||
('/', '$build', 'python*.exe', is_not_debug),
|
|
||||||
('/', '$build', '*.pyd', is_not_debug),
|
|
||||||
('/', '$build', '*.dll', is_not_debug),
|
|
||||||
('{}.zip'.format(BASE_NAME), 'Lib', '**/*', include_in_embeddable_lib),
|
|
||||||
]
|
|
||||||
|
|
||||||
if os.getenv('DOC_FILENAME'):
|
|
||||||
FULL_LAYOUT.append(('Doc/', 'Doc/build/htmlhelp', os.getenv('DOC_FILENAME'), None))
|
|
||||||
if os.getenv('VCREDIST_PATH'):
|
|
||||||
FULL_LAYOUT.append(('/', os.getenv('VCREDIST_PATH'), 'vcruntime*.dll', None))
|
|
||||||
EMBED_LAYOUT.append(('/', os.getenv('VCREDIST_PATH'), 'vcruntime*.dll', None))
|
|
||||||
|
|
||||||
def copy_to_layout(target, rel_sources):
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
if target.suffix.lower() == '.zip':
|
|
||||||
if target.exists():
|
|
||||||
target.unlink()
|
|
||||||
|
|
||||||
with ZipFile(str(target), 'w', ZIP_DEFLATED) as f:
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdir:
|
|
||||||
for s, rel in rel_sources:
|
|
||||||
if rel.suffix.lower() == '.py':
|
|
||||||
pyc = Path(tmpdir) / rel.with_suffix('.pyc').name
|
|
||||||
try:
|
|
||||||
py_compile.compile(str(s), str(pyc), str(rel), doraise=True, optimize=2)
|
|
||||||
except py_compile.PyCompileError:
|
|
||||||
f.write(str(s), str(rel))
|
|
||||||
else:
|
|
||||||
f.write(str(pyc), str(rel.with_suffix('.pyc')))
|
|
||||||
else:
|
|
||||||
f.write(str(s), str(rel))
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
else:
|
|
||||||
for s, rel in rel_sources:
|
|
||||||
dest = target / rel
|
|
||||||
try:
|
|
||||||
dest.parent.mkdir(parents=True)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
if dest.is_file():
|
|
||||||
dest.chmod(stat.S_IWRITE)
|
|
||||||
shutil.copy(str(s), str(dest))
|
|
||||||
if dest.is_file():
|
|
||||||
dest.chmod(stat.S_IWRITE)
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
return count
|
|
||||||
|
|
||||||
def rglob(root, pattern, condition):
|
|
||||||
dirs = [root]
|
|
||||||
recurse = pattern[:3] in {'**/', '**\\'}
|
|
||||||
while dirs:
|
|
||||||
d = dirs.pop(0)
|
|
||||||
for f in d.glob(pattern[3:] if recurse else pattern):
|
|
||||||
if recurse and f.is_dir() and (not condition or condition(f)):
|
|
||||||
dirs.append(f)
|
|
||||||
elif f.is_file() and (not condition or condition(f)):
|
|
||||||
yield f, f.relative_to(root)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('-s', '--source', metavar='dir', help='The directory containing the repository root', type=Path)
|
|
||||||
parser.add_argument('-o', '--out', metavar='file', help='The name of the output archive', type=Path, default=None)
|
|
||||||
parser.add_argument('-t', '--temp', metavar='dir', help='A directory to temporarily extract files into', type=Path, default=None)
|
|
||||||
parser.add_argument('-e', '--embed', help='Create an embedding layout', action='store_true', default=False)
|
|
||||||
parser.add_argument('-b', '--build', help='Specify the build directory', type=Path, default=None)
|
|
||||||
ns = parser.parse_args()
|
|
||||||
|
|
||||||
source = ns.source or (Path(__file__).resolve().parent.parent.parent)
|
|
||||||
out = ns.out
|
|
||||||
build = ns.build or Path(sys.exec_prefix)
|
|
||||||
assert isinstance(source, Path)
|
|
||||||
assert not out or isinstance(out, Path)
|
|
||||||
assert isinstance(build, Path)
|
|
||||||
|
|
||||||
if ns.temp:
|
|
||||||
temp = ns.temp
|
|
||||||
delete_temp = False
|
|
||||||
else:
|
|
||||||
temp = Path(tempfile.mkdtemp())
|
|
||||||
delete_temp = True
|
|
||||||
|
|
||||||
if out:
|
|
||||||
try:
|
|
||||||
out.parent.mkdir(parents=True)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
temp.mkdir(parents=True)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
layout = EMBED_LAYOUT if ns.embed else FULL_LAYOUT
|
|
||||||
|
|
||||||
try:
|
|
||||||
for t, s, p, c in layout:
|
|
||||||
if s == '$build':
|
|
||||||
fs = build
|
|
||||||
else:
|
|
||||||
fs = source / s
|
|
||||||
files = rglob(fs, p, c)
|
|
||||||
extra_files = []
|
|
||||||
if s == 'Lib' and p == '**/*':
|
|
||||||
extra_files.append((
|
|
||||||
source / 'tools' / 'msi' / 'distutils.command.bdist_wininst.py',
|
|
||||||
Path('distutils') / 'command' / 'bdist_wininst.py'
|
|
||||||
))
|
|
||||||
copied = copy_to_layout(temp / t.rstrip('/'), chain(files, extra_files))
|
|
||||||
print('Copied {} files'.format(copied))
|
|
||||||
|
|
||||||
if ns.embed:
|
|
||||||
with open(str(temp / (BASE_NAME + '._pth')), 'w') as f:
|
|
||||||
print(BASE_NAME + '.zip', file=f)
|
|
||||||
print('.', file=f)
|
|
||||||
print('', file=f)
|
|
||||||
print('# Uncomment to run site.main() automatically', file=f)
|
|
||||||
print('#import site', file=f)
|
|
||||||
|
|
||||||
if out:
|
|
||||||
total = copy_to_layout(out, rglob(temp, '**/*', None))
|
|
||||||
print('Wrote {} files to {}'.format(total, out))
|
|
||||||
finally:
|
|
||||||
if delete_temp:
|
|
||||||
shutil.rmtree(temp, True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(int(main() or 0))
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
function Find-Tool {
|
||||||
|
param([string]$toolname)
|
||||||
|
|
||||||
|
$kitroot = (gp 'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots\').KitsRoot10
|
||||||
|
$tool = (gci -r "$kitroot\Bin\*\x64\$toolname" | sort FullName -Desc | select -First 1)
|
||||||
|
if (-not $tool) {
|
||||||
|
throw "$toolname is not available"
|
||||||
|
}
|
||||||
|
Write-Host "Found $toolname at $($tool.FullName)"
|
||||||
|
return $tool.FullName
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Alias SignTool (Find-Tool "signtool.exe") -Scope Script
|
||||||
|
|
||||||
|
function Sign-File {
|
||||||
|
param([string]$certname, [string]$certsha1, [string]$certfile, [string]$description, [string[]]$files)
|
||||||
|
|
||||||
|
if (-not $description) {
|
||||||
|
$description = $env:SigningDescription;
|
||||||
|
if (-not $description) {
|
||||||
|
$description = "Python";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $certname) {
|
||||||
|
$certname = $env:SigningCertificate;
|
||||||
|
}
|
||||||
|
if (-not $certfile) {
|
||||||
|
$certfile = $env:SigningCertificateFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($a in $files) {
|
||||||
|
if ($certsha1) {
|
||||||
|
SignTool sign /sha1 $certsha1 /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
|
||||||
|
} elseif ($certname) {
|
||||||
|
SignTool sign /n $certname /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
|
||||||
|
} elseif ($certfile) {
|
||||||
|
SignTool sign /f $certfile /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
|
||||||
|
} else {
|
||||||
|
SignTool sign /a /fd sha256 /t http://timestamp.verisign.com/scripts/timestamp.dll /d $description $a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<#
|
||||||
|
.Synopsis
|
||||||
|
Recursively signs the contents of a directory.
|
||||||
|
.Description
|
||||||
|
Given the file patterns, code signs the contents.
|
||||||
|
.Parameter root
|
||||||
|
The root directory to sign.
|
||||||
|
.Parameter patterns
|
||||||
|
The file patterns to sign
|
||||||
|
.Parameter description
|
||||||
|
The description to add to the signature (optional).
|
||||||
|
.Parameter certname
|
||||||
|
The name of the certificate to sign with (optional).
|
||||||
|
.Parameter certsha1
|
||||||
|
The SHA1 hash of the certificate to sign with (optional).
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][string]$root,
|
||||||
|
[string[]]$patterns=@("*.exe", "*.dll", "*.pyd"),
|
||||||
|
[string]$description,
|
||||||
|
[string]$certname,
|
||||||
|
[string]$certsha1,
|
||||||
|
[string]$certfile
|
||||||
|
)
|
||||||
|
|
||||||
|
$tools = $script:MyInvocation.MyCommand.Path | Split-Path -parent;
|
||||||
|
Import-Module $tools\sdktools.psm1 -WarningAction SilentlyContinue -Force
|
||||||
|
|
||||||
|
pushd $root
|
||||||
|
try {
|
||||||
|
Sign-File -certname $certname -certsha1 $certsha1 -certfile $certfile -description $description -files (gci -r $patterns)
|
||||||
|
} finally {
|
||||||
|
popd
|
||||||
|
}
|
|
@ -20,25 +20,28 @@
|
||||||
<SignOutput>false</SignOutput>
|
<SignOutput>false</SignOutput>
|
||||||
<TargetName>$(OutputName).$(NuspecVersion)</TargetName>
|
<TargetName>$(OutputName).$(NuspecVersion)</TargetName>
|
||||||
<TargetExt>.nupkg</TargetExt>
|
<TargetExt>.nupkg</TargetExt>
|
||||||
<IntermediateOutputPath>$(IntermediateOutputPath)\nuget_$(ArchName)</IntermediateOutputPath>
|
<IntermediateOutputPath>$(IntermediateOutputPath)\nuget_$(ArchName)\</IntermediateOutputPath>
|
||||||
|
|
||||||
<CleanCommand>rmdir /q/s "$(IntermediateOutputPath)"</CleanCommand>
|
<CleanCommand>rmdir /q/s "$(IntermediateOutputPath.TrimEnd(`\`))"</CleanCommand>
|
||||||
|
|
||||||
<PythonArguments>"$(PythonExe)" "$(MSBuildThisFileDirectory)\..\msi\make_zip.py"</PythonArguments>
|
<PythonArguments>"$(PythonExe)" "$(PySourcePath)PC\layout"</PythonArguments>
|
||||||
<PythonArguments>$(PythonArguments) -t "$(IntermediateOutputPath)" -b "$(BuildPath.TrimEnd(`\`))"</PythonArguments>
|
<PythonArguments>$(PythonArguments) -b "$(BuildPath.TrimEnd(`\`))" -s "$(PySourcePath.TrimEnd(`\`))"</PythonArguments>
|
||||||
|
<PythonArguments>$(PythonArguments) -t "$(IntermediateOutputPath)obj"</PythonArguments>
|
||||||
|
<PythonArguments>$(PythonArguments) --copy "$(IntermediateOutputPath)pkg"</PythonArguments>
|
||||||
|
<PythonArguments>$(PythonArguments) --include-dev --include-tools --include-pip --include-stable --include-launcher --include-props</PythonArguments>
|
||||||
|
|
||||||
<PipArguments>"$(IntermediateOutputPath)\python.exe" -B -c "import sys; sys.path.append(r'$(PySourcePath)\Lib'); import ensurepip; ensurepip._main()"</PipArguments>
|
<PackageArguments Condition="$(Packages) != ''">"$(IntermediateOutputPath)pkg\pip.exe" -B -m pip install -U $(Packages)</PackageArguments>
|
||||||
<PackageArguments Condition="$(Packages) != ''">"$(IntermediateOutputPath)\python.exe" -B -m pip install -U $(Packages)</PackageArguments>
|
|
||||||
|
|
||||||
<NugetPackCommand>"$(Nuget)" pack "$(MSBuildThisFileDirectory)\$(OutputName).nuspec" -BasePath "$(IntermediateOutputPath)"</NugetPackCommand>
|
<NugetPackCommand>"$(Nuget)" pack "$(MSBuildThisFileDirectory)\$(OutputName).nuspec" -BasePath "$(IntermediateOutputPath)pkg"</NugetPackCommand>
|
||||||
<NugetPackSymbolsCommand Condition="Exists('$(MSBuildThisFileDirectory)\$(OutputName).symbols.nuspec')">"$(Nuget)" pack "$(MSBuildThisFileDirectory)\$(OutputName).symbols.nuspec" -BasePath "$(BuildPath.TrimEnd(`\`))"</NugetPackSymbolsCommand>
|
<NugetPackSymbolsCommand Condition="Exists('$(MSBuildThisFileDirectory)\$(OutputName).symbols.nuspec')">"$(Nuget)" pack "$(MSBuildThisFileDirectory)\$(OutputName).symbols.nuspec" -BasePath "$(BuildPath.TrimEnd(`\`))"</NugetPackSymbolsCommand>
|
||||||
<NugetArguments>$(NugetArguments) -OutputDirectory "$(OutputPath.Trim(`\`))"</NugetArguments>
|
<NugetArguments>$(NugetArguments) -OutputDirectory "$(OutputPath.Trim(`\`))"</NugetArguments>
|
||||||
<NugetArguments>$(NugetArguments) -Version "$(NuspecVersion)"</NugetArguments>
|
<NugetArguments>$(NugetArguments) -Version "$(NuspecVersion)"</NugetArguments>
|
||||||
<NugetArguments>$(NugetArguments) -NoPackageAnalysis -NonInteractive</NugetArguments>
|
<NugetArguments>$(NugetArguments) -NoPackageAnalysis -NonInteractive</NugetArguments>
|
||||||
|
|
||||||
<Environment>set DOC_FILENAME=python$(PythonVersion).chm</Environment>
|
|
||||||
<Environment>$(Environment)%0D%0Aset PYTHONPATH=$(PySourcePath)Lib</Environment>
|
<Environment>$(Environment)%0D%0Aset PYTHONPATH=$(PySourcePath)Lib</Environment>
|
||||||
<Environment Condition="Exists($(CRTRedist))">$(Environment)%0D%0Aset VCREDIST_PATH=$(CRTRedist)\$(Platform)</Environment>
|
<Environment>$(Environment)%0D%0Aset PYTHON_NUSPEC_VERSION=$(NuspecVersion)</Environment>
|
||||||
|
<Environment Condition="$(Platform) != 'x86'">$(Environment)%0D%0Aset PYTHON_PROPS_PLATFORM=$(Platform)</Environment>
|
||||||
|
<Environment Condition="$(Platform) == 'x86'">$(Environment)%0D%0Aset PYTHON_PROPS_PLATFORM=Win32</Environment>
|
||||||
<Environment>$(Environment)%0D%0Amkdir "$(OutputPath.Trim(`\`))" >nul 2>nul</Environment>
|
<Environment>$(Environment)%0D%0Amkdir "$(OutputPath.Trim(`\`))" >nul 2>nul</Environment>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -48,22 +51,7 @@
|
||||||
|
|
||||||
<Target Name="_Build">
|
<Target Name="_Build">
|
||||||
<Exec Command="$(CleanCommand)" />
|
<Exec Command="$(CleanCommand)" />
|
||||||
<Exec Command="setlocal%0D%0A$(Environment)%0D%0A$(PythonArguments)" />
|
<Exec Command="setlocal%0D%0A$(Environment)%0D%0A$(PythonArguments)%0D%0A$(PackageArguments)" />
|
||||||
<Exec Command="$(PipArguments)" />
|
|
||||||
<Exec Command="$(PackageArguments)" Condition="$(PackageArguments) != ''" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<_PropsContents>$([System.IO.File]::ReadAllText('python.props'))</_PropsContents>
|
|
||||||
<_PropsContents>$(_PropsContents.Replace('$$PYTHON_TAG$$', '$(MajorVersionNumber).$(MinorVersionNumber)'))</_PropsContents>
|
|
||||||
<_PropsContents>$(_PropsContents.Replace('$$PYTHON_VERSION$$', '$(NuspecVersion)'))</_PropsContents>
|
|
||||||
<_PropsContents Condition="$(Platform) == 'x86'">$(_PropsContents.Replace('$$PYTHON_PLATFORM$$', 'Win32'))</_PropsContents>
|
|
||||||
<_PropsContents Condition="$(Platform) != 'x86'">$(_PropsContents.Replace('$$PYTHON_PLATFORM$$', '$(Platform)'))</_PropsContents>
|
|
||||||
<_PropsContents>$(_PropsContents.Replace('$$PYTHON_TARGET$$', '_GetPythonRuntimeFilesDependsOn$(MajorVersionNumber)$(MinorVersionNumber)_$(Platform)'))</_PropsContents>
|
|
||||||
<_ExistingContents Condition="Exists('$(IntermediateOutputPath)\python.props')">$([System.IO.File]::ReadAllText('$(IntermediateOutputPath)\python.props'))</_ExistingContents>
|
|
||||||
</PropertyGroup>
|
|
||||||
<WriteLinesToFile File="$(IntermediateOutputPath)\python.props"
|
|
||||||
Lines="$(_PropsContents)"
|
|
||||||
Condition="$(_PropsContents) != $(_ExistingContents)" />
|
|
||||||
|
|
||||||
<Exec Command="$(NugetPackCommand) $(NugetArguments)" />
|
<Exec Command="$(NugetPackCommand) $(NugetArguments)" />
|
||||||
<Exec Command="$(NugetPackSymbolsCommand) $(NugetArguments)" Condition="$(NugetPackSymbolsCommand) != ''" />
|
<Exec Command="$(NugetPackSymbolsCommand) $(NugetArguments)" Condition="$(NugetPackSymbolsCommand) != ''" />
|
||||||
|
|
Loading…
Reference in New Issue