Releasing SDL-binary app for Linux?

Hello!

I have been wondering about how to release
an SDL-game for Linux as a binary distribution?
(It seems that BillyTheKid will be released
for Linux now :slight_smile:

It seems that I can run the game as just a
plain binary file without any libraries -
but distributing that would be violating
LGPL - right?

So I would like to know how to make it work
with shared libraries and how I
distribute and install that?

Cheers–
http://www.HardcoreProcessing.com

I have been wondering about how to release
an SDL-game for Linux as a binary distribution?
(It seems that BillyTheKid will be released
for Linux now :slight_smile:

Very cool.

It seems that I can run the game as just a
plain binary file without any libraries -
but distributing that would be violating
LGPL - right?

Right. In general, the best way to do this is to distribute your game
with a particular dynamically loaded version of SDL, and provide the
source to that version on your web page. That way people can make changes
to SDL and your game benefits.

i.e. link with the standard libSDL.a that is built when you build SDL,
and put the dynamic libraries in, say, a ‘lib’ subdirectory of your
game installation. Then, when you initialize SDL, specify where the
dynamic libraries are:

main(int argc, char argv[])
{
/
Determine the runtime path, maybe from argv[0] */

/* Initialize SDL */
SDL_SetLibraryPath("<runtime>/lib");
if ( SDL_Init(...) < 0 ) {
	error message based on SDL_GetError();
	exit(1);
}
atexit(SDL_Quit);

/* Continue loading... */

}

That way your game doesn’t get confused by other versions of SDL installed,
and you still comply with LGPL.

I’ll be happy to post code to determine your runtime path from argv[0],
as soon as we get all the bugs out of it. :slight_smile:

-Sam Lantinga				(slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
“Any sufficiently advanced bug is indistinguishable from a feature”
– Rich Kulawiec

Sam Lantinga wrote:

Right. In general, the best way to do this is to distribute your game
with a particular dynamically loaded version of SDL, and provide the
source to that version on your web page. That way people can make changes
to SDL and your game benefits.

i.e. link with the standard libSDL.a that is built when you build SDL,
and put the dynamic libraries in, say, a ‘lib’ subdirectory of your
game installation. Then, when you initialize SDL, specify where the
dynamic libraries are:

main(int argc, char argv[])
{
/
Determine the runtime path, maybe from argv[0] */

    /* Initialize SDL */
    SDL_SetLibraryPath("<runtime>/lib");
    if ( SDL_Init(...) < 0 ) {
            error message based on SDL_GetError();
            exit(1);
    }
    atexit(SDL_Quit);

    /* Continue loading... */

}

That way your game doesn’t get confused by other versions of SDL installed,
and you still comply with LGPL.

I’ll be happy to post code to determine your runtime path from argv[0],
as soon as we get all the bugs out of it. :slight_smile:

Cool! Thanks! If SDL_SetLibraryPath understands “./lib” shouldn’t
that be fine?

Cheers–
http://www.HardcoreProcessing.com

ANOQ of the Sun wrote:

Cool! Thanks! If SDL_SetLibraryPath understands “./lib” shouldn’t
that be fine?

Oh, and I’m using SDL0.9.9 which hasn’t got
the SDL_SetLibraryPath functions, and I don’t
dare to move to a new version - I’ve got
exams at 30th of June and a new deadline at
1st of July :slight_smile:

I’ll just rip off that function from
a newer version…

Cheers–
http://www.HardcoreProcessing.com

ANOQ of the Sun wrote:

Cool! Thanks! If SDL_SetLibraryPath understands “./lib” shouldn’t
that be fine?

People may not be running your game from the run directory.
They may have placed the directory in their path, or be invoking it
with a full pathname.

Oh, and I’m using SDL0.9.9 which hasn’t got
the SDL_SetLibraryPath functions, and I don’t
dare to move to a new version - I’ve got
exams at 30th of June and a new deadline at
1st of July :slight_smile:

The new version is very stable, and has very little changed in the API.
The only significant change is the keyboard input supports UNICODE input,
so SDL_SymToASCII() is gone, and replaced by SDL_EnableUNICODE() and the
unicode member of the keysym structure.

I’ll just rip off that function from
a newer version…

I’d recommend using a newer version - it should mostly be just a recompile.

-Sam Lantinga				(slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
“Any sufficiently advanced bug is indistinguishable from a feature”
– Rich Kulawiec

Sam Lantinga wrote:

People may not be running your game from the run directory.
They may have placed the directory in their path, or be invoking it
with a full pathname.

OK, good points… can SDL_SetLibraryPath search in
multiple directories then? The game should most
likely be distributed as a tgz file and should
be “ready to run” from where it’s unpacked.
I also think I will need to know the path where
the game has been run from, as you mentioned.
If you can tell me how to do that I will be very
happy :slight_smile:

I’d recommend using a newer version - it should mostly be just a recompile.

OK, thanks - I’ll wait for a week then so that I’ve got
plenty of time :slight_smile:

Cheers–
http://www.HardcoreProcessing.com

ANOQ of the Sun wrote:

OK, good points… can SDL_SetLibraryPath search in
multiple directories then? The game should most
likely be distributed as a tgz file and should
be “ready to run” from where it’s unpacked.
I also think I will need to know the path where
the game has been run from, as you mentioned.
If you can tell me how to do that I will be very
happy :slight_smile:
Some solutions:

  1. you can scan argv[0]
    There are few possible “value types”:
  • argv[0] == "/some/absolute/path/to/your_binary"
    that’s tricky. Just take “/some/absolute/path/to”
  • argv[0] == “./your_binary”
    (running from its directory)
  • argv[0] == "your_binary"
    This means problems. It may occur when path to your binary is in PATH env.
    variable. So you must scan PATH for all paths and check each path for presence
    of your_binary

Approach 1) maybe cause problems when user creates a symlink to your_binary.
(E.g. /usr/local/bin/yb --> /some/absolute/path/to/your_binary) Then he may run
"yb" command and your path detection will fail.

  1. So it would probably be better to create a simple shell script:

#!/bin/sh
MY_APP_DIR=/some/absolute/path/to
cd MY_APP_DIR
./your_binary

and launch the game ONLY using this script. Then your_binary is always called
from within application’s directory. AFAIK this approach is used by many
programs that are distributed only as binaries.

  1. or tell the users they must always run it from app’s directory :slight_smile:

bye
Vasek

Vaclav Slavik wrote:

  1. So it would probably be better to create a simple shell script:

#!/bin/sh
MY_APP_DIR=/some/absolute/path/to
cd MY_APP_DIR
./your_binary

and launch the game ONLY using this script. Then your_binary is always called
from within application’s directory. AFAIK this approach is used by many
programs that are distributed only as binaries.

With tar.gz I won’t even know where MY_APP_DIR is :{

But thanks - I might think of something…

Cheers–
http://www.HardcoreProcessing.com

ANOQ of the Sun wrote:

Vaclav Slavik wrote:

  1. So it would probably be better to create a simple shell script:

#!/bin/sh
MY_APP_DIR=/some/absolute/path/to
cd MY_APP_DIR
./your_binary

and launch the game ONLY using this script. Then your_binary is always called
from within application’s directory. AFAIK this approach is used by many
programs that are distributed only as binaries.

With tar.gz I won’t even know where MY_APP_DIR is :{

Yes. But then there is no way except always launching the program from its
directory…

ANOQ of the Sun wrote:

Vaclav Slavik wrote:

  1. So it would probably be better to create a simple shell script:

#!/bin/sh
MY_APP_DIR=/some/absolute/path/to
cd MY_APP_DIR
./your_binary

and launch the game ONLY using this script. Then your_binary is always called
from within application’s directory. AFAIK this approach is used by many
programs that are distributed only as binaries.

With tar.gz I won’t even know where MY_APP_DIR is :{

Yes. But then there is no way except always launching the program from its
directory…

Nope. I decided to implement all the mentioned ways.

  1. Create a list with default paths…

    • /usr/local/share/app_name
    • /usr/share/app_name …
    • …/share/app_name
    • ./
      Add to this list the args[0] argument without the “my_binary”-string
      try to find the data in one of those paths…
  2. Parse the command-line arguments… for example
    my_app -d=/my/path/to/app
    if the user wants to start the app from some other directory
    he has to specify this option
    if the path is not found then help appears:
    $> my_app
    ERROR: Datapath not found!
    try my_app -d=

What do you think?

cu
Manuel

Manuel Klimek wrote:

Nope. I decided to implement all the mentioned ways.

  1. Create a list with default paths…

    • /usr/local/share/app_name
    • /usr/share/app_name …
    • …/share/app_name
    • ./
      Add to this list the args[0] argument without the “my_binary”-string
      try to find the data in one of those paths…
  2. Parse the command-line arguments… for example
    my_app -d=/my/path/to/app
    if the user wants to start the app from some other directory
    he has to specify this option
    if the path is not found then help appears:
    $> my_app
    ERROR: Datapath not found!
    try my_app -d=

What do you think?

Neat! :slight_smile:
Of course this is the way to do it :slight_smile:

Cheers–
http://www.HardcoreProcessing.com

“warren” == Warren Downs writes:

warren> The remainder of the script should strip off the program name
warren> (there’s a standard utility to do this, but I can’t remember
warren> the name. Anyone else?).

dirname

-Mat

Why not just:

Create a script which is run as the main binary for your program. The script
contains:

#!/bin/sh

MYPATH=type -path $0 # Where were we run from?
RELATIVE=echo $MYPATH | cut -b 1-1
if [ “$RELATIVE” = “.” ]; then
MYPATH=pwd/echo $MYPATH | cut -b 3-
fi

Now, MYPATH contains the absolute path we were run from.

The remainder of the script should strip off the program name (there’s a
standard utility to do this, but I can’t remember the name. Anyone else?).
Then, use that path, plus the name of your executable, to run the executable.
You can pass that path plus the data/library path, etc., to the executable as a
parameter.

Hope this helps,

Warren E. Downs
Systems Engineer

______________________________ Reply Separator _________________________________Subject: Re: [SDL] Releasing SDL-binary app for Linux?
Author: at internet-mail
Date: 6/25/99 12:46 PM

ANOQ of the Sun wrote:

Vaclav Slavik wrote:

  1. So it would probably be better to create a simple shell script:

#!/bin/sh
MY_APP_DIR=/some/absolute/path/to
cd MY_APP_DIR
./your_binary

and launch the game ONLY using this script. Then your_binary is always
called

from within application’s directory. AFAIK this approach is used by many
programs that are distributed only as binaries.

With tar.gz I won’t even know where MY_APP_DIR is :{

Yes. But then there is no way except always launching the program from its
directory…

Nope. I decided to implement all the mentioned ways.

  1. Create a list with default paths…

    • /usr/local/share/app_name
    • /usr/share/app_name …
    • …/share/app_name
    • ./
      Add to this list the args[0] argument without the “my_binary”-string
      try to find the data in one of those paths…
  2. Parse the command-line arguments… for example
    my_app -d=/my/path/to/app
    if the user wants to start the app from some other directory
    he has to specify this option
    if the path is not found then help appears:
    $> my_app
    ERROR: Datapath not found!
    try my_app -d=

What do you think?

cu
Manuel

Thanks…

You could also pass the lib/data paths as environment variables. In that case,
the final script would be:

---- cut here ----
#!/bin/sh

MYPATH=type -path $0
RELATIVE=echo $MYPATH | cut -b 1-1
if [ “$RELATIVE” = “.” ]; then
MYPATH=pwd/echo $MYPATH | cut -b 3-
fi

MYPROG=dirname $MYPATH/myprog
export MYLIB=dirname $MYPATH/lib
export MYDATA=dirname $MYPATH/data
$MYPROG
---- end here ----

Btw, there’s also a utility that returns the final path element (a complement to
dirname). Unfortunately, I can’t remember it’s name either. I’d have to look
at one of my books at home…

Warren
______________________________ Reply Separator _________________________________Subject: Re: Re[2]: [SDL] Releasing SDL-binary app for Linux?
Author: at internet-mail
Date: 6/25/99 2:16 PM

“warren” == Warren Downs writes:

warren> The remainder of the script should strip off the program name
warren> (there’s a standard utility to do this, but I can’t remember
warren> the name. Anyone else?).

dirname

-Mat

basename, I believe.On Fri, 25 Jun 1999, Warren Downs wrote:

Btw, there’s also a utility that returns the final path element (a complement to
dirname). Unfortunately, I can’t remember it’s name either. I’d have to look
at one of my books at home…

Warren

That’s it. Strangely, RedHat puts basename in /bin, but dirname in /usr/bin.
Seems like they should be in the same place, since they provide complementary
functions. (That’s why I couldn’t find basename when I looked for name).

Warren

______________________________ Reply Separator _________________________________Subject: Re: Re[4]: [SDL] Releasing SDL-binary app for Linux?
Author: at internet-mail
Date: 6/25/99 11:32 AM

basename, I believe.

On Fri, 25 Jun 1999, Warren Downs wrote:

Btw, there’s also a utility that returns the final path element (a complement
to
dirname). Unfortunately, I can’t remember it’s name either. I’d have to look

at one of my books at home…

Warren

Hmm, a script is a nice thingie, but I thought you wanted to
program system-independent…

cu
Manuel>

Thanks…

You could also pass the lib/data paths as environment variables. In that case,
the final script would be:

---- cut here ----
#!/bin/sh

MYPATH=type -path $0
RELATIVE=echo $MYPATH | cut -b 1-1
if [ “$RELATIVE” = “.” ]; then
MYPATH=pwd/echo $MYPATH | cut -b 3-
fi

MYPROG=dirname $MYPATH/myprog
export MYLIB=dirname $MYPATH/lib
export MYDATA=dirname $MYPATH/data
$MYPROG
---- end here ----

Btw, there’s also a utility that returns the final path element (a complement to
dirname). Unfortunately, I can’t remember it’s name either. I’d have to look
at one of my books at home…

Warren
______________________________ Reply Separator _________________________________
Subject: Re: Re[2]: [SDL] Releasing SDL-binary app for Linux?
Author: at internet-mail
Date: 6/25/99 2:16 PM

“warren” == Warren Downs writes:

warren> The remainder of the script should strip off the program name
warren> (there’s a standard utility to do this, but I can’t remember
warren> the name. Anyone else?).

dirname

-Mat

This is the code we used in CivCTP.
It is Linux specific, and has a subtle bug for which I will post a fix on
Monday.

Enjoy! :slight_smile:

/*
This function gets the directory containing the running program.
argv0 - the 0’th argument to the program
runpath - the buffer for the final run path
runpathlen - the size of the buffer for the output
Warning: This function has lots of buffer overflows.
*/
char *loki_getrundirectory(char *argv0, char *runpath, int runpathlen)
{
char temppath[MAXPATHLEN];
char fullpath[MAXPATHLEN];
char *spot;
struct stat sb;

strcpy(temppath, argv0);  /* If this overflows, it's your own fault :) */
if ( strrchr(temppath, '/') == NULL ) {
    char *path = getenv("PATH");
    while ( path ) {
        char *PATHspot = strchr(path, ':');
        if ( PATHspot ) {
            *PATHspot = '\0';
        }
        if ( (!PATHspot && *path) || (PATHspot > (path+1)) ) {
            if ( (*path == '~') && getenv("HOME") ) {
                sprintf(temppath, "%s/%s/%s", getenv("HOME"),path+1,argv0);
            } else {
                sprintf(temppath, "%s/%s", path, argv0);
            }
        } else {
            sprintf(temppath, "./%s", argv0);
        }
        path = PATHspot+1;
        if ( (access(temppath, X_OK) == 0) &&
             (stat(temppath, &sb) == 0) && S_ISREG(sb.st_mode) ) {
            path = NULL;
        }
        if ( ! PATHspot ) {
            /* At the end of PATH, and we haven't found our program? */
            strcpy(temppath, argv0);
            path = NULL;
        } else {
            *PATHspot = ':';
        }
    }
}

/* Now canonicalize it to a full pathname and return directory portion */
if ( realpath(temppath, fullpath) ) {
    /* There should always be '/' in the path */
    *(strrchr(fullpath, '/')) = '\0';
    if ( strlen(fullpath) < runpathlen ) {
        strcpy(runpath, fullpath);
    } else {
        runpath = NULL;
    }
} else {
    runpath = NULL;
}
return(runpath);

}

#ifdef __TEST_MAIN
int main(int argc, char *argv[])
{
printf(“Old pathname: %s\n”, argv[1]);
printf(“New pathname: %s\n”, loki_canonical_path(argv[1]));
}
#endif

I think something like this should go into the FAQ.

It should be made cross-platform first. :slight_smile:

-Sam Lantinga				(slouken at devolution.com)

Lead Programmer, Loki Entertainment Software–
“Any sufficiently advanced bug is indistinguishable from a feature”
– Rich Kulawiec

Nope. I decided to implement all the mentioned ways.

  1. Create a list with default paths…

    • /usr/local/share/app_name
    • /usr/share/app_name …
    • …/share/app_name
    • ./
      Add to this list the args[0] argument without the “my_binary”-string
      try to find the data in one of those paths…
  2. Parse the command-line arguments… for example
    my_app -d=/my/path/to/app
    if the user wants to start the app from some other directory
    he has to specify this option
    if the path is not found then help appears:
    $> my_app
    ERROR: Datapath not found!
    try my_app -d=

Neat! :slight_smile:
Of course this is the way to do it :slight_smile:

I think something like this should go into the FAQ.