Sunday, April 17, 2011

Python Binary Woes (PyInstaller to the rescue)

I obviously like Python very much. It is nice and speedy for most of the things I use it for, the code is very easy to maintain, and its data structures are beautiful.  However, there is one thing that I truly don't like about it: distribution. There are eggs, and tarballs, apps, installers, and executables. How horrifying!

Writing creation scripts for all of these is a nightmare, and for small projects (aren't they all when they are written in Python), it is too much of a hassle. At least Windows and Mac have standalone executable builders.

But what about the lonely Linux/UNIX? You could either require the user to download a bunch of python eggs that they don't have, install them, then run your script, only to find they have the wrong Python version; or you could bundle them all up with a handy little tool called: PyInstaller.


You're probably thinking, "Whoa, who does this guy think he is, breaking the UNIX file hierarchy like that?". Here is the deal, while it may be fine and dandy passing out source code and requiring users to download dependencies and such there are a few reasons you might not want to do it:
  1. Your source code is proprietary, I know, I know, proprietary stuff is evil, but it could happen!
  2. You want to distribute your code off-line and want to ensure all dependencies are satisfied.
  3. Your users cry when they see a command line.
  4. You like things in a clean, tidy, single executable.
 Now on to the HOWTO:
  1. Download PyInstaller
  2. Extract it.
  3. cd to the extracted folder and run "python Configure.py"
  4. Run "python Makespec.py -F /path/to/your/script.py"
  5. Run "python Build.py /path/to/your/spec.spec" You should have received the location of the .spec file in the output of Makespec.py.
  6. Go have lunch, the executable is in a subdirectory of the PyInstaller directory.
There are a few problems though, some files don't like being built due to the way imports are done, just play around with those using the full paths for imports rather than the Python shortcuts and it should all work.

No comments:

Post a Comment