Search code examples
pythonexecutablecx-freeze

How to know the current file path after being frozen into an executable using cx_Freeze?


I am making games in Python. Since I am using Python3, I have to cx_Freeze my scripts into executables to let other people who don't have Python3 run the games. I've put the resources (textures, audio, files etc.) in a folder that was related to the script path. When I didn't cx_Freeze the script, I used __file__ to locate the script and use this to locate the resources and use them. But once frozen using cx_Freeze, this method doesn't work.

My question is, how can find the file path of a script after it is being frozen using cx_Freeze?

I've tried __file__, os module and any other modules related to file paths.

path = str(__file__).split("/")
path.remove("My executable name")
path.remove("MacOS")
path = "/".join(path) + "/Resources/"

I expected to return my Resources folder, but __file__ only returns my home directory so this causes a traceback.


Solution

  • There is a section Using data files in the cx_Freeze documentation dedicated to this question, saying:

    Applications often need data files besides the code, such as icons. Using a setup script, you can list data files or directories in the include_files option to build_exe. They’ll be copied to the build directory alongside the executable. Then to find them, use code like this:

    def find_data_file(filename):
        if getattr(sys, 'frozen', False):
            # The application is frozen
            datadir = os.path.dirname(sys.executable)
        else:
            # The application is not frozen
            # Change this bit to match where you store your data files:
            datadir = os.path.dirname(__file__)
        return os.path.join(datadir, filename)
    

    An alternative is to embed data in code, for example by using Qt’s resource system.

    There is one further point to notice if you are using cx_Freeze version 5.1.0 or 5.1.1: packages will be included into a subdirectory lib of the build directory of the frozen application, whereas they are in the main directory of the unfrozen application or in the site-packages directory of the Python installation. If you refer to data files located in packages directories from the main application, you need to add this additionnal lib to the relative path using e.g. os.path.join() (or to remove it in the other direction).

    In your case, however, I guess Resources is simply a data directory, not a package with Python code. Then you only need to add 'Resources' to the include_files list in the setup script. To get a file named filename located in the Resources directory, the example code modified like this should do the job:

    def find_data_file(filename):
        if getattr(sys, 'frozen', False):
            # The application is frozen
            datadir = os.path.dirname(sys.executable)
        else:
            # The application is not frozen
            datadir = os.path.dirname(__file__)
        # The following line has been changed to match where you store your data files:
        return os.path.join(datadir, 'Resources', filename)