Creating an Easily Distributable Executable File

Hey guys,

I am looking for advice for when it comes to distributing a compiled SDL file (currently on a Mac using Emacs, but also looking for info on Windows).

At the end of competing in a GameJam I post my compiled SDL game for all other participants to open, play, and rate. The issue comes in the distribution and opening of the file itself. Once compiled, the file opens and runs as expected on my machine, but this is only because it has all the dependencies installed (SDL2, SDL2_image, SDL2_mixer, SDL2_ttf). Any other person who chooses to download the file and play will not have these dependencies installed, as they not included in the compiled file.

When opening the file on a Mac with prior no installation of SDL (e.g. another participant in the GameJam) an error will appear as:
dyld: Library not loaded: /usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib
Referenced from: /Users/name/Downloads/FileName
Reason: image not found
Abort trap: 6

Or in Linux:
bash: ./FileName: cannot execute binary file: Exec format error

This becomes an issue, as I am willing to believe people are not willing to go the extent of installing HomeBrew, and then dependency individually before they are able to open the file.

Correct me if I am wrong, but with Windows I believe I could place the .dll files inside the same folder as the .exe, and this will run the file as a whole?

If anyone can point in the right direction of how I can compile my file into an executable that does not require numerous other installations, or how easiest to make the file accessible to others, or if I’ve got completely the wrong idea let me know. Any help would be great.

I appreciate any responses I will receive. Thanks.

For Mac OS I distribute a self-contained application bundle as a disk image (.dmg) file. This has all the dependencies (e.g. SDL frameworks) embedded. For Windows I distribute a .zip file containing my app and any required DLLs, which just has to be extracted somewhere.

In both cases I wrote a simple script to create the required file.

For Windows I use InnoSetup to create an installer .exe file. It’s very easy to use and is free.

http://www.jrsoftware.org/isinfo.php

For Windows, there’s also NSIS, also free: https://sourceforge.net/projects/nsis/

Rpath or static linkage also an option. Think you could fiddle you game in a homebrew env also. Github releases, having multiple cross complied binaries with libs. Well runtime libs for mac and win are on the sdl page.

Thank you for the reply rtrussell, it has been very helpful. Before I attempt this could I just ask you to clarify a few points regarding distribution on Mac OS.

