Skip to content

Commit

Permalink
Merge pull request #87 from takluyver/applocal-msvcrt
Browse files Browse the repository at this point in the history
Applocal msvcrt
  • Loading branch information
takluyver authored Nov 1, 2016
2 parents 23a5941 + 1bbc917 commit eabbdca
Show file tree
Hide file tree
Showing 91 changed files with 77 additions and 198 deletions.
26 changes: 22 additions & 4 deletions doc/cfgfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,32 @@ Python section
- ``bundled`` includes an embeddable Python build, which will be installed as
part of your application. This is available for Python 3.5 and above.

.. describe:: include_msvcrt (optional)

This option is only relevant with ``format = bundled``. The default is ``true``,
which will include an app-local copy of the Microsoft Visual C++ Runtime,
required for Python to run. The installer will only install this if it doesn't
detect a system installation of the runtime.

Setting this to ``false`` will not include the C++ Runtime. Your application may
not run for all users until they install it manually (`download from Microsoft
<https://www.microsoft.com/en-us/download/details.aspx?id=48145>`__). You may
prefer to do this for security reasons: the separately installed runtime will
get updates through Windows Update, but app-local copies will not.

Users on Windows 10 should already have the runtime installed systemwide, so
this does won't affect them. Users on Windows Vista, 7, 8 or 8.1 *may* already
have it, depending on what else is installed.

.. versionadded:: 1.9

.. _python_bundled:

Bundled Python
~~~~~~~~~~~~~~

.. versionadded:: 1.6
Experimental support for bundling Python into the application.
Support for bundling Python into the application.

Using ``format = bundled``, an embeddable Python build will be downloaded at
build time and packaged along with the application. When the installer runs, it
Expand All @@ -172,9 +191,8 @@ limitations:
- This option is only available for Python 3.5 and above. These versions of
Python have dropped support for Windows XP, so your application will only work
on Windows Vista and newer.
- Installing in Windows Vista to 8.1 (inclusive) may need an internet connection
to download the necessary `Visual C++ runtime
<http://www.microsoft.com/en-us/download/details.aspx?id=48145>`__. This isn't
- Installing in Windows Vista to 8.1 (inclusive) may install an app-local copy
of the Visual C++ runtime (see above). This isn't
needed on Windows 10, which includes the necessary files.
- The embeddable Python builds don't include ``tkinter``, to save space.
Applications with a tkinter GUI can't easily use bundled Python. Workarounds
Expand Down
10 changes: 10 additions & 0 deletions doc/releasenotes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Release notes
=============

Version 1.9
-----------

* The C Runtime needed for bundled Python is now installed 'app-local', rather
than downloading and installing Windows Update packages at install time. This
is considerably simpler, but the app-local runtime will not be updated by
Windows Update. A new ``include_msvcrt`` config option allows the developer to
exclude the app-local runtime - their applications will then depend on the
runtime being installed systemwide.

Version 1.8
-----------

