Temple of The Roguelike Forums

Development => Programming => Topic started by: KM on January 17, 2017, 04:11:41 AM

Title: Packaging a python script as an executable
Post by: KM on January 17, 2017, 04:11:41 AM
Hi; I'm trying to package my python script as an executable, but am finding it very difficult.  I'm following the directions at py2exe.org, and am using bearlibterminal and libtcod, and am getting dependencies that I don't understand how to fix.  When I try to click the .exe file I created, it just crashes with no errors, but it runs fine when I launch it out of powershell.

Here's what powershell tells me when I'm trying to run the .exe from there:

Code: [Select]
PS C:\Python27\Grit\dist> .\gritandsteel.exe
Traceback (most recent call last):
  File "gritandsteel.py", line 6, in <module>
  File "zipextimporter.pyc", line 82, in load_module
  File "PyBearLibTerminal.pyc", line 58, in <module>
  File "PyBearLibTerminal.pyc", line 56, in _load_library
RuntimeError: BearLibTerminal library cannot be loaded (looked for BearLibTerminal.dll in C:\Python27\Grit\dist\gritandsteel.exe)
PS C:\Python27\Grit\dist>

I don't know why it's looking for the .dll IN the .exe, or how I would fix it.  BearLibTerminal.dll is in the same file directory as my .exe.

I created the .exe using the tutorial code here:
Code: [Select]
from distutils.core import setup
import py2exe
import os
import sys
 
sys.argv.append('py2exe')
 
# The filename of the script you use to start your program.
target_file = 'gritandsteel.py'
 
# The root directory containing your assets, libraries, etc.
assets_dir = '.\\'
 
# Filetypes not to be included in the above.
excluded_file_types = ['py','pyc','project','pydevproject']
 
def get_data_files(base_dir, target_dir, list=[]):
    """
    " * get_data_files
    " *    base_dir:    The full path to the current working directory.
    " *    target_dir:  The directory of assets to include.
    " *    list:        Current list of assets. Used for recursion.
    " *
    " *    returns:     A list of relative and full path pairs. This is
    " *                 specified by distutils.
    """
    for file in os.listdir(base_dir + target_dir):
 
        full_path = base_dir + target_dir + file
        if os.path.isdir(full_path):
            get_data_files(base_dir, target_dir + file + '\\', list)
        elif os.path.isfile(full_path):
            if (len(file.split('.')) == 2 and file.split('.')[1] not in excluded_file_types):
                list.append((target_dir, [full_path]))
 
    return list
 
# The directory of assets to include.
my_files = get_data_files(sys.path[0] + '\\', assets_dir)
 
# Build a dictionary of the options we want.
opts = { 'py2exe': {
                    'ascii':'True',
                    'excludes':['_ssl','_hashlib'],
                    'includes' : ['anydbm', 'dbhash'],
                    'bundle_files':'1',
                    'compressed':'True'}}
 
# Run the setup utility.
setup(console=[target_file],
      data_files=my_files,
      zipfile=None,
      options=opts)

Any help is appreciated as to why this isn't launching.  Thank you.
Title: Re: Packaging a python script as an executable
Post by: AgingMinotaur on January 17, 2017, 08:38:24 AM
Hello. I used to pack Windows executables with Py2exe, but I switched to Pyinstaller (http://pyinstaller.org) a while back. Don't know if this may be a solution for you, but I thought I'd mention it. Pyinstaller is pretty nice overall, but the main draw for me is that I can use it in Linux to get Window exes. I wrote a short blot post (http://agingminotaur.blogspot.de/2015/12/how-to-make-windows-exe-in-linux-with.html) about that. The short, not Linux-specific version is to install Pywin32, Setuptools and MS Visual C++. Then you get an exe by typing "pyinstaller --onefile main.py". Hope this helps.

As always,
Minotauros
Title: Re: Packaging a python script as an executable
Post by: javelinrl on January 17, 2017, 06:55:07 PM
If all you want is for the user to be able to click a file icon and run your game automatically, the usual way to do that with Python is to provide a .bat file for Windows and a .sh file for Linux, both of them being mostly just the "python3 myscript.py" command (and also a #!/usr/bin/python3 opening line for the .sh). If you go that route make sure your .sh file is packaged as +x (executable).

I think this is how most RLs written in Python achieve that and it's certainly a lot less complex than creating an actual binary file. If you want something more professional you can try an installer package as been said in the last post and maybe provide a shortcut that launches Python directly from a command (instead of creating an EXE).

Finally, I think most modern operating systems can handle the user double clicking a Python file to launch it directly. Haven't used Windows in a long while but Linux certainly does that if the file is executable (+x) and has the appropriate shebang line (#!).
Title: Re: Packaging a python script as an executable
Post by: AgingMinotaur on January 17, 2017, 08:17:23 PM
A binary saves the player the hassle of installing dependencies, though. And I don't think Python is a standard component in Windows like it is in Linux (someone correct me if I'm wrong). So for many casual users, it's the difference between "click on the file" and "download and install Python and Pygame, then click on the file". For Linux users, of course, it's mostly hunky dory just to ship a Python script :) but I maintain a deb-file of my own project just for kicks.