Would you care to give more detail on how you have embedded the frameworks? When you include the frameworks are you simply including the framework for each dependency (e.g. the SDL2_image.framework for Mac OS X that is contained within the runtime(?) binary .dmg download from https://www.libsdl.org/projects/SDL_image/) in the root folder containing the executable?

I have put the .dlls and the app inside a .dmg, opened it, but still received the same error message of:

dyld: Library not loaded: /usr/local/opt/sdl2/lib/libSDL2-2.0.0.dylib

But this time of course the error message reference path is different:

Referenced from: /Volumes/Disk Image/AppName
Reason: image not found

Do you have to make any changes to your make file in order for this to work (perhaps specifying the paths to these frameworks within your make file?)

Would it be possible for you to post an example of the simple script you have written to create the required file?

Thanks again for the reply.

Thanks for the info Sean & Ant - I’m currently in the process of building for Windows and am making progress. Will get back to you once I’ve worked it all out.

1 Like

Excuse my ignorance - when you refer to rpath you are talking about stating the path of which the compiler searches for libraries? So in reference to the error I posted previously in my reply to rtrussell, in the make file I could put

LDFLAGS="-Wl,-rpath,…/Disk Image/AppName"

and this would specify to the compiler where exactly to locate SDL_image, and the other dependencies?

https://en.m.wikipedia.org/wiki/Rpath =)
Kinda, yes. The rpath overrules the ld path.
Think I would provide the libs with the exe. Like it’s often done in books covering sdl. I tried to build a crossplatform premake script but I failed on mac, well I am stuck there. Not trying to finish that atm. Even so I like the idea that premake generates projects files for several IDE’s. I know it isn’t the same problem but it’s related cause I was struggling with framework paths.
Think docker is another solution, never tried that.

I don’t think just using …/Disk Image/etc will work.
See this article for how rpath is used on Linux and Mac http://jorgen.tjer.no/post/2014/05/20/dt-rpath-ld-and-at-rpath-dyld/
Note especially the special variables ($ORIGIN on Linux, @@executable_path on Mac) needed for relative paths.

The entire script would be too specific to my application to be useful, but the section relevant to copying the frameworks is as follows:

rm -R BBCBasic.app
mkdir BBCBasic.app
mkdir BBCBasic.app/Contents
mkdir BBCBasic.app/Contents/Frameworks
mkdir BBCBasic.app/Contents/Frameworks/SDL2.framework
mkdir BBCBasic.app/Contents/Frameworks/SDL2_ttf.framework
mkdir BBCBasic.app/Contents/Frameworks/SDL2_net.framework
mkdir BBCBasic.app/Contents/MacOS
mkdir BBCBasic.app/Contents/Resources
mkdir BBCBasic.app/Contents/Resources/lib
mkdir BBCBasic.app/Contents/Resources/examples
cp -R /Library/Frameworks/SDL2.framework/* BBCBasic.app/Contents/Frameworks/SDL2.framework/
cp -R /Library/Frameworks/SDL2_ttf.framework/* BBCBasic.app/Contents/Frameworks/SDL2_ttf.framework/
cp -R /Library/Frameworks/SDL2_net.framework/* BBCBasic.app/Contents/Frameworks/SDL2_net.framework/

I am using Xcode rather than a makefile.

This is actually a really tedious topic that has tons of little items
and details… something I have spent an unfortunate chunk of my
professional career dealing with. With cross-platform, languages and
libraries are easily portable, but build systems and distribution
rules/conventions (and now codesigning) are a real pain.

I don’t have time to go into everything, but a brief overview:

For dynamic libraries:

  • Windows: Put your .dll’s in the same directory as your .exe. Be
    aware that if you linked to a C or C++ runtime, you are also
    responsible for getting those to your end users, either by also
    copying those .dlls into the same directory as the .exe or in the case
    of Microsoft’s VS, hook into and ship the redistributable installer
    for the C++ components. SDL does not by default link to the C standard
    library on Windows, but if any of your own code or dependencies call
    things like malloc or new, then you will need it.

  • ELF/Linux: There is a mechanism called RPATH $ORIGIN which lets you
    specify relative paths from your executable to where the .so’s are
    located. You need to be very careful about shipping binaries on Linux
    because even the foundational stuff like glibc and the C++ standard
    libraries don’t really focus on keeping the ABI stable. If you are
    serious about shipping Linux binaries, you should build inside
    Steam-Runtime (provided by Valve on Github), which gives you your best
    shot of working on most distros.

  • Mac: There are two variants of dynamic libraries on Mac, .dylib and
    .framework. Frameworks are basically a standardized packaged bundle
    that include a .dylib (without suffix) and also any related assets
    that go with the library (e.g. header files, image files, localization
    strings, nib files). Apple tooling tends to favor .frameworks so there
    are advantages to using them even if you don’t have any assets you
    need to go with your library. So you will notice that the official SDL
    binary for Mac is a .framework bundle.

For shipping apps, your application also has an asset bundle like a
framework. Again, there is a standardized layout, and it includes
different sections for executables, frameworks, dylibs, PlugIns,
assets, etc.). Following standard convention, you want to to put all
your .frameworks in .app/Contents/Frameworks. Finally, Apple has a
mechanism similar to the RPATH $ORIGIN, except it is divided into two
halves. You build the libraries with an anchor and relative path (e.g.
@rpath), and then when you build your app, you specify the paths that
the app will search (e.g. -rpath @executable_path/…/Frameworks). I
believe the SDL .frameworks are already built with the first half
using @rpath. So your app just needs to do the second part.

iOS: Similar to Mac, but .dylibs don’t seem to be supported by Xcode
for iOS at all. So you pretty much have to use .frameworks. However,
the Xcode iOS tooling is still utter crap for 3rd-party libraries.
Because iOS needs both device and simulator binaries, your build
breaks when you switch targets. Xcode doesn’t really offer good
mechanisms for 3rd party libraries, so the easiest thing has been to
build a fat binary with all architectures. But the problem is when you
ship a binary, Xcode won’t strip out the simulator binaries in dynamic
libraries. Because of this problem, and the historical fact that iOS
disallowed dynamic libraries until a few years ago, static libraries
are easier, and how the SDL Xcode project is setup.

Android: You must NOT use SONAME versioning. All .so files must be
bundled with your .apk. The standard build process will put them in a
special place and on first launch, will extract them out to a special
area on disk so they can be used. (This path is considered private
API.) You then must load each library (dependency order matters) in
Java using System.loadLibrary.

There are also a ton of rules for bundling assets (images, sounds,
etc) for each platform.

Anyway, I hope this is helpful and at least gets you on the right path.

Also, I want to mention Blurrr SDK, the SDL based SDK I’m currently
developing. One major thing Blurrr provides is it implements all these
rules into its build system so you don’t have to get bogged down with
all these details and you can just focus on your app. You just list
your files in a pre-laidout CMake-based file provided by the SDK, and
you can build a binary that is completely self-contained and
ready-to-distribute.

https://blurrrsdk.com

Thanks,
Eric

2 Likes