Expand Down
31 changes: 26 additions & 5 deletions nsist/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,16 @@ class InstallerBuilder(object):
:param str py_version: Full version of Python to bundle
:param int py_bitness: Bitness of bundled Python (32 or 64)
:param str py_format: 'installer' or 'bundled'
:param bool inc_msvcrt: True to include the Microsoft C runtime with 'bundled'
Python. Ignored when py_format='installer'.
:param str build_dir: Directory to run the build in
:param str installer_name: Filename of the installer to produce
:param str nsi_template: Path to a template NSI file to use
"""
def __init__(self, appname, version, shortcuts, icon=DEFAULT_ICON,
packages=None, extra_files=None, py_version=DEFAULT_PY_VERSION,
py_bitness=DEFAULT_BITNESS, py_format='installer',
build_dir=DEFAULT_BUILD_DIR,
inc_msvcrt=True, build_dir=DEFAULT_BUILD_DIR,
installer_name=None, nsi_template=None,
exclude=None, pypi_wheel_reqs=None, commands=None):
self.appname = appname
Expand Down Expand Up @@ -123,14 +125,18 @@ def __init__(self, appname, version, shortcuts, icon=DEFAULT_ICON,
else:
if py_format != 'installer':
raise InputError('py_format', py_format, "installer (for Python < 3.5)")
self.inc_msvcrt = inc_msvcrt

# Build details
self.build_dir = build_dir
self.installer_name = installer_name or self.make_installer_name()
self.nsi_template = nsi_template
if self.nsi_template is None:
if self.py_format == 'bundled':
self.nsi_template = 'pyapp_msvcrt.nsi'
if self.inc_msvcrt:
self.nsi_template = 'pyapp_msvcrt.nsi'
else:
self.nsi_template = 'pyapp.nsi'
elif self.py_version_tuple < (3, 3):
self.nsi_template = 'pyapp_w_pylauncher.nsi'
else:
Expand All @@ -141,6 +147,7 @@ def __init__(self, appname, version, shortcuts, icon=DEFAULT_ICON,
# To be filled later
self.install_files = []
self.install_dirs = []
self.msvcrt_files = []

_py_version_pattern = re.compile(r'\d\.\d+\.\d+$')

Expand Down Expand Up @@ -212,6 +219,20 @@ def fetch_python_embeddable(self):

self.install_dirs.append(('Python', '$INSTDIR'))

def prepare_msvcrt(self):
arch = 'x64' if self.py_bitness == 64 else 'x86'
src = pjoin(_PKGDIR, 'msvcrt', arch)
dst = pjoin(self.build_dir, 'msvcrt')
self.msvcrt_files = sorted(os.listdir(src))

try:
shutil.rmtree(dst)
except OSError as e:
if e.errno != errno.ENOENT:
raise

shutil.copytree(src, dst)

def fetch_pylauncher(self):
"""Fetch the MSI for PyLauncher (required for Python2.x).
Expand Down Expand Up @@ -416,9 +437,6 @@ def write_nsi(self):
self.install_files.sort(key=operator.itemgetter(1))
nsis_writer.write(self.nsi_file)

if self.py_format == 'bundled':
shutil.copy2(pjoin(_PKGDIR, 'windowsversion.nsh'), self.build_dir)

