Packaging your project

I'm using Makefile (Make) to package my SDL2 project. I'm also using SDL_GetPrefPath to locate and store/install my project's data, plugins, fonts, and other resources.

But the only way that I could think of to install those files into the returned path was to create a separate program called "paths" that I call from the Makefile; [all it does is return the results of SDL_GetPrefPath("myOrg", "MyGame")]].

Here's the excerpt from the Makefile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
LIBS = -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2_gfx -I./
LOCALS = item.cpp shapes.cpp
PHONEY = help
PREFIX = $(shell ./paths)
TAGS = -Wall -Os
GAMENAME = "MyGame"
BUILD = res/plugins/

install: paths
        @echo 'Installing $(GAMENAME) to ~/bin'
        @echo ' other files and resources will be added to $(PREFIX)'
        cp -ruv * `./paths`
        cp -u $(GAMENAME) ~/bin/

paths:
        g++ $(TAGS) installPaths.cpp $(LOCALS) $(LIBS) -o paths -I./


Is this a good system? Is there a better option for a general install instructions? Is there a way to do this without creating a separate "paths" program?
On Linux I would follow the XDG Base Directory Specification no matter what SDL says. I would not use upper case letters for the executable file name because they are case sensitive and nearly all linux commands/programs that I've seen have had lower case names.

https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
Last edited on
I'm going to push back on specifically relying on XDG environment variables: simply because they are not enabled by default across many Linux distributions, including my base install of Ubuntu. However, the specification does say what their variables generally boil down to, and most of those are very standard paths. It's really great to have those paths listed out.

The only disappointing one that I hoped to see an answer for was where to build for single-user local installs since my installing to ~/bin is not supported on some Linux distros that I've tested; but XDG recommends $HOME/.local/bin, which is not so common as to be in Ubuntu's default $PATH either. On the bright side, it might make more sense at that point to let that user decide where to copy the binary. Let them modify their own $PATH if needed/desired, otherwise I will provide a wider system install at/usr/local/bin or there's always the option to run in place.

"MyGame" is definitely a placeholder, but having a Capital at the beginning is nice for personal binaries as they do not often have name collisions in the terminal. Quick tab access for testing my installed versions is nice. I will change it for any released versions.

You certainly gave me a good option, and I have spent several hours this morning of research and self-debate over whether it's right for the project. In doing so I've learned a lot; Peter87, thank you.
Last edited on
newbieg wrote:
I'm going to push back on specifically relying on XDG environment variables: simply because they are not enabled by default across many Linux distributions

The XDG Base Directory Specification mentions default values that should be used if they are not set.

newbieg wrote:
The only disappointing one that I really wanted to see was where to build for single-user local installs ...

