Binary file works in onedir mode, but not onefile

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Binary file works in onedir mode, but not onefile

Gemedet
I'm new to PyInstaller, and I've read through the manual and searched the mailing list, but I can't figure this out.

I want to include a single .dll file, like so:
a.binaries + [('avbin.dll', 'C:\\Windows\\System32\\avbin.dll', 'BINARY')]

Everything works fine when it just builds to a folder, but when I build it to an executable, it errors out:
WindowsError: [Error 126] The specified module could not be found

I used ArchiveViewer to look at the .exe, and I also looked in the _MEIPASS folder.  The .dll is definitely there, so I don't know what the problem is.

Thanks!  

--
You received this message because you are subscribed to the Google Groups "PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/pyinstaller?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
Reply | Threaded
Open this post in threaded view
|

Re: Binary file works in onedir mode, but not onefile

Martin Zibricky
Gemedet píše v Út 26. 03. 2013 v 09:13 -0700:
> I want to include a single .dll file, like so: a.binaries +
> [('avbin.dll', 'C:\\Windows\\System32\\avbin.dll', 'BINARY')]

What is the purpose of 'avbin.dll'?
- Is it a windows dll?
- pyinstaller ignores all dlls from C:\Windows\System32 and suppose that
these files should be available everywhere.

--
You received this message because you are subscribed to the Google Groups "PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/pyinstaller?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply | Threaded
Open this post in threaded view
|

Re: Binary file works in onedir mode, but not onefile

Martin Zibricky
In reply to this post by Gemedet
Gemedet píše v Út 26. 03. 2013 v 09:13 -0700:
> I'm new to PyInstaller, and I've read through the manual and searched
> the mailing list, but I can't figure this out.

Could you please as a new to pyinstaller give David Cortesi some
feedback to the new manual he works on?

--
You received this message because you are subscribed to the Google Groups "PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/pyinstaller?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Zak
Reply | Threaded
Open this post in threaded view
|

Re: Binary file works in onedir mode, but not onefile

Zak
In reply to this post by Gemedet
I had a similar problem with a ctypes DLL. I wrote a library in C, let's
call it my_lib.dll, and it worked fine in --onedir mode. It gave this
same error in --onefile mode (if I recall correctly). The problem was
that when Python tried to load my_lib.dll, it was looking in the wrong
folder. It was looking in the folder holding the --onefile EXE, it was
not looking in the temp directory created by the PyInstaller bootloader.
The example application below shows the solution:

# pyi_ctypes_example.py
#
# By Zak Fallows, 2013-03-26
#
# Point PyInstaller at this file, this is the base script.
#
# PyInstaller has a problem when working with ctypes DLLs in --onefile
mode.
# The problem appears as the following error message:
#   WindowsError: [Error 126] The specified module could not be found
# At least, I think that is the error message. I am only 95% sure. The core
# of the problem is that if you freeze the app to create my_app.exe, and
the
# file my_app.exe is in C:\Users\zakf\Downloads\my_app.exe, then the app
# will look for DLLs in C:\Users\zakf\Downloads\, it will NOT look for DLLs
# in C:\Users\zakf\AppData\Local\Temp\_MEI8482\, but this latter directory
# (which is the PyInstaller temp directory) is where the DLL is actually
# located. We must hack the Python so that it looks for the DLL in the temp
# directory, rather than the directory that holds the EXE.
#
# Much of this file is copied from saber/pyi_utils.py

from ctypes import *
import sys
import os.path

def resource_path(relative_path):
     """Returns the path to a resource file in the PyInstaller temp
directory

     Arguments:
         relative_path   String, e.g. "my_lib.dll"

     When this file is running in development (i.e. it has not been
packaged by
     PyInstaller yet), this function returns a path such as:
         C:/Users/zakf/my_app/my_lib.dll
     But when this app is running in frozen mode (i.e. it has been
packaged by
     PyInstaller and it is now a --onefile executable), the resource
files are
     in a very different place. In --onefile frozen mode, the resource
files
     are all extracted to a temporary directory. The path to the temporary
     directory is given by sys._MEIPASS. Thus, resource_path() will
return the
     correct path to the resource file in the temporary directory, such as:
         C:/Users/zakf/AppData/Local/Temp/_MEI8482/my_lib.dll

     """

     try:
         temp_dir_path = sys._MEIPASS
     except AttributeError:
         temp_dir_path = os.path.abspath(".")
     return os.path.join(temp_dir_path, relative_path)

