Search code examples
pythonwindowspyinstallerminiconda

PyInstaller CLI can't use added binary (an .exe) even though I have added it with --add-binary flag (Windows)


Using Windows, I have a python program that runs CMD within using subprocess.Popen. When I run it from python, it works. When I create the executable and run it, it doesn't find the tool I am using (esptool):

'esptool' is not recognized as an internal or external command,
operable program or batch file.

The command call I have built so far with --add-binary is as follows:

pyinstaller -F main.py -n "ProgramTest" -i resources/ico/icon.ico --add-binary "C:\\Users\\<my_user>\\AppData\\Local\\miniconda3\\envs\\this_env\\Scripts\\esptool.exe;."

(I have obtained the path to esptool by running where.exe esptool. That's the only instance of esptool that appears.)

Also tried the solution listed here, where they use = after the flag (--add-binary="...") and using lib as in --add-binary="...;lib".

Perhaps it has something to do with my python environments? Maybe I am not adding correctly the executable?

The code to execute my cmd lines is as follows:

import subprocess

def execute(cmd):
    popen = subprocess.Popen(
        cmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True
    )
    for stdout_line in iter(popen.stdout.readline, ""):
        yield stdout_line
    popen.stdout.close()
    return popen.wait()

My environment:

  • OS Name: Microsoft Windows 10 Pro
  • Version: Windows 10.0.19045 Build 19045
  • miniconda: 23.1.0
  • Python (env): 3.10.9
  • PyInstaller: 5.8.0
  • esptool: 3.1

Solution

  • Same problem as adding data, you must create a relative path to the .exe.

    To be able to run the command in both an .exe and as a python script, I used:

    def get_exe_path(exe_name):
        if getattr(sys, "frozen", False):
            application_path = os.path.join(sys._MEIPASS, exe_name + ".exe")
        else:
            application_path = exe_name
        return application_path
    

    Now, just by appending it at the beggining of the call I want to call, it works:

    ESPTOOL_PATH = get_exe_path("esptool")
    order = ESPTOOL_PATH + " --port " + port + " --chip esp32 erase_flash"