148

I thought I heard that py2exe was able to do this, but I never figured it out. Has anyone successfully done this? Can I see your setup.py file, and what command line options you used?

Basically I'm thinking of it giving me a single executable file that does something like unzips itself to maybe /temp and runs.

Jerub
  • 38,558
  • 14
  • 69
  • 90
Greg
  • 39,830
  • 86
  • 217
  • 286

9 Answers9

175

The way to do this using py2exe is to use the bundle_files option in your setup.py file. For a single file you will want to set bundle_files to 1, compressed to True, and set the zipfile option to None. That way it creates one compressed file for easy distribution.

Here is a more complete description of the bundle_file option quoted directly from the py2exe site*

Using "bundle_files" and "zipfile"

An easier (and better) way to create single-file executables is to set bundle_files to 1 or 2, and to set zipfile to None. This approach does not require extracting files to a temporary location, which provides much faster program startup.

Valid values for bundle_files are:

  • 3 (default) don't bundle
  • 2 bundle everything but the Python interpreter
  • 1 bundle everything, including the Python interpreter

If zipfile is set to None, the files will be bundle within the executable instead of library.zip.

Here is a sample setup.py:

from distutils.core import setup
import py2exe, sys, os

sys.argv.append('py2exe')

setup(
    options = {'py2exe': {'bundle_files': 1, 'compressed': True}},
    windows = [{'script': "single.py"}],
    zipfile = None,
)
Community
  • 1
  • 1