As always,
Minotauros
Title: Re: Packaging a python script as an executable
Post by: javelinrl on January 17, 2017, 08:29:05 PM
You're absolutely right. My game requires Java but I don't provide an installer, I just ask people to download it from the website first and install it if they don't have it already. People still seem to download and play the game so I guess it's not something that bothers people too much. So I was saying this in regards to humble games like most RLs. If you want a game on Steam or to feel more professional (and potentially sold) you'd probably want an installer of some kind to do that for you.

As for dependencies, I've been successful in the past just distributing their source files with my own package. I've seen some big companies do the same. I'm not sure this would work with all libraries though, or if some of them need to be installed to work properly. Anyway, you can always ask your players to run a single pip command line as well to install any dependencies - the system is there and works fine so why not use it. Again, if you're trying to sell your game you shouldn't do this but for hobby projects like ours I feel it's not much to ask from the player, since we don't ask for anything else.
Title: Re: Packaging a python script as an executable
Post by: AgingMinotaur on January 17, 2017, 08:49:37 PM
True that. It is a privilege of tinkering in all humility, as you say, to make whatever you like however you want.

As always,
Minotauros
Title: Re: Packaging a python script as an executable
Post by: Krice on January 17, 2017, 09:28:37 PM
Java is super annoying dependency, because it's such a bloatware and security risk. Python is also kind of dumb, because it has no backwards compatibility whatsoever so many programs simply include the entire python with it, using the proper version for that software. Why can't we fix this? It's 2017 and still we don't have something that would turn EVERYTHING into a native .exe (binary) without dependencies. Go computer science.
Title: Re: Packaging a python script as an executable
Post by: KM on January 18, 2017, 02:21:59 AM
Java is super annoying dependency, because it's such a bloatware and security risk. Python is also kind of dumb, because it has no backwards compatibility whatsoever so many programs simply include the entire python with it, using the proper version for that software. Why can't we fix this? It's 2017 and still we don't have something that would turn EVERYTHING into a native .exe (binary) without dependencies. Go computer science.

It's actually baffling to me how difficult this process is.  I figured I'd just hit compile in Python and BOOM, have an .exe.

Alas, it's a challenge.
Title: Re: Packaging a python script as an executable
Post by: javelinrl on January 18, 2017, 05:20:30 AM
If you thought you'd just compile Python into an EXE then you've fundamentally misunderstood the whole premise of it. I suggest you reconsider your way of thinking, as I've said before because you could be trying to hit a screw with a hammer (trying to solve a problem with a method that really doesn't apply to it).

