Jack Antares
Jack Antares

Reputation: 67

Accessing resources from program in Debian package structure

I've made a DEB package of an C++ app that I've created. I want this app to use resources in the "data" directory, which, in my tests (for convenience), is in the same location that the program binary, and I call it from inside the code by its relative path. In the Debian OS there are standard locations to put the data files in (something like /usr/share/...), and other location to put the binaries in (probably /usr/bin). I'd not like to put the paths hard-coded in my program, I think its a better practice to access an image by "data/img.png" than "/usr/share/.../data/img.png". All the GNU classic programs respect the directories structure, and I imagine they do it in a good manner. I tried to use dpkg to find out the structure of the apps, but that didn't help me. Is there a better way that I'm doing to do this?

PS: I also want my code to be portable to Windows (cross-platform) avoiding using workarounds like "if WIN32" as much as possible.

Upvotes: 2

Views: 479

Answers (2)

Pihhan
Pihhan

Reputation: 808

This is not entirely linux specific or debian specific. I think is has something to do with Linux Standard Base or POSIX specifications maybe. I were unable to discover any specification quickly enough.

But you should not use some "base" directory and subdirectories in it for each type of data. Platform dependent code should belong into /usr/lib/programname, platform independent read-only data into /usr/share/programname/img.png. Data changed by application in /var/lib/programname/cache.db. Or ~/.programname/cache.db, depends what kind of application it is and what it does. Note: there is no need to "data" directory when /usr/share is already there for non-executable data.

You may want check http://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html if packaging for Debian. But it is not resources like in adroid or iphone, or windows files. These files are extracted on package install into target file system as real files.

Edit: see http://www.debian.org/doc/packaging-manuals/fhs/fhs-2.3.html

Edit2: As for multiplatform solution, i suggest you make some wrapper functions. On windows, it depends on installer, usually programs usually have path in registry to directory where they are installed. On unix, place for data is more or less given, you may consider build option for changing target prefix, or use environment variable to override default paths. On windows, prefix would be sufficient also, if it should not be too flexible.

I suggest some functions, where you will pass name of object and they will return path of file. It depends on toolkit used, Qt library may have something similar already implemented.

    #include <string>
    #ifdef WIN32
    #define ROOT_PREFIX "c:/Program Files/"
    const char DATA_PREFIX[] = ROOT_PREFIX "program/data";
    #else
    #define ROOT_PREFIX "/usr/"
    /* #define ROOT_PREFIX "/usr/local/" */
    const char DATA_PREFIX[] = ROOT_PREFIX "share/program";
    #endif

    std::string GetImageBasePath()
    {
      return std::string(DATA_PREFIX) + "/images";
    }

    std::string GetImagePath(const std::string &imagename)
    {
      // multiple directories and/or file types could be tried here, depends on how    sophisticated
      // it should be.
      // you may check if such file does exist here for example and return only image type that does exist, if you can load multiple types.
      return GetImageBasePath() + imagename + ".png";
    }

    class Image;
    extern Image * LoadImage(const char *path);

    int main(int argc, char *argv[])
    {
      Image *img1 = LoadImage(GetImagePath("toolbox").c_str());
      Image *img2 = LoadImage(GetImagePath("openfile").c_str());
      return 0;
    }

It might be wise to make class Settings, where you can initialize platform dependent root paths once per start, and then use Settings::GetImagePath() as method.

Upvotes: 1

oliver
oliver

Reputation: 6771

In your Debian package you should indeed install your data in /usr/share/. When accessing your data, you should use the XDG standard, which states that $XDG_DATA_DIRS is a colon-separated list of data directories to search (also, "if $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used.").

Upvotes: 1

Related Questions