What *PyInstaller* Does and How It Does It
******************************************

This section covers the basic ideas of *PyInstaller*. These ideas
apply to all platforms. Options and special cases are covered below,
under Using PyInstaller.

*PyInstaller* reads a Python script written by you. It analyzes your
code to discover every other module and library your script needs in
order to execute. Then it collects copies of all those files --
including the active Python interpreter! -- and puts them with your
script in a single folder, or optionally in a single executable file.

For the great majority of programs, this can be done with one short
command,

   pyinstaller myscript.py

or with a few added options, for example a windowed application as a
single-file executable,

   pyinstaller --onefile --windowed myscript.py

You distribute the bundle as a folder or file to other people, and
they can execute your program. To your users, the app is self-
contained. They do not need to install any particular version of
Python or any modules. They do not need to have Python installed at
all.

Note:

  The output of  *PyInstaller* is specific to the active operating
  system and the active version of Python. This means that to prepare
  a distribution for:

     * a different OS

     * a different version of Python

     * a 32-bit or 64-bit OS

  you run *PyInstaller* on that OS, under that version of Python. The
  Python interpreter that executes *PyInstaller* is part of the
  bundle, and it is specific to the OS and the word size.


Analysis: Finding the Files Your Program Needs
==============================================

What other modules and libraries does your script need in order to
run? (These are sometimes called its "dependencies".)

To find out, *PyInstaller* finds all the "import" statements in your
script. It finds the imported modules and looks in them for "import"
statements, and so on recursively, until it has a complete list of
modules your script may use.

*PyInstaller* understands the "egg" distribution format often used for
Python packages. If your script imports a module from an "egg",
*PyInstaller* adds the egg and its dependencies to the set of needed
files.

*PyInstaller* also knows about many major Python packages, including
the GUI packages Qt (imported via PyQt or PySide), WxPython, TkInter,
Django, and other major packages. For a complete list, see Supported
Packages.

Some Python scripts import modules in ways that *PyInstaller* cannot
detect: for example, by using the "__import__()" function with
variable data, using "imp.find_module()", or manipulating the
"sys.path" value at run time. If your script requires files that
*PyInstaller* does not know about, you must help it:

* You can give additional files on the "pyinstaller" command line.

* You can give additional import paths on the command line.

* You can edit the "*myscript*.spec" file that *PyInstaller* writes
  the first time you run it for your script. In the spec file you can
  tell *PyInstaller* about code modules that are unique to your
  script.

* You can write "hook" files that inform *PyInstaller* of hidden
  imports. If you create a "hook" for a package that other users might
  also use, you can contribute your hook file to *PyInstaller*.

If your program depends on access to certain data files, you can tell
*PyInstaller* to include them in the bundle as well. You do this by
modifying the spec file, an advanced topic that is covered under Using
Spec Files.

In order to locate included files at run time, your program needs to
be able to learn its path at run time in a way that works regardless
of whether or not it is running from a bundle. This is covered under
Run-time Information.

*PyInstaller* does *not* include libraries that should exist in any
installation of this OS. For example in GNU/Linux, it does not bundle
any file from "/lib" or "/usr/lib", assuming these will be found in
every system.


Bundling to One Folder
======================

When you apply *PyInstaller* to "myscript.py" the default result is a
single folder named "myscript". This folder contains all your script's
dependencies, and an executable file also named "myscript"
("myscript.exe" in Windows).

You compress the folder to "myscript.zip" and transmit it to your
users. They install the program simply by unzipping it. A user runs
your app by opening the folder and launching the "myscript" executable
inside it.

It is easy to debug problems that occur when building the app when you
use one-folder mode. You can see exactly what files *PyInstaller*
collected into the folder.

Another advantage of a one-folder bundle is that when you change your
code, as long as it imports *exactly the same set of dependencies*,
you could send out only the updated "myscript" executable. That is
typically much smaller than the entire folder. (If you change the
script so that it imports more or different dependencies, or if the
dependencies are upgraded, you must redistribute the whole bundle.)

A small disadvantage of the one-folder format is that the one folder
contains a large number of files. Your user must find the "myscript"
executable in a long list of names or among a big array of icons. Also
your user can create a problem by accidentally dragging files out of
the folder.


How the One-Folder Program Works
================================

A bundled program always starts execution in the *PyInstaller*
bootloader. This is the heart of the "myscript" executable in the
folder.

The *PyInstaller* bootloader is a binary executable program for the
active platform (Windows, GNU/Linux, Mac OS X, etc.). When the user
launches your program, it is the bootloader that runs. The bootloader
creates a temporary Python environment such that the Python
interpreter will find all imported modules and libraries in the
"myscript" folder.