As a last case scenario you can always create a compiled EXE in another language like C++ that does nothing but execute a system command that calls Python for you and runs your script. Unnecessary to say that'd be a very unpythonic way of doing things. It will work but you'd be just as better reconsidering your language of choice if it comes down to it, in my opinion. Or, as I've said before, create a system link (like a start menu entry) that does the same thing for you, or a BAT file.
Title: Re: Packaging a python script as an executable
Post by: tuturto on January 18, 2017, 10:36:35 AM
It's been a while since I used py2exe, but my hunch is that you should explicitly include BearLibTerminal.dll in your package, as shown in http://stackoverflow.com/questions/220777/including-pyds-dlls-in-py2exe-builds
Title: Re: Packaging a python script as an executable
Post by: Cfyz on January 18, 2017, 02:37:13 PM
As for BearLibTerminal the problem was in the wrapper. It looked for a binary in the module directory (if it exists) or the application directory (otherwise). Turns out, a packed module still has its __file__, though a wrong one like "C:\dist\app.exe\terminal.py" which looks like there is an app.exe directory.

I've made a small update (0.15.1), changing the behaviour to look in both directories. I've tested it with PyInstaller and py2exe and it seems to work as long as you copy a library .dll near the .exe.
I do not know how to correctly pack the .dll into the executable yet.
Title: Re: Packaging a python script as an executable
Post by: Avagart on January 18, 2017, 04:20:57 PM
My game requires Java but I don't provide an installer, I just ask people to download it from the website first and install it if they don't have it already. People still seem to download and play the game so I guess it's not something that bothers people too much.

AgingMinotaurs is right - it's all about dependencies. People (I mean windows users now, due to py2exe case) still are downloading and playing your game, ok. But java is really common thing, most users have it installed already, usually there is no need to download any additional package. It's why java dependecy doesn't bother and doesn't affect your downloads. But python is not very popular on windows. Unlike linux, microsoft doesn't ship python together with its systems; also python is very rare dependency. So, most users wouldn't download and install python just for playing one game. (Omitting whole topic about py2 vs py3 mess and problems with using these two environments together). Packing python application into executable
is only sensible way to distribute python games for windows.
Title: Re: Packaging a python script as an executable
Post by: KM on January 19, 2017, 02:25:38 AM
If you thought you'd just compile Python into an EXE then you've fundamentally misunderstood the whole premise of it.

Elaborate?
Title: Re: Packaging a python script as an executable
Post by: Avagart on January 19, 2017, 09:31:02 AM
I suppose that javelinrl had in mind that whole python compilation is sort of... fake. Output of py2exe and pyinstaller (and cx_freeze, if I'm not mistaken, but maybe it's linux exclusive?) is exe package that includes your scripts and a python interpreter. Your code is still interpreted by python environment. It implies few things you'd need to know: a) python exes are bloated b) your code will not be faster; if it's slow now, it will be slow after compilation 3) it's very easy to decompile python exes (so, no the best choice if you really need your sources closed)

But still, in my opinion, packing py files into exe is best choice for deploying your software to windows. But not due to speed up or something. It's a good choice because there will be no need to download python.
Title: Re: Packaging a python script as an executable
Post by: javelinrl on January 19, 2017, 05:37:19 PM
Avagart got my meaning but just to make it clearer: Python is not a compiled language in the sense it compiles to an EXE so the fact you're trying to do that isn't even something the language creators had in mind. It is, in fact a compiled language but not in the same sense that C or C++ are compiled, you're not supposed to distribute the PYC binaries but the source PY files themselves. Py2exe is not an official part of the Python language but a hack and as such it's obviously not the recommended way of doing things (the pythonic way).

I have raised a few issues that you haven't addressed but my point is: if you have no reason against doing that, you should just distribute a BAT file that executes the Python command like all other Python games do. The player will need to install Python manually but that is the pythonic way of doing things, as far as I'm concerned - or you could ship an installer that also runs the Python installation and uses pip to grab any required dependencies.

I've got nothing against you creating an EXE for your game if it works. I just want you to understand that this is a hack and unofficial way of doing things (which is why you're running into trouble, probably) and not the way Python is designed to work.
Title: Re: Packaging a python script as an executable
Post by: Avagart on January 20, 2017, 12:11:31 AM
Quote
it's obviously not the recommended way of doing things (the pythonic way).
It's right.