def run_nsis(self):
"""Runs makensis using the specified .nsi file
Expand Down Expand Up @@ -448,6 +466,8 @@ def run(self, makensis=True):

if self.py_format == 'bundled':
self.fetch_python_embeddable()
if self.inc_msvcrt:
self.prepare_msvcrt()
else:
self.fetch_python()
if self.py_version < '3.3':
Expand Down Expand Up @@ -517,6 +537,7 @@ def main(argv=None):
py_version = cfg.get('Python', 'version', fallback=DEFAULT_PY_VERSION),
py_bitness = cfg.getint('Python', 'bitness', fallback=DEFAULT_BITNESS),
py_format = cfg.get('Python', 'format', fallback='installer'),
inc_msvcrt = cfg.getboolean('Python', 'include_msvcrt', fallback=True),
build_dir = cfg.get('Build', 'directory', fallback=DEFAULT_BUILD_DIR),
installer_name = cfg.get('Build', 'installer_name', fallback=None),
nsi_template = cfg.get('Build', 'nsi_template', fallback=None),
Expand Down
1 change: 1 addition & 0 deletions nsist/configreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def _check_invalid_keys(self, section_name, section):
('version', False),
('bitness', False),
('format', False),
('include_msvcrt', False),
]),
'Shortcut': SectionValidator([
('entry_point', False),
Expand Down
Binary file removed nsist/inetc.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-debug-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-file-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-file-l1-2-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-file-l2-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-heap-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-synch-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-synch-l1-2-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-core-util-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-crt-conio-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-crt-heap-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-crt-locale-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-crt-math-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-crt-stdio-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-crt-string-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x64/api-ms-win-crt-time-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x64/ucrtbase.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-debug-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-file-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-file-l1-2-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-file-l2-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-heap-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-synch-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-synch-l1-2-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-core-util-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-crt-conio-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-crt-heap-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-crt-locale-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-crt-math-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-crt-stdio-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-crt-string-l1-1-0.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/api-ms-win-crt-time-l1-1-0.dll
Binary file not shown.
Binary file not shown.
Binary file added nsist/msvcrt/x86/ucrtbase.dll
Binary file not shown.
Binary file added nsist/msvcrt/x86/x86.zip
Binary file not shown.
7 changes: 6 additions & 1 deletion nsist/pyapp.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ Section "!${PRODUCT_NAME}" sec_app
SetOutPath "$INSTDIR\pkgs"
File /r "pkgs\*.*"
SetOutPath "$INSTDIR"


[% block install_files %]
; Install files
[% for destination, group in grouped_files %]
SetOutPath "[[destination]]"
Expand All @@ -60,6 +61,7 @@ Section "!${PRODUCT_NAME}" sec_app
SetOutPath "[[ pjoin(destination, dir) ]]"
File /r "[[dir]]\*.*"
[% endfor %]
[% endblock install_files %]

[% block install_shortcuts %]
; Install shortcuts
Expand Down Expand Up @@ -127,6 +129,7 @@ Section "Uninstall"
[% endif %]
[% endblock uninstall_commands %]

[% block uninstall_files %]
; Uninstall files
[% for file, destination in ib.install_files %]
Delete "[[pjoin(destination, file)]]"
Expand All @@ -135,6 +138,8 @@ Section "Uninstall"
[% for dir, destination in ib.install_dirs %]
RMDir /r "[[pjoin(destination, dir)]]"
[% endfor %]
[% endblock uninstall_files %]

[% block uninstall_shortcuts %]
; Uninstall shortcuts
[% if single_shortcut %]
Expand Down
81 changes: 12 additions & 69 deletions nsist/pyapp_msvcrt.nsi
Original file line number Diff line number Diff line change
@@ -1,71 +1,14 @@
[% extends "pyapp.nsi" %]

[% block sections %]
!addplugindir [[ pynsist_pkg_dir ]]
!include windowsversion.nsh
!include x64.nsh

Section "-msvcrt"
${GetWindowsVersion} $R0

StrCpy $0 "--"

${If} ${RunningX64}
${If} $R0 == "8.1"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x64/Windows8.1-KB2999226-x64.msu"
${ElseIf} $R0 == "8"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x64/Windows8-RT-KB2999226-x64.msu"
${ElseIf} $R0 == "7"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x64/Windows6.1-KB2999226-x64.msu"
${ElseIf} $R0 == "Vista"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x64/Windows6.0-KB2999226-x64.msu"
${EndIf}
${Else}
${If} $R0 == "8.1"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x86/Windows8.1-KB2999226-x86.msu"
${ElseIf} $R0 == "8"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x86/Windows8-RT-KB2999226-x86.msu"
${ElseIf} $R0 == "7"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x86/Windows6.1-KB2999226-x86.msu"
${ElseIf} $R0 == "Vista"
StrCpy $0 "https://cdn.rawgit.com/takluyver/pynsist/msvcrt-tag1/x86/Windows6.0-KB2999226-x86.msu"
${EndIf}
${EndIf}

IfFileExists "$SYSDIR\ucrtbase.dll" skip_msvcrt
StrCmp $0 "--" skip_msvcrt

DetailPrint "Need to install MSVCRT 2015. This may take a few minutes."
DetailPrint "Downloading $0"
inetc::get /RESUME "" "$0" "$INSTDIR\msvcrt.msu"
Pop $2
DetailPrint "Download finished ($2)"
${If} $2 == "OK"
DetailPrint "Running wusa to install update package"
ExecWait 'wusa "$INSTDIR\msvcrt.msu" /quiet /norestart' $1
Delete "$INSTDIR\msvcrt.msu"
${Else}
MessageBox MB_OK "Failed to download important update! \
${PRODUCT_NAME} will not run until you install the Visual C++ \
redistributable for Visual Studio 2015.\
$\n$\nhttp://www.microsoft.com/en-us/download/details.aspx?id=48145"
${EndIf}

# This WUSA exit code means a reboot is needed.
${If} $1 = 0x00240005
SetRebootFlag true
${Else}
IntOp $0 $1 & 0x80000000
${If} $0 <> 0
MessageBox MB_OK "Failed to install important update! \
${PRODUCT_NAME} will not run until you install the Visual C++ \
redistributable for Visual Studio 2015.\
$\n$\nhttp://www.microsoft.com/en-us/download/details.aspx?id=48145"
${EndIf}
${EndIf}

skip_msvcrt:
SectionEnd

[[ super() ]]
[% endblock sections %]
[% block install_files %]
[[ super() ]]

; Install MSVCRT if it's not already on the system
IfFileExists "$SYSDIR\ucrtbase.dll" skip_msvcrt
SetOutPath $INSTDIR\Python
[% for file in ib.msvcrt_files %]
File msvcrt\[[file]]
[% endfor %]
skip_msvcrt:

[% endblock %]
Loading

0 comments on commit eabbdca

Please sign in to comment.