Creating standalone applications with Python

With BuildApplet you can build a standalone Python application that works like any other Mac application: you can double-click it, run it while the Python interpreter is running other scripts, drop files on it, etc. It is, however, still dependent on the whole Python installation on your machine: the PythonCore engine, the plugin modules and the various Lib folders.

In some cases you may want to create a true application, for instance because you want to send it off to people who may not have Python installed on their machine, or because you the application is important and you do not want changes in your Python installation like new versions to influence it.

The easy way

The easiest way to create an application from a Python script is simply by dropping it on the BuildApplication applet in the main Python folder. BuildApplication has a similar interface as BuildApplet: you drop a script on it and it will process it, along with an optional .rsrc file.

What BuildApplication does, however, is very different. It parses your script, recursively looking for all modules you use, bundles the compiled code for all these modules in PYC resources, adds the executable machine code for the PythonCore engine, any dynamically loaded modules you use and a main program, combines all this into a single file and adds a few preference resources (which you can inspect with EditPythonPrefs, incidentally) to isolate the new program from the existing Python installation.

Usually you do not need to worry about all this, but occasionally you may have to exercise some control over the process, for instance because your program imports modules that don't exist (which can happen if your script is multi-platform and those modules will never be used on the Mac). See the section on directives below for details. If you get strange error messages about missing modules it may also be worthwhile to run macfreeze in report mode on your program, see below.

Doing it the hard way

With the macfreeze script, for which BuildApplication is a simple wrapper, you can go a step further and create CodeWarrior projects and sourcefiles which can then be used to build your final application. While BuildApplication is good enough for 90% of the use cases there are situations where you need macfreeze itself, mainly if you want to embed your frozen Python script into an existing C application, or when you need the extra bit of speed: the resulting application will start up a bit quicker than one generated with BuildApplication.

When you start Mac:Tools:macfreeze:macfreeze.py you are asked for the script file, and you can select which type of freeze to do. The first time you should always choose report only, which will produce a listing of modules and where they are included from in the console window. Macfreeze actually parses all modules, so it may crash in the process. If it does try again with a higher debug value, this should show you where it crashes.

Directives

For more elaborate programs you will often see that freeze includes modules you don't need (because they are for a different platform, for instance) or that it cannot find all your modules (because you modify sys.path early in your initialization). It is possible to include directives to tell macfreeze to add items to the search path and include or exclude certain modules. All your directives should be in the main script file.

Directives have the following form:

# macfreeze: command argument
The trigger macfreeze: must be spelled exactly like that, but the whitespace can be any combination of spaces and tabs. Macfreeze understands the following directives:
path
Prepend a folder to sys.path. The argument is a pathname, which should probably be relative (starting with a colon) and is interpreted relative to the folder where the script lives.
include
Include a module. The module can either be given by filename or by module name, in which case it is looked up through the normal method.
exclude
Exclude a module. The module must be given by modulename. Even when freeze deems the module necessary it will not be included in the application.
optional
Include a module if it can be found, but don't complain if it can't.
There is actually a fourth way that macfreeze can operate: it can be used to generate only the resource file containing the compiled PYC resources. This may be useful if you have embedded Python in your own application. The resource file generated is the same as for the CodeWarrior generation process.

Freezing with CodeWarrior

To freeze with CodeWarrior you need CodeWarrior, obviously, and a full source distribution of Python. You select the Codewarrior source and project option. You specify an output folder, which is by default the name of your script with .py removed and build. prepended. If the output folder does not exist yet it is created, and a template project file and bundle resource file are deposited there. Next, a source file macfreezeconfig.c is created which includes all builtin modules your script uses, and a resource file frozenmodules.rsrc which contains the PYC resources for all your Python modules.

The project expects to live in a folder one level below the Python root folder, so the next thing you should do is move the build folder there. It is a good idea to leave an alias with the same name in the original location: when you run freeze again it will regenerate the frozenmodules.rsrc file but not the project and bundle files. This is probably what you want: if you modify your python sources you have to re-freeze, but you may have changed the project and bundle files, so you don't want to regenerate them.

An alternative is to leave the build folder where it is, but then you have to adapt the search path in the project.

The project is set up to include all the standard builtin modules, but the CW linker is smart enough to exclude any object code that isn't referenced. Still, it may be worthwhile to remove any sources for modules that you are sure are not used to cut back on compilation time. You may also want to examine the various resource files (for Tcl/Tk, for instance): the loader has no way to know that these aren't used.

You may also need to add sourcefiles if your script uses non-standard builtin modules, like anything from the Extensions folder.

The frozenbundle.rsrc resource file contains the bundle information. It is almost identical to the bundle file used for applets, with the exception that it sets the sys.path initialization to $(APPLICATION) only. This means that all modules will only be looked for in PYC resources in your application.