But
Quote
distribute a BAT file that executes the Python command like all other Python games do
It's... not exactly true. It's clearly java's way to execute programs. Just checked randomly some windows software written in python. Calibre, Deluge, TortoiseHG - they are python-indenpendent. OK, it's not just bloated exe that we was talking about. But also, their windows releases are not shipped via source code and instruction 'if you want to use this software, you need to download python and all dependencies', or with python installer. Sometimes games (Civilization 4 is good example) are using python as intepreter in more traditional way, but it's more about shipping game with portable python, with all dependencies already installed. No need to manually install third-party software or libraries. Especially that pip, altought handy, is really vulnerable part of python. So, despite being pythonic or unpythonic, I'd say that your assumption (that everyone who make windows software in python is just releasing sources) seems wrong for me.
Title: Re: Packaging a python script as an executable
Post by: javelinrl on January 20, 2017, 01:07:31 PM
your assumption (that everyone who make windows software in python is just releasing sources) seems wrong for me.

That is not what I said, though. I deliberately said most Python games. I've seen a few Python roguelikes and that's how they do things. I can't say much for commercial games but I honestly doubt there are many commercial games written purely in Python.

I took a quick look at the projects you mention and at least one of them seems to be using bbfreeze, which compiles Python into an EXE.

Another uses MSVCCompiler, which seems to be more of an official approach. I wouldn't recommend it though since the project's build script alone is almost a thousand lines of Python code. https://wiki.python.org/moin/WindowsCompilers
Title: Re: Packaging a python script as an executable
Post by: Avagart on January 20, 2017, 02:31:22 PM
Yeah, I made my own assumption about your assumpion :D I misunderstood *spirit* of your post, I'm sorry.

So, about python roguelikes - I'm working on roguelike collection now, and currently I'm into 7DRLS. Most of python roguelike developers (not only 7DRLs) include windows build (created usually by py2exe or pyinstaller). Examples: Swift Swurd by Neil Thapen, ZDay by Sheep, mujahid by Pat Wilson, Madness by hmp, Hive Awakening by Gero Kunter, Dungeon Themed Starvation Simulator by Mark R Johnson, Nightmare Tyrant by zasvid, and much, really much more. And it's true not only for 7DRLS, check, for example, ArmCom by Rev. Sudasana, Lands of Strangers by Aging Minotaur, rng clrc by Jan. I'm putting info about authors to show that it's really common practice, not the quirk of one or two developers.

Of course, there are roguelikes released only as source code (like, for example, Swamp Monster by cturner, Trinkets by Geek of Geeks and Dad) but it is the minority. Sometimes developers (as Geek of Geeks and Dad, if I remember correctly) stated that they wanted to build windows executable, but there was no more time. And only-sources releases, if at all, are mainly for 7DRL, I don't know much not-7drl python roguelikes without exe package. Also, I know about only one developer who used to ship roguelikes as sources with python installer (unable to find it now, unfortunately. Name of game was... Sandstorm? Something similar). Probably never spot any single roguelike released as sources with windows batch file.

One more word, because... Why is it important in my opinion? You stated that (yeah, I know I quoted it my previous post already)
Quote
you should just distribute a BAT file that executes the Python command like all other Python games do
If you'd make proper reasearch (you should do it, it's about packing python into windows executable, and, as you said, you wasn't using windows for long time) you would see that it isn't correct.  So, you gave KM advice basing on wrong conviction, and you presented this conviction as fact.

To be clear: hi, KM, most python developers release windows builds created in various ways, including py2exe.

edit: edits was about grammar
Title: Re: Packaging a python script as an executable
Post by: Aukustus on January 20, 2017, 03:17:54 PM
Exe compilation is undoubtedly the only real way of doing Python game development on Windows.
Title: Re: Packaging a python script as an executable
Post by: javelinrl on January 20, 2017, 07:37:39 PM
No need to apologize, communication on the Internet is hard - it took a little while but I think we're on the same page now. I only knew a few Python RLs and games and you certainly know much more than me based on your examples and collecting work so it's pretty clear to me now that Python EXEs are a thing. It still stands though that it's a hack (maybe a necessary one, but still a hack) and not the official pythonic way of doing things, which Python developers are usually is so proud of. Again I understand now and admit that it must be a necessity for games but it still is a hack since Python doesn't compile to EXEs natively.