SFML community forums

General => General discussions => Topic started by: zmertens on February 07, 2015, 06:43:03 am

Title: distributing SFML projects on Linux (binaries)
Post by: zmertens on February 07, 2015, 06:43:03 am
I just started really using Linux (Ubuntu) a couple months ago and I was wondering how you guys distribute a binary on Linux (so excluding CMake or source files which I realize is the preferred Linux way). The context for this situation is if I just wanted somebody to be able to play my game right away (like on itch.io). Could I just have the SFML .so files adjacent to the binary similar to .dlls on Windows? I looked at static linking but I saw some posts on Stack Overflow which suggested this might be a bad thing to do.

Anyone comments or tips would be awesome.
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Mario on February 07, 2015, 10:58:52 am
You could put the library files next to your binary but they won't be used unless you set LD_LIBRARY_PATH.

So you could write a small shell script to launch your game or create your own bootstrap executable not requiring any other dependencies, which will set LD_LIBRARY_PATH to the current directory and then start the actual game.
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Jesper Juhl on February 07, 2015, 04:46:09 pm
You can do it a lot simpler than that by using the linkers -rpath option and $ORIGIN to set the path to the libraries to be relative to the location of the  executable.

Read these links:

https://enchildfone.wordpress.com/2010/03/23/a-description-of-rpath-origin-ld_library_path-and-portable-linux-binaries/

https://www.technovelty.org/linux/exploring-origin.html

http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

http://man7.org/linux/man-pages/man8/ld.so.8.html
Title: Re: distributing SFML projects on Linux (binaries)
Post by: MorleyDev on February 07, 2015, 05:26:10 pm
Not sure how good a practice this is, probably a terrible one, but at the moment when I'm doing C++ stuff then as a part of my build process, I have CMake copy some launch scripts to the root install directory. The launch script for linux looks something like this:
Code: [Select]
#!/bin/sh

LD_LIBRARY_PATH=$(dirname "$(readlink -f "$0")")/lib exec $(dirname "$(readlink -f "$0")")/bin/engine

Basically it adds the lib folder to the LD_LIBRARY_PATH (and works regardless of where the script is ran from) and then runs the engine executable in the bin folder.

You can actually kinda fake this behaviour for windows too if needed. The equivalent script on windows looks like:
Code: [Select]
@echo off
setlocal
PATH=%PATH%;%~dp0\lib
"%~dp0\bin\engine.exe"
endlocal
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Mario on February 07, 2015, 10:33:51 pm
For Windows you don't need to do that. the executable's own path is always the first lookup location (even before other entries in the PATH environment variable; and considering that dynamic libraries should be in the bin path, not some lib dir).
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Tenry on February 13, 2015, 02:47:57 pm
Some linux distros already provide SFML in the official repositories (such as Linux Mint 17.1, having SFML 2.1), so I would like to distribute my binary with its game data in an archive (e.g. tar.gz) and tell the user he has to install SFML 2.1 via package manager. Unfortunately, some distros don't have SFML or only version 1.6 in the official repository. So, I should rather provide the SFML binaries with the archive? I'm not sure, if that is the best design (of not working with system dependent packages like rpm or deb). Any ideas?
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Jesper Juhl on February 13, 2015, 03:00:28 pm
Personally I would do the following if I wanted to distribute as a .tar.gz :

Package my application so that when you extract app.tar.gz you'd get an "app/" directory with 3 subdirectories; "lib/", "bin/" and "data/".
My applications binary(s) would go in "app/bin/", SFML and other libraries my app depends on would go in "app/lib/" and other stuff like music files, graphics etc would go in "app/data/". If I had configuration files I'd probably put them in a "app/etc/" directory.

When building my app I would make sure to set my apps path to the libraries it needs to be relative to the location of the executable, using the -rpath option for the linker along with $ORIGIN, so that my app would look for its libraries in "../lib/" independently of where it is located.

This way, when the user extracts the tarball they can put the toplevel "app/" directory wherever they please. Locations like "/opt/app/", "/usr/local/app/" and "~/app/" will all work equally well - as will symlinks to the executables that the user may choose to create.