dll_path = resource_path("my_lib.dll")
lib = cdll.LoadLibrary(dll_path)

# Call a function in the DLL:

lib.my_function(c_int(5))

I am also attaching this example as a Python file. It works, all you
need to do is add the DLL.

I don't know if you are using ctypes to call the DLL. If you are using
something else, then it may be having a similar problem. It may not be
looking in the right directory (the temp dir) for the DLL. There are two
possible solutions:

1. Do something like what I did. Tell it where to look.

2. When you distribute your app, tell the users that they need a copy
avbin.dll sitting right next to the EXE. They must keep the EXE and DLL
together, because the EXE will look for the DLL in its home folder. This
is silly but it works. You package with --onefile, but you have to
distribute two files.

Good luck,

Zak Fallows

--
You received this message because you are subscribed to the Google Groups "PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/pyinstaller?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.



pyi_ctypes_example.py (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Binary file works in onedir mode, but not onefile

Gemedet
Awesome, thanks Zak!  It was using ctypes, so calling LoadLibrary manually fixed it.

G


On Tue, Mar 26, 2013 at 11:03 AM, Zak <[hidden email]> wrote:
I had a similar problem with a ctypes DLL. I wrote a library in C, let's call it my_lib.dll, and it worked fine in --onedir mode. It gave this same error in --onefile mode (if I recall correctly). The problem was that when Python tried to load my_lib.dll, it was looking in the wrong folder. It was looking in the folder holding the --onefile EXE, it was not looking in the temp directory created by the PyInstaller bootloader. The example application below shows the solution:

# pyi_ctypes_example.py
#
# By Zak Fallows, 2013-03-26
#
# Point PyInstaller at this file, this is the base script.
#
# PyInstaller has a problem when working with ctypes DLLs in --onefile mode.
# The problem appears as the following error message:
#   WindowsError: [Error 126] The specified module could not be found
# At least, I think that is the error message. I am only 95% sure. The core
# of the problem is that if you freeze the app to create my_app.exe, and the
# file my_app.exe is in C:\Users\zakf\Downloads\my_app.exe, then the app
# will look for DLLs in C:\Users\zakf\Downloads\, it will NOT look for DLLs
# in C:\Users\zakf\AppData\Local\Temp\_MEI8482\, but this latter directory
# (which is the PyInstaller temp directory) is where the DLL is actually
# located. We must hack the Python so that it looks for the DLL in the temp
# directory, rather than the directory that holds the EXE.
#
# Much of this file is copied from saber/pyi_utils.py

from ctypes import *
import sys
import os.path

def resource_path(relative_path):
    """Returns the path to a resource file in the PyInstaller temp directory

    Arguments:
        relative_path   String, e.g. "my_lib.dll"

    When this file is running in development (i.e. it has not been packaged by
    PyInstaller yet), this function returns a path such as:
        C:/Users/zakf/my_app/my_lib.dll
    But when this app is running in frozen mode (i.e. it has been packaged by
    PyInstaller and it is now a --onefile executable), the resource files are
    in a very different place. In --onefile frozen mode, the resource files
    are all extracted to a temporary directory. The path to the temporary
    directory is given by sys._MEIPASS. Thus, resource_path() will return the
    correct path to the resource file in the temporary directory, such as:
        C:/Users/zakf/AppData/Local/Temp/_MEI8482/my_lib.dll

    """

    try:
        temp_dir_path = sys._MEIPASS
    except AttributeError:
        temp_dir_path = os.path.abspath(".")
    return os.path.join(temp_dir_path, relative_path)

dll_path = resource_path("my_lib.dll")
lib = cdll.LoadLibrary(dll_path)

# Call a function in the DLL:

lib.my_function(c_int(5))

I am also attaching this example as a Python file. It works, all you need to do is add the DLL.

I don't know if you are using ctypes to call the DLL. If you are using something else, then it may be having a similar problem. It may not be looking in the right directory (the temp dir) for the DLL. There are two possible solutions:

1. Do something like what I did. Tell it where to look.

2. When you distribute your app, tell the users that they need a copy avbin.dll sitting right next to the EXE. They must keep the EXE and DLL together, because the EXE will look for the DLL in its home folder. This is silly but it works. You package with --onefile, but you have to distribute two files.

Good luck,

Zak Fallows

--
You received this message because you are subscribed to the Google Groups "PyInstaller" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/pyinstaller?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.