minty
  • 21,168
  • 38
  • 87
  • 105
  • is it possible to create a single file, that depends on the python dll? I don't mind 1 exe+1 dll (as the dll can be installed to a common location), as long as all the little dependency files are hidden away in the exe. – gbjbaanb Jul 30 '09 at 10:29
  • 6
    Sure if you want only the interpreter not bundled then choose 2 for the bundle_files option. Good luck! – minty Aug 10 '09 at 17:36
  • 13
    Please note that bundle_files 1 isn't supported on amd64 (py2exe 0.6.9 for Python 2.6 at least) – Joril Mar 08 '11 at 17:20
  • @endolith: Sorry but I don't remember anymore... :( – Joril Mar 13 '12 at 08:49
  • 1
    What's with the `sys.argv.append('py2exe')` line? I didn't need that for it to work. – Pat Jun 12 '12 at 18:19
  • 2
    @Pat: The call to run py2exe is "python setup.py py2exe". By automatically appending the "py2exe" on the end, it just means you don't have to type it in at the command line. – orlade Jul 01 '12 at 02:30
  • 4
    Not exactly a single executable, as you need to [install the Microsoft Visual C runtime DLL](http://www.py2exe.org/index.cgi/Tutorial#A5.ProvidingtheMicrosoftVisualCruntimeDLL). – Kevin Smyth Sep 28 '12 at 13:56
  • 3
    I had a console application that I wanted to have as a single executable. I had to replace `windows = [{'script': "single.py"}]` with `console = ['single.py']` so double-clicking the file would open in a CMD window in Windows. – Jeff B Jul 09 '14 at 16:08
  • @minty How does the set-up file know what file directory the resources to bundle are in? How does it know which files they are? Thanks. – the_prole Nov 21 '14 at 14:32
  • This doesn't bundle Tcl –  Apr 03 '16 at 21:56
  • 2
    6 years since @Joril's comment and still - "error: bundle-files 1 not yet supported on win64" – lightsong Mar 19 '17 at 15:13
  • @AlexJolig That is probably because you aren't using a compatible version of python. See this post [here](https://stackoverflow.com/questions/41578808/python-indexerror-tuple-index-out-of-range-when-using-py2exe) – Firix Feb 07 '19 at 16:13
  • This works wonderful w/ the console options for setup. I am able to retain original console interaction. console=['scriptypoo.py'], thank you! – Everett Wenzel Apr 26 '19 at 15:21
  • In my case (Python 2.7, Windows 10), this solution creates a huuuuge 4MB EXE file from just a 18KB PY file, and the worst: running the EXE file does absolutely nothing! – Apostolos Dec 03 '19 at 19:34
108

PyInstaller will create a single .exe file with no dependencies; use the --onefile option. It does this by packing all the needed shared libs into the executable, and unpacking them before it runs, just as you describe (EDIT: py2exe also has this feature, see minty's answer)

I use the version of PyInstaller from svn, since the latest release (1.3) is somewhat outdated. It's been working really well for an app which depends on PyQt, PyQwt, numpy, scipy and a few more.

Community
  • 1
  • 1
dF.
  • 67,375
  • 27
  • 125
  • 135
  • 6
    I found py2exe worked a lot better than pyInstaller, when you're using eggs. minty's answer is the solution. – gbjbaanb Jul 30 '09 at 10:23
  • Please note that as of version 1.4, PyInstaller doesn't support Python 2.6+ on Windows – Joril Mar 09 '11 at 08:08
  • 2
    I am now using version 1.5.1, and it works with Python 2.7.2. – oob Jan 02 '12 at 03:35
  • 1
    py2exe can create a single file executable if you specify a few arguments in the compiler program. py2exe has a tutorial for single file executables online. – trevorKirkby Dec 09 '13 at 21:41
  • 3
    Objective Viewpoint: I do not see how this is an acceptable answer since it does not address the question of creating a single exe file with py2exe. (Nonetheless, this is a useful answer of course.) – Jonathan Komar May 15 '15 at 11:24
  • PyInstaller is very bad at adding extra data files in the bundle. It's trying luck! I never got it working. But PyInstaller works perfect if you don't need a single executable file, but a folder is acceptable. – Jithin Pavithran Oct 14 '17 at 19:03
  • As mentioned above (@JonathanKomar) this does not answer the question directly. **note**: working with environment separation (like venv) might cause PyInstaller to miss packages. one should use the `--paths=` switch to avoid that – DarkLight Nov 18 '19 at 15:04
  • @JithinPavithran I have no problem bundling data files and resources in my single executable file using PyInstaller, but it imports too many unused modules which causes an huge exe size (300 MB with my distribution). That's what brought me here actually, looking for alternatives to PyInstaller. – Guimoute Oct 22 '20 at 15:29
15

As the other poster mention, py2exe, will generate an executable + some libraries to load. You can also have some data to add to your program.

Next step is to use an installer, to package all this into one easy-to-use installable/unistallable program.

I have used InnoSetup with delight for several years and for commercial programs, so I heartily recommend it.

galoget
  • 529
  • 6
  • 11
Philippe F
  • 10,569
  • 5
  • 27
  • 29
7

I've been able to create a single exe file with all resources embeded into the exe. I'm building on windows. so that will explain some of the os.system calls i'm using.

First I tried converting all my images into bitmats and then all my data files into text strings. but this caused the final exe to be very very large.

After googleing for a week i figured out how to alter py2exe script to meet my needs.

here is the patch link on sourceforge i submitted, please post comments so we can get it included in the next distribution.

http://sourceforge.net/tracker/index.php?func=detail&aid=3334760&group_id=15583&atid=315583

this explanes all the changes made, i've simply added a new option to the setup line. here is my setup.py.

i'll try to comment it as best I can. Please know that my setup.py is complex do to the fact that i'm access the images by filename. so I must store a list to keep track of them.

this is from a want-to-b screen saver I was trying to make.

I use exec to generate my setup at run time, its easyer to cut and paste like that.

exec "setup(console=[{'script': 'launcher.py', 'icon_resources': [(0, 'ICON.ico')],\
      'file_resources': [%s], 'other_resources': [(u'INDEX', 1, resource_string[:-1])]}],\
      options={'py2exe': py2exe_options},\
      zipfile = None )" % (bitmap_string[:-1])

breakdown

script = py script i want to turn to an exe

icon_resources = the icon for the exe

file_resources = files I want to embed into the exe

other_resources = a string to embed into the exe, in this case a file list.

options = py2exe options for creating everything into one exe file

bitmap_strings = a list of files to include

Please note that file_resources is not a valid option untill you edit your py2exe.py file as described in the link above.

first time i've tried to post code on this site, if I get it wrong don't flame me.

from distutils.core import setup
import py2exe #@UnusedImport
import os

#delete the old build drive
os.system("rmdir /s /q dist")

#setup my option for single file output
py2exe_options = dict( ascii=True,  # Exclude encodings
                       excludes=['_ssl',  # Exclude _ssl
                                 'pyreadline', 'difflib', 'doctest', 'locale',
                                 'optparse', 'pickle', 'calendar', 'pbd', 'unittest', 'inspect'],  # Exclude standard library
                       dll_excludes=['msvcr71.dll', 'w9xpopen.exe',
                                     'API-MS-Win-Core-LocalRegistry-L1-1-0.dll',
                                     'API-MS-Win-Core-ProcessThreads-L1-1-0.dll',
                                     'API-MS-Win-Security-Base-L1-1-0.dll',
                                     'KERNELBASE.dll',
                                     'POWRPROF.dll',
                                     ],
                       #compressed=None,  # Compress library.zip
                       bundle_files = 1,
                       optimize = 2                        
                       )

#storage for the images
bitmap_string = '' 
resource_string = ''
index = 0

print "compile image list"                          

for image_name in os.listdir('images/'):
    if image_name.endswith('.jpg'):
        bitmap_string += "( " + str(index+1) + "," + "'" + 'images/' + image_name + "'),"
        resource_string += image_name + " "
        index += 1

print "Starting build\n"

exec "setup(console=[{'script': 'launcher.py', 'icon_resources': [(0, 'ICON.ico')],\
      'file_resources': [%s], 'other_resources': [(u'INDEX', 1, resource_string[:-1])]}],\
      options={'py2exe': py2exe_options},\
      zipfile = None )" % (bitmap_string[:-1])

print "Removing Trash"
os.system("rmdir /s /q build")
os.system("del /q *.pyc")
print "Build Complete"

ok, thats it for the setup.py now the magic needed access the images. I developed this app without py2exe in mind then added it later. so you'll see access for both situations. if the image folder can't be found it tries to pull the images from the exe resources. the code will explain it. this is part of my sprite class and it uses a directx. but you can use any api you want or just access the raw data. doesn't matter.

def init(self):
    frame = self.env.frame
    use_resource_builtin = True
    if os.path.isdir(SPRITES_FOLDER):
        use_resource_builtin = False
    else:
        image_list = LoadResource(0, u'INDEX', 1).split(' ')

    for (model, file) in SPRITES.items():
        texture = POINTER(IDirect3DTexture9)()
        if use_resource_builtin: 
            data = LoadResource(0, win32con.RT_RCDATA, image_list.index(file)+1) #windll.kernel32.FindResourceW(hmod,typersc,idrsc)               
            d3dxdll.D3DXCreateTextureFromFileInMemory(frame.device,   #Pointer to an IDirect3DDevice9 interface
                                              data,                #Pointer to the file in memory
                                              len(data),           #Size of the file in memory
                                              byref(texture))      #ppTexture
        else:
            d3dxdll.D3DXCreateTextureFromFileA(frame.device, #@UndefinedVariable
                                               SPRITES_FOLDER + file,
                                               byref(texture))            
        self.model_sprites[model] = texture
    #else:
    #    raise Exception("'sprites' folder is not present!")

Any questions fell free to ask.

Nor
  • 105
  • 1
  • 4
  • I 've tried your method and it works good but I don' t understeand how to add file to the option file_resurces to embled some file into the .exe. I' ve modified the build_exe.py file as you said but when I go into the setup.py file and I write `\'file_resources': [('txt2.txt')]` it gives me error (the file that I want to embled in my .exe is named txt2 and it's a .txt file) – VinceLomba Sep 27 '15 at 08:27
  • You talked about how you converted all your images into bitmats and then all your data files into text strings. Even though you said that it makes the exe large, does this work and if so, can you tell me how to do this? I know this answer is pretty old but if you can respond that will be appreciated. – Peppa Apr 10 '19 at 00:57
4

You should create an installer, as mentioned before. Even though it is also possible to let py2exe bundle everything into a single executable, by setting bundle_files option to 1 and the zipfile keyword argument to None, I don't recommend this for PyGTK applications.

That's because of GTK+ tries to load its data files (locals, themes, etc.) from the directory it was loaded from. So you have to make sure that the directory of your executable contains also the libraries used by GTK+ and the directories lib, share and etc from your installation of GTK+. Otherwise you will get problems running your application on a machine where GTK+ is not installed system-wide.

For more details read my guide to py2exe for PyGTK applications. It also explains how to bundle everything, but GTK+.

Sebastian Noack
  • 1,677
  • 1
  • 14
  • 14
1

I'm told bbfreeze will create a single file .EXE, and is newer than py2exe.

ℳ  .
  • 361
  • 2
  • 9
  • 3
    As far as I can understand bbfreeze does not produce single-file executables. Could you document your answer ? – joaquin Dec 22 '12 at 09:35
-2

I recently used py2exe to create an executable for post-review for sending reviews to ReviewBoard.

This was the setup.py I used

from distutils.core import setup
import py2exe

setup(console=['post-review'])

It created a directory containing the exe file and the libraries needed. I don't think it is possible to use py2exe to get just a single .exe file. If you need that you will need to first use py2exe and then use some form of installer to make the final executable.

One thing to take care of is that any egg files you use in your application need to be unzipped, otherwise py2exe can't include them. This is covered in the py2exe docs.

David Dibben
  • 16,774
  • 6
  • 38
  • 40
-2

try c_x freeze it can create a good standalone

Denis
  • 332
  • 2
  • 14
  • cx_Freeze can't create a standalone executable, in fact, the documentation for cx_Freeze at https://buildmedia.readthedocs.org/media/pdf/cx-freeze/latest/cx-freeze.pdf says, "cx_Freeze does not support building a single file exe, where all of the libraries for your application are embedded in one executable file." For more details on standalone executables in cx_Freeze go to the documentation (https://buildmedia.readthedocs.org/media/pdf/cx-freeze/latest/cx-freeze.pdf) and go to section 4.5. – Peppa Apr 10 '19 at 00:51
-6

No, it's doesn't give you a single executable in the sense that you only have one file afterwards - but you have a directory which contains everything you need for running your program, including an exe file.

I just wrote this setup.py today. You only need to invoke python setup.py py2exe.

Torsten Marek
  • 74,426
  • 19
  • 88
  • 96
  • 1
    This is not accurate. With the correct options, you can get one standalone file. – trevorKirkby Dec 11 '13 at 15:59
  • @Torsten Marek... the link to your setup.py is dead. In particular.. the first two rederects end-up promoting commercial stuff. The third time it ends [here](http://ww1.diotavelli.net/?sub1=41f7fc3c-0080-11e8-8512-e8d570006125) at the dead-end of the internet. – ZF007 Jan 23 '18 at 21:04