The bootloader starts a copy of the Python interpreter to execute your
script. Everything follows normally from there, provided that all the
necessary support files were included.

(This is an overview. For more detail, see The Bootstrap Process in
Detail below.)


Bundling to One File
====================

*PyInstaller* can bundle your script and all its dependencies into a
single executable named "myscript" ("myscript.exe" in Windows).

The advantage is that your users get something they understand, a
single executable to launch. A disadvantage is that any related files
such as a README must be distributed separately. Also, the single
executable is a little slower to start up than the one-folder bundle.

Before you attempt to bundle to one file, make sure your app works
correctly when bundled to one folder. It is is *much* easier to
diagnose problems in one-folder mode.


How the One-File Program Works
==============================

The bootloader is the heart of the one-file bundle also. When started
it creates a temporary folder in the appropriate temp-folder location
for this OS. The folder is named "_MEI*xxxxxx*", where *xxxxxx* is a
random number.

The one executable file contains an embedded archive of all the Python
modules used by your script, as well as compressed copies of any non-
Python support files (e.g. ".so" files). The bootloader uncompresses
the support files and writes copies into the the temporary folder.
This can take a little time. That is why a one-file app is a little
slower to start than a one-folder app.

Note:

  *PyInstaller* currently does not preserve file attributes. see
  #3926.

After creating the temporary folder, the bootloader proceeds exactly
as for the one-folder bundle, in the context of the temporary folder.
When the bundled code terminates, the bootloader deletes the temporary
folder.

(In GNU/Linux and related systems, it is possible to mount the "/tmp"
folder with a "no-execution" option. That option is not compatible
with a *PyInstaller* one-file bundle. It needs to execute code out of
"/tmp". If you know the target environment, "--runtime-tmpdir" might
be a workaround.)

Because the program makes a temporary folder with a unique name, you
can run multiple copies of the app; they won't interfere with each
other. However, running multiple copies is expensive in disk space
because nothing is shared.

The "_MEI*xxxxxx*" folder is not removed if the program crashes or is
killed (kill -9 on Unix, killed by the Task Manager on Windows, "Force
Quit" on Mac OS). Thus if your app crashes frequently, your users will
lose disk space to multiple "_MEI*xxxxxx*" temporary folders.

It is possible to control the location of the "_MEI*xxxxxx*" folder by
using the "--runtime-tmpdir" command line option. The specified path
is stored in the executable, and the bootloader will create the
"_MEI*xxxxxx*" folder inside of the specified folder. Please see
Defining the Extraction Location for details.

Note:

  Do *not* give administrator privileges to a one-file executable
  (setuid root in Unix/Linux, or the "Run this program as an
  administrator" property in Windows 7). There is an unlikely but not
  impossible way in which a malicious attacker could corrupt one of
  the shared libraries in the temp folder while the bootloader is
  preparing it. Distribute a privileged program in one-folder mode
  instead.

Note:

  Applications that use *os.setuid()* may encounter permissions
  errors. The temporary folder where the bundled app runs may not
  being readable after *setuid* is called. If your script needs to
  call *setuid*, it may be better to use one-folder mode so as to have
  more control over the permissions on its files.


Using a Console Window
======================

By default the bootloader creates a command-line console (a terminal
window in GNU/Linux and Mac OS, a command window in Windows). It gives
this window to the Python interpreter for its standard input and
output. Your script's use of "print" and "input()" are directed here.
Error messages from Python and default logging output also appear in
the console window.

An option for Windows and Mac OS is to tell *PyInstaller* to not
provide a console window. The bootloader starts Python with no target
for standard output or input. Do this when your script has a graphical
interface for user input and can properly report its own diagnostics.

As noted in the CPython tutorial Appendix, for Windows a file
extention of *.pyw* suppresses the console window that normally
appears. Likewise, a console window will not be provided when using a
"myscript.pyw" script with *PyInstaller*.


Hiding the Source Code
======================

The bundled app does not include any source code. However,
*PyInstaller* bundles compiled Python scripts (".pyc" files). These
could in principle be decompiled to reveal the logic of your code.

If you want to hide your source code more thoroughly, one possible
option is to compile some of your modules with Cython. Using Cython
you can convert Python modules into C and compile the C to machine
language. *PyInstaller* can follow import statements that refer to
Cython C object modules and bundle them.

Additionally, Python bytecode can be obfuscated with AES256 by
specifying an encryption key on PyInstaller's command line. Please
note that it is still very easy to extract the key and get back the
original bytecode, but it should prevent most forms of "casual"
tampering. See Encrypting Python Bytecode for details.
