Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

compiling .py into windows AND mac executables on Ubuntu

I have been trying for hours to figure out how to do this going through pyinstaller's docs, but I haven't had any luck.

I have a single .py file, and I need that made into a .exe file executable in windows 7, and a .app (or what ever works) executable in OS X Lion. The problem is that when ever I use

python pyinstaller.py my_code.py

it compiles into a linux executable.

like image 267
Nick Taber Avatar asked Jul 17 '13 20:07

Nick Taber


2 Answers

Pyinstaller doesn't build executables for cross-platform targets, only for the platform on which Pyinstaller is run "natively". However, WINE allows running the native Windows Pyinstaller under Linux, so it can be used to build Python scripts developed on Linux into native Windows .exe executables using only the single Linux host - no separate Windows host necessary. These instructions don't target Mac.

  1. I'm using Ubuntu 15.10 on a 64bit Pentium-type.

    $ uname -op
    x86_64 GNU/Linux
    $ grep DISTRIB_DESCRIPTION /etc/lsb-release  
    DISTRIB_DESCRIPTION="Ubuntu 15.10"
    
  2. Ensure Python is installed.

    $ apt-get install python2.7
    [installed OK]
    $ python --version
    Python 2.7.10
    
  3. (Upgrade and) use the Python package manager to install and possibly upgrade Pyinstaller on Linux. Running pip without superuser privileges might fail.

    $ sudo -H pip install --upgrade pip
    [upgraded OK]
    $ sudo -H pip install PyInstaller
    [installed OK]
    $ sudo -H pip install --upgrade pyinstaller
    [installed OK]
    $ pyinstaller --version
    3.0
    
  4. You can install Python/Pyinstaller, install/configure WINE and write Python code in any order (though running code requires Python is installed). Use the Python package manager to install Python packages pendent to your Python project.

    $ pip install package1 [package2, ...]
    [packages installed OK]
    
  5. Test packaging the executable targeting Linux.

    $ cd python-project
    $ pyinstaller --onefile python-project.py
    [built OK]
    $ dist/python-project
    [ran OK]
    

    If it doesn't build or run OK, try building it as --onedir , the Pyinstaller default, which doesn't include pendent files in the single executable. That shouldn't build/run any differently than the onefile version, but it can be easier to debug the onedir which should then build OK as onefile too.

  6. Ensure WINE is installed and configure it to use your selected target Windows version (eg. Windows 7):

    $ wine --version
    wine-1.7.50
    $ winecfg
    [GUI: Applications tab > Windows Version: Windows 7]
    
  7. Use WINE to install the Windows Python, pywin32 (Windows GUI extensions); match their versions. You should probably go to each installer's download page for the right versions and mirrors rather than these current direct download links. Note that running WINE dumps a lot of WINE bug notifications to the console; these are practically all negligible in this procedure.

    $ mkdir -p /opt/windows $ pushd /opt/windows
    $ wget https://www.python.org/ftp/python/2.7.10/python-2.7.10.amd64.msi
    $ wget http://iweb.dl.sourceforge.net/project/pywin32/pywin32/Build%20219/pywin32-219.win-amd64-py2.7.exe
    $ wine msiexec -i python-2.7.10.amd64.msi $ wine msiexec -i pywin32-219.win-amd64-py2.7.exe
    $ popd
    

    I had problems with the Python 2.7.10 MSI wizard failing to "Next" after selecting the install directory, so I cancelled it there and ran it again adding the -qn option that suppresses the GUI. It complained a little but it completed the installation. If you need to find Windows Python in your Linux filesystem it's by default installed in your Linux user's default WINE "C:" directory in your home directory, ie. ~/.wine/drive_c/Python27 .

    $ wine C:/Python27/python --version Python 2.7.10
    $ find ~/.wine/drive_c -name python.exe ~/.wine/drive_c/Python27/python.exe
    
  8. Upgrade Windows pip and install Pyinstaller using WINE Python/pip.

    $ wine C:/Python27/Scripts/pip.exe install --upgrade pip
    [upgraded OK]
    $ wine C:/Python27/Scripts/pip.exe --version
    pip 7.1.2 from C:\Python27\lib\site-packages (python 2.7)
    $ wine C:/Python27/Scripts/pip.exe install pyinstaller
    [installed OK]
    $ wine c:/Python27/python.exe C:/Python27/Scripts/pyinstaller-script.py --version
    3.0
    
  9. Install your project's pendent packages with Windows pip

    $ wine C:/Python27/Scripts/pip.exe install xlwt
    [installed OK]
    
  10. Now your Windows (WINE) Python environment is configured equivalently to your Linux native environment. Running Windows Pyinstaller under WINE generates a native Windows .exe executable. Use the Windows Python script version of Windows Pyinstaller to maintain parity with your tested OK Linux Pyinstaller procedure, against your python project in your Linux filesystem (it doesn't need to be copied to the WINE Windows filesystem). Keeping the Windows build and dist directories separate from the tested OK Linux one can help debugging the packaging procedure.

     $ wine c:/Python27/python.exe C:/Python27/Scripts/pyinstaller-script.py --onefile --workpath=./win-wrk --distpath=/opt/windows python-project.py
     [packaged OK]
     $ ls -F /opt/windows/python-project.exe
     python-project.exe*
     $ wine /opt/windows/python-project.exe
     [Windows app runs OK]
    
like image 102
Matthew Avatar answered Sep 28 '22 15:09

Matthew


From the pyinstaller FAQ:

Can I package Windows binaries while running under Linux?

No, this is not supported. Please use ​Wine for this, PyInstaller runs fine in Wine. You may also want to have a look at ​this thread in the mailinglist. In version 1.4 we had build in some support for this, but it showed to work only half. It would require some Windows system on another partition and would only work for pure Python programs. As soon as you want a decent GUI (gtk, qt, wx), you would need to install Windows libraries anyhow. So it's much easier to just use Wine.

In other words, you cannot simply run a command in Linux to build a Windows executable (or a Mac executable for that matter) like you are trying to do. The workaround they have provided for Windows (and only for Windows) is to install Wine.

Wine is a program that allows windows programs to run on Linux. It creates an environment that replicates a windows environment. The idea is that you would install Python (using a Windows Python installer), as well as any other libraries that you need (such as pyinstaller), into this environment. Then, still in that environment, you run the python pyinstaller.

I haven't done all of this, but the mailing list thread mentioned in the FAQ would be a good start. Here is an example that they use:

PYDIR="c:/Python27" 
PYTHON="wine $PYDIR/python.exe" 
WINPWD=$(winepath -w $(pwd))

cd pyinstaller 

$PYTHON Configure.py 
$PYTHON Makespec.py -p $WINPWD $WINPWD/diceroller.py 
$PYTHON Build.py diceroller/diceroller.spec 

It looks like this uses the old "Configure.py", "Makespec.py" and "Build.py", whereas nowadays the "pyinstaller.py" script tries to do all of this for you.

like image 44
Mark Hildreth Avatar answered Sep 28 '22 14:09

Mark Hildreth