I have to admit that I have no experience with "single-user local installs", not with my own software or with other software that I've installed, so I don't know how that would work. I normally just run make followed by sudo make install which installs it for all users (not that it matters for me since I'm the only user).
Last edited on
There are a couple of benefits to local installs;

Technically they take less permissions by the user, I think even a guest account could build and locally install a program, as long as they can use make and g++ (though I don't know why guest would be given build permissions...)

Second, they remain personal to the one user, no need to alert the admin that you just installed solitaire.

Finally, and my favorite: you can build and install to a thumb-drive and take your programs/utilities and data on the go all together. That makes swapping between computers much more convenient as all your settings and tweaks to those tools also travel with your thumb-drive. (This just isn't quite as practical if you have a laptop that can travel almost as easily and is less likely to be forgotten while plugged in.)
Last edited on
I understand the advantages, but it doesn't seem to be as well supported. As you said, the default PATH often doesn't contain a user-specific directory. I made some lame attempts many years ago to see if I would work for my own software but the binaries were not found by default and the .desktop files were not picked up.

Many programs doesn't really need to be "installed" which I guess is why you can put them on a thumb-drive as you said. Instead of running make followed by make install you only run make and start running the program from where the executable is located (unless you create your own shortcuts manually). If the program has data files that are required to run then the program would need to search for the necessarily data files relative to the location of the executable file for this to work.

Makefiles often have variables (e.g. PREFIX) to configure where to install the files. This allows the user to do a "local install" pretty easily, assuming the PATH etc. has been set up for it to work correctly.

make install PREFIX=/home/user


I don't know if it's worth trying to read the XDG variables in the makefile. I think most build scripts just defaults to /usr/local (even when using ./configure by GNU Autotools).

XDG_DATA_DIRS can contain many paths so it's not even clear which one to choose for installation. I think these variables are mostly intended for the program itself and not for the build scripts because that is up to who is building to decide. When I said I would "follow the XDG Base Directory Specification no matter what SDL says" I mainly meant that I would not use SDL as the source of truth but instead do something that is compatible with the XDG specification even if that means the user needs to explicitly set the path when installing.


Forgive me if I make things more complicated than they really are, but to me it's not clear from the XDG specification how XDG_DATA_HOME should be handled exactly.

In the past I have treated XDG_DATA_HOME the same as the XDG_DATA_DIRS, with highest priority, and simply used it to look for static data files that the program used. It's a game so we're talking things like fonts and graphics.
XDG Base Directory Specification wrote:
$XDG_DATA_DIRS defines the preference-ordered set of base directories to search for data files in addition to the $XDG_DATA_HOME base directory.
XDG Base Directory Specification wrote:
The order of base directories denotes their importance; the first directory listed is the most important. When the same information is defined in multiple places the information defined relative to the more important base directory takes precedent. The base directory defined by $XDG_DATA_HOME is considered more important than any of the base directories defined by $XDG_DATA_DIRS.

I used XDG_CONFIG_HOME for all files that the program created (settings, replays and highscores) but I'm thinking now that maybe it would have been more correct to only use XDG_CONFIG_HOME for the settings and instead used XDG_DATA_HOME for the other program-generated files?
XDG Base Directory Specification wrote:
There is a single base directory relative to which user-specific configuration files should be written. This directory is defined by the environment variable $XDG_CONFIG_HOME.
XDG Base Directory Specification wrote:
There is a single base directory relative to which user-specific data files should be written. This directory is defined by the environment variable $XDG_DATA_HOME.

But does this mean that XDG_DATA_HOME should be used both for searching for static data files (that normally doesn't change after installation) AND for writing various data files that are created by the program (high scores, saved games, etc.)? My concern here is that it would require the uninstall target of the makefile to be much more complicated (normally I just remove all files in the game's install data dir but I don't necessarily want it to remove saved games and such). It would also make it more cumbersome for the user to make backups of only the relevant data.

I know the degree to which this specification is followed varies quite a lot. Some projects keep doing how they always have done because they don't want to break backwards compatibility. But I have a suspicion that many projects simply treat XDG_DATA_HOME and XDG_DATA_DIRS differently (i.e. write files to XDG_DATA_HOME and read static data files from XDG_DATA_DIRS) but I would have to do more research to know if this is true.
Last edited on
Makefiles often have variables (e.g. PREFIX) to configure where to install the files. This allows the user to do a "local install" pretty easily, assuming the PATH etc. has been set up for it to work correctly.

make install PREFIX=/home/user

I don't know if it's worth trying to read the XDG variables in the makefile. I think most build scripts just defaults to /usr/local (even when using ./configure by GNU Autotools).

Indeed.

At least the ./configure and CMake accept prefix as option when you do run them
(and tend to have /usr/local as default prefix). That way you don't have to give it to the "make install".


I do use RHEL-based distros. They have XDG, but more importantly, they have software in packages -- just like Ubuntu. Mixing files from source builds and from packages leads to a mess. The /usr/local is a bit gray, because some packages go there too. (Or NVidia is just evil ...)

Ideally, you would create deb-package for your software so that you can "apt install myprog" (or however one does use Ubuntu).


Most of my field-specific applications are not packaged for my distro. There are both source distributions and commercials proprietary apps. I have separate directory, e.g. /site/app9, where I shovel all those apps. With PREFIX or whatever.
Furthermore, I do use environment modules package. The apps are not on PATH
by default, the "modules" can set environment for apps when needed, and system config is augmented to find the modules. Furthermore, the directory is on file server and every workstation automounts the dir. Laptops have the dir on local disk.


The point is, don't write a Makefile. Write rules how to generate a Makefile. Rules for GNU buildtools, CMake, etc. For example: https://cmake.org/cmake/help/latest/guide/tutorial/index.html
Then user can decide on the PREFIX. It is not your problem.
SDL_GetPrefPath does not provide a place to install your app, it returns a system specific directory that the user has permissions to write to. This has nothing to do with where the app is installed.

You should not use the result of SDL_GetPrefPath as the build prefix (app install directory).

Different systems have different conventions for install system-wide apps.

For example, ArchLinux installs apps in /usr/, and mixes them with systems apps. Some systems may use /usr/local instead.

The convention is to use /opt to install full apps, with all their dependencies. Apple use this system, but renames /opt to /Applications.

Often, I build apps and use $HOME as the install directory. Typically, you just need to add $HOME/bin to PATH and $HOME/lib to LD_LIBRARY_PATH in your login profile.
Last edited on
[quote kbw]SDL_GetPrefPath does not provide a place to install your app, it returns a system specific directory that the user has permissions to write to. This has nothing to do with where the app is installed.[/quote]
- So you wouldn't even recommend SDL_GetPrefPath for config and data? Just leave it as output for the user? I was hoping by using it the Android API could make use of "Move this program to sd-card" option, but that was a guess on my part since I'm still just compiling and testing for my computer.

Thank you Keskiverto. I'm now looking into other options and tools; It makes sense to use the native tools for each target platform. I thought creating a deb package would be overwhelming, but there's a checkoff-sheet of steps that I found to streamline getting started. Getting that package hosted in a meaningful way may be a bit more complicated, but it will still be an interesting option.

@Peter87, thank you for describing the flow you use for XDG, it's still a path that I'm interested in implementing since it is going to be available on github.
PS, how do you get your [quote] to show a source?
Last edited on
The method you're using to install the files is not the most efficient, as it involves creating a separate program to determine the installation path. Instead, you can use a shell script to perform the installation, which will make the process more streamlined and avoid the need for the separate "paths" program.

First, create an installation shell script called install.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

# Determine the binary directory
if [ -d "$HOME/bin" ]; then
    BINDIR="$HOME/bin"
else
    BINDIR="/usr/local/bin"
fi

# Compile the project
make

# Copy the binary to the binary directory
cp -u MyGame "$BINDIR/"

# Create the base directory for resources
BASEDIR="$HOME/.local/share/MyGame"
mkdir -p "$BASEDIR"

# Copy resources to the base directory
cp -ruv res/ "$BASEDIR/"

echo "Installation complete."


Make the script executable:

chmod +x install.sh

Then, update your Makefile to remove the "paths" target and the "install" target. Instead, instruct users to run the install.sh script for installation:

1
2
3
4
5
6
7
8
9
10
11
12
13
LIBS = -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2_gfx -I./
LOCALS = item.cpp shapes.cpp
TAGS = -Wall -Os
GAMENAME = MyGame
BUILD = res/plugins/

all: $(GAMENAME)

$(GAMENAME): $(LOCALS)
        g++ $(TAGS) $(LOCALS) $(LIBS) -o $(GAMENAME) -I./

clean:
        rm -f $(GAMENAME)

Now users can build the project by running make and install it by running ./install.sh. This approach is more efficient and eliminates the need for the separate "paths" program.
Topic archived. No new replies allowed.