At runtime when the app needs to find its own files in "data/" & "etc/" it can just read the  "/proc/self/exe" symlink to find out where it is located, strip the executable name from that path and add "../data/" and it then has a path to its data files. This works regardless of where the user moves the app to.
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Tenry on February 13, 2015, 03:38:27 pm
At runtime when the app needs to find its own files in "data/" & "etc/" it can just read the  "/proc/self/exe" symlink to find out where it is located, strip the executable name from that path and add "../data/" and it then has a path to its data files. This works regardless of where the user moves the app to.
Wouldn't it work using the path passed with the first argument to main (argv[0]) as well?

There should be tutorials on the wiki about best practices distributing SFML apps for Windows, Linux and Mac (at least, I can't see any such tutorial yet).
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Jesper Juhl on February 13, 2015, 03:49:20 pm
Using argv[0] is not reliable. It could be set to anything by a program launching your app. The fact that it is often set to the path to (or just name of) your executable is purely a convention and if you have symlinks or hardlinks in play that will also mess you up.
On the other hand, /proc/self/exe is reliable.
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Jesper Juhl on February 13, 2015, 03:52:05 pm
This link may also be of some use/interest: http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Tenry on February 13, 2015, 03:57:25 pm
This link may also be of some use/interest: http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe (http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe)
That's interesting and useful, thanks! :)
Title: Re: distributing SFML projects on Linux (binaries)
Post by: MorleyDev on February 13, 2015, 08:19:13 pm
If you're using CMake as a build system, there is also support for configuring your projects like Jesper suggests via setting the RPATH: http://www.cmake.org/Wiki/CMake_RPATH_handling
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Tenry on February 14, 2015, 10:52:49 am
Hm, if you suggest to distribute the SFML lib (.so) with the app anyway, why not linking the app statically with SFML then? That would even eliminate code, that is never called by the app.
Title: Re: distributing SFML projects on Linux (binaries)
Post by: zmertens on February 14, 2015, 11:24:09 pm
Hm, if you suggest to distribute the SFML lib (.so) with the app anyway, why not linking the app statically with SFML then? That would even eliminate code, that is never called by the app.

I was reading around the Web and I thought I came across some discussions that static linking on Linux wasn't preferred (although I can't remember the exact reasons - I think it was a StackOverflow discussion). I was hoping to get a second opinion and to see how long time Linux / SFML users would consider distributing their applications. I've been browsing Itch.io (http://itch.io) a lot recently and I want to distribute my project there. It seems that a lot of the projects uploaded there which support Linux use Unity which I think takes care of linking automatically  but I just was looking for a second opinion.

Also, thanks for all the excellent feedback and links, its been very helpful and educational.
Title: Re: distributing SFML projects on Linux (binaries)
Post by: Tenry on February 15, 2015, 01:41:47 am
I was reading around the Web and I thought I came across some discussions that static linking on Linux wasn't preferred (although I can't remember the exact reasons - I think it was a StackOverflow discussion).
As far, as I know, dynamic linking is preffered on Linux because it usually has a well managed package manager. For example, don't link your Linux app statically with OpenAL or FreeType, use the dynamic linking and let the package manager care about the dependencies. And, unlike Windows, on Linux having several versions of the same library for dynamic linking is quite good supported. However, what about less known/distributed libraries? I don't know.
Title: Re: distributing SFML projects on Linux (binaries)
Post by: FRex on February 15, 2015, 12:15:48 pm
First of all: Linus rants about shipping applications on Linux desktop:
https://www.youtube.com/watch?v=5PmHRSeA2c8&=6m

This is the divers app he is talking about (compare the download options for Mac, Windows and Linux users...): http://subsurface-divelog.org/download/



(In case you don't want to read through the rant, the quick help list is at the end).
(Also, this is a complex issue - I might be wrong at times).
(Also, I'm a bit biased talking about Lua and Red Hat based distros since I use Fedora and used CentOS for a short while and Lua is one of most interestingly problematic libs in terms of shipping stuff that I ran into so far).
Second: I rant about shipping applications on Linux desktop:

Basically: it's impossible to get 101% right.
You use dynamic libraries: bitness, ABI or missing libs get you.
You use static libraries and set the environment to use own .so: it's kind of OK actually... but it doesn't use the InfinitePowerOfDynamicLibraries(tm). And might be illegal without making your entire app LGPL along with it (OpenAL, libsndfile, etc.) :(


There is a bunch of fun problems with dlls (by that I mean dynamic libs, not the Windows .dll format itself, I know, the format is .so on Linux) on Linux:
1. ABI
2. Versions/'configurations'
3. Names
4. Missing stuff

Let me explain them all:
ABI is simple - ABIs change often between releases of less 'core' libs ie.: Lua 5.1 is not ABI compatible with 5.2, Fedora 20 ships 5.1 and links liblua.so to it, Fedora 21 does the same with 5.2 and 5.1 is now compatibility, RHEL and CentOS 6 and 7 ship 5.1 - have fun linking your app dynamically to liblua.so, it links to one of two incompatible libs depending on distro relase/version, and that is inside a single distro tree (RH), without even going into Debian, Arch, Suse or more exotic systems like Oralce Linux and so on. Of course this doesn't affect XCB, GL, libc, etc. (This - the change of what is behind the symbolic link - is more of an issue in compiling and runtime linking actually, compile time dynamic linking doesn't get affect by it, but it then gets affected by 3. possibly).

Versions/'configurations' - this is a bit more subtle (but even more dangerous). Libraries have build configs, SFML has almost none so yay. Worst is configs that violate ABI and that cut into feature set (SFML itself has 0 of that). Even if there is no ABI incompatibility you risk that your program will not work because some part of feature set is just missing/replaced with stubs.
Examples:
1. Fedora didn't enable Eliptic Curves in OpenSSL - patent issues. This broke (for example) BitCoin apps so you have to build yourself or add a special, unofficial repo to package manager that doesn't fear patent litgation and download your bitcoin app from there, it will pull in a completely separate OpenSSL lib binary built with EC in it, named differently. Problem solved - kind of - any app that comes to your system and thinks that normal OpenSSL has EC will break (I actually had this happen to me on certain experimental mail client app).
2. Lua again, it can be built with a lot of configuration options (none actually make sense for common usage IMO), LuaJit even more so (and here it makes sense, the 5.2 compat flag in particular).

Names - this is a bit connected to 2., like the issue of EC capable OpenSLL being named differently and no one knowing that. Basically - you have no guarantee what the dynamic lib will be named on the target system. Standard libs have obvious-as-hell names but the more rare ones might differ, and given that there is probably close to dozen or two 'popular' distros (and their versions, since versions can vary wildly) you might want to carter to, you are taking a big risk.

Missing stuff - simple, user might not have ability to install what you need easily: F20 has no Lua 5.2, F21 has no Lua 5.3, RHEL/CentOS 7 has no Lua 5.2 and OpenAL(!).
It probably IS possible after adding more repos to package managers (EPEL and nux for RHEL/CentOS, rpmfusion for Fedora, etc.) and by manual compilation but it's hard to require either of your user. Also, not everyone might want to install Mono (quite a big/convoluted lib..) or something just for your one app. We are going for the instant fun experience here... like there is on Windows (or with Unity...).


You mention Unity - it cheats around the problem with mix of static and dynamic and it's kind of good solution actually, what Unity built Linux binary is doing is:
1. Link everything statically  to the executable (you can find PhysicsSDK, Box2D and OpenSLL in it, possibly more).
2. Bring own libmono(!) and a bunch of managed libraries (these are 100% cross platform).
3. Link only bare minimum to your dynamic libs and your executable: libc, opengl, xcb, etc. that is sure to be ABI compatible.
4. Be 32 bit to not lock out 32 bit users (it forces 64 bit users to install 32 bit libraries of all the stuff from 3. I think... I have 32 bit system so I don't know) .

This is what I gathered from looking at binaries of just from 2 games on gamejolt so take it with a grain of salt...


So, given all these problems, incompatibilities, traps and possible missing stuff I made a set of rules I'd go by if I ever tried to ship a Linux binary.

0. Acknowledge that this is MY list, that it might be WRONG or INCOMPLETE since I'm not the Linux-Native-Apps-Guru-Of-All-Time.
1. Go 32 bit (or both) to not lock out 32 bit users, if you don't go both you will have to make 64 bit people install 32 bit version of few libs you rely on.
2. Link everything you legally and technically can statically.
3. Bring your own dlls for all else except sys libs and use a bash script to start your game with them.
4. Use just the most basic libs in the system - gl, xcb, libc, etc.
5. Bring all own scripts/managed libs (mono dlls, lua and python scripts, etc.) - don't trust that users will have them - they won't.

In terms of SFML: go 32 bit (or both), build it fully statically (except for the two dlls of audio), link it statically to your executable and bring your own dlls for OpenAL and libsndfile and launch via a bash/sh script that sets the environment variable for ld.