[SDL] Embed SDL.dll in the .exe
Sylvain Beucler
beuc at beuc.net
Thu Sep 27 12:54:18 PDT 2007
On Wed, Sep 26, 2007 at 03:57:30PM +0200, Sylvain Beucler wrote:
> On Wed, Sep 26, 2007 at 03:14:25PM +0200, Gerry JJ wrote:
> > Den Wed, 26 Sep 2007 12:02:28 +0200
> > skrev Sylvain Beucler <beuc at beuc.net>:
> > > I look for a kind of "partially static" compilation, as if SDL was
> > > part of my own code, but I don't have enough knowledge of GCC to know
> > > how that can be done.
> > >
> > > Do you know if that's possible?
> >
> > Yes, it's possible, you just have to be a bit more specific when
> > telling the linker what you want to do, since -static affects the
> > entire linking process and not just part of it like you want. The
> > linker has some options called -Bstatic and -Bdynamic that can be used
> > to do exactly what you want, and you can pass args to the linker with
> > gcc's -Wl arg, with commas in stead of spaces. So, just surround the
> > libraries you want to link statically with -Wl,-Bstatic and
> > -Wl,-Bdynamic:
> >
> > gcc stuff -Wl,-Bstatic -lSDL etc -Wl,-Bdynamic
> >
> > You can do this as many times as you want in a link. A -Wl,-Bdynamic
> > at the end ensures that gcc won't try to statically link system libs
> > and such. If you still get a dynamically linked SDL after this, you
> > probably just have to sort out the order of the link args (a request
> > for a lib in a dynamic part after that lib's already been statically
> > linked will pull it in dynamically as well if possible. If you've got
> > false dependencies interfering with your link, -Wl,--as-needed might
> > help (makes the target only depend on first-level dependencies)).
>
> Thanks, I'll dig more into those options.
>
> I'm also having a first clean build by simply adding -lwinmm - I
> thought that --static-libs would give me this kind of dependencies
> automatically :)
>
> i586-mingw32msvc-gcc -static joytest.c \
> `/usr/local/cross-tools/i386-mingw32msvc/bin/sdl-config --cflags --static-libs` \
> -lwinmm
OK, I managed to build the stand-alone executable.
I cross-compiled all SDL libraries manually because the binary
releases don't provide static libs. I also cross-compiled freetype2
for SDL_ttf. There was a couple libtool fixes to do on SDL_gfx as
well.
Then I just add to specific '-static' and '-lfreetype -lwinmm' to gcc.
No need to specfic 'disable-shared' for me when building the
libraries, using '-static' for my .exe takes care of using the static
libs appropriately.
Doing the same thing for GNU/Linux is quite more difficult, because
SDL's dependencies require dlopen(), which in turn requires a
non-static build, so we have to use the scary -Wl,-Bstatic and
-Wl,-Bdynamic options. Moreover, some versions of SDL conflicts with
X11 when compiled statically (SDL_x11dyn.o). And of course, GNU/Linux
has numerous backends which can make your dependencies list grow very
large!
Building a dynamic executable that includes SDL + its dependencies
*except X11* is easy enough though, once you listed the dependencies
and the matching distro packages.
I attach 2 files from my documentation for people interested in doing
the same thing for their project :)
http://git.sv.gnu.org/gitweb/?p=freedink.git;a=blob;f=doc/cross.txt
http://git.sv.gnu.org/gitweb/?p=freedink.git;a=blob;f=doc/static-build.txt
Thanks to the list for the tips :)
--
Sylvain
-------------- next part --------------
Statically compiling for GNU/Linux
==================================
Thread "[SDL] Embed SDL.dll in the .exe"
http://lists.libsdl.org/pipermail/sdl-libsdl.org/2007-September/062841.html
Distros compile libSDL with a number of backends (such as X11 and
AAlib for graphics, ALSA and OSS for sounds, etc.) which will trigger
a lot of dependencies.
You may need to statically compile against a manually-compiled libSDL
which fewer backends enabled.
Another solution may be to have SDL use relaytool (check
http://autopackage.org/docs/tutorials/glb-binport.html).
Technical note: maybe use -Wl,--as-needed, it's supposed to reduce the
number of NEEDED symbols (objdump -x src/freedink | grep NEEDED). The
SDL list says it "makes the target only depend on first-level
dependencies".
Compiling with the distro's SDL
===============================
Here's an attempt to list the minimum dependencies to statically
compile against Debian Etch's libsdl1.2-dev:
##
# Dynamic
##
# glibc-related, better keep them dynamic I think
-ldl # dlopen
-lpthreads # threads
# X11 - conflicts with SDL_x11dyn.o if statically
# compiled. Something to do with ./configure --enable-x11-shared ?
-lX11
##
# Static
##
# Maths
-lm
# AAlib text-mode graphics backend
aptitude install libaa1-dev
aptitude install libgpmg1-dev # mouse support
-laa -lgpm
# caca text-mode graphics backend
aptitude install libcaca-dev
aptitude install libslang2-dev
aptitude install libncurses5-dev
-lcaca -lslang -lncurses -lcucul
# Direct frame buffer graphics backend
aptitude install libdirectfb-dev
aptitude install libfusionsound-0.9-25
-ldirectfb -ldirect -lfusion
# SVGA graphics backend
aptitude install libsvga1-dev
-lvga
# ALSA sound backend
aptitude install libasound2-dev
-lasound
# aRts sound backend
aptitude install libarts1-dev
-lartsc
# ESD sound backend
aptitude install libesd0-dev
-lesd
# NAS sound backend
aptitude install libaudio-dev
-laudio
$ gcc -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT joytest.c \
-L/usr/lib -Wl,--as-needed -Wl,-Bstatic -lSDL -lcaca -lslang -laa \
-laudio -lesd -lartsc -lvga -ldirectfb -ldirect -lfusion -lcurses \
-lcucul -lasound -lgpm -lm -Wl,-Bdynamic -lX11 -ldl -lpthread -o \
joytest
# --as-needed doesn't seem useful here.
$ ls -lh joytest
-rwxr-xr-x 1 me me 2,5M 2007-09-26 22:24 joytest
$ strip joytest
$ ls -lh joytest
-rwxr-xr-x 1 me me 2,0M 2007-09-26 22:24 joytest
me at dmc:~/freedink/test/sdl$ ldd joytest
linux-gate.so.1 => (0xffffe000)
libX11.so.6 => /usr/lib/libX11.so.6 (0xb7ee2000)
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7ede000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7ecc000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7d9b000)
libXau.so.6 => /usr/lib/libXau.so.6 (0xb7d98000)
/lib/ld-linux.so.2 (0xb7fe8000)
libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0xb7d92000)
Here we still have a dynamic executable, with the usual glibc
issues. Compiling with apgcc from Apbuild (Autopackage) may help.
Compiling with a custom simpler SDL
===================================
We can try to recompile SDL ourself and get rid of the X11 conflicts,
allowing for a truly static executable:
$ cd SDL-1.2.12
# not sure if both options are mandatory:
$ ./configure --disable-x11-shared --disable-shared
$ make && make install
...
$ gcc -static -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT \
joytest.c -L/usr/local/lib -L/usr/lib -lSDL -laudio -lvga -ldirectfb \
-ldirect -lfusion -lm -lXrandr -lXrender -lX11 -lXau -lXdmcp \
-lXext -ldl -lpthread -o joytest
/usr/local/lib/libSDL.a(SDL_alsa_audio.o): In function `LoadALSALibrary':
./src/audio/alsa/SDL_alsa_audio.c:139: warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/libdirect.a(stream.o): In function `tcp_open':
(.text+0x891): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/libaudio.a(ConnSvr.o): In function `MakeTCPConnection':
/home/steve/debian/nas/nas-1.8/lib/audio/ConnSvr.c:981: warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/libX11.a(x11_trans.o): In function `_X11TransSocketINETConnect':
(.text+0x1da4): warning: Using 'getservbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
$ ls -lh joytest
-rwxr-xr-x 1 me me 4,4M 2007-09-26 23:52 joytest
$ strip joytest
$ ls -lh joytest
-rwxr-xr-x 1 me me 2,3M 2007-09-26 23:52 joytest
$ ldd joytest
not a dynamic executable
$ ./joytest
# Runs fine until I exit the app:
*** glibc detected *** double free or corruption (out): 0xb7ba4230 ***
Abandon
The resulting binary also crashes with a floating point exception
under Fedora 7 :/
Maybe it can work with a different SDL setup, namely one that wouldn't
use dlopen.
Something in-between works. The improvement over using the distro's
SDL is that X11 is now statically linked:
$ gcc -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT joytest.c \
-L/usr/local/lib -L/usr/lib -Wl,-Bstatic -lSDL -laudio -lvga \
-ldirectfb -ldirect -lfusion -lm -lXrandr -lXrender -lX11 -lXau \
-lXdmcp -lXext -o joytest -Wl,-Bdynamic -ldl -lpthread
$ ls -lh joytest
-rwxr-xr-x 1 me me 3,6M 2007-09-26 23:50 joytest
$ strip joytest
me at dmc:~/freedink/test/sdl$ ls -lh joytest
-rwxr-xr-x 1 me me 1,8M 2007-09-26 23:50 joytest
$ ldd joytest
linux-gate.so.1 => (0xffffe000)
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7f5a000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7f48000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7e17000)
/lib/ld-linux.so.2 (0xb7f78000)
Try switching from dlopen to relaytool
======================================
Left as exercise to the reader ;)
-------------- next part --------------
Cross-compilation
=================
# Install a cross-compiler version of GCC
aptitude install mingw32
# Prepare directory to store cross-compiled libraries
mkdir -p -m 775 /usr/local/cross-tools/i386-mingw32msvc
cd /usr/local/cross-tools
ln -s i386-mingw32msvc i386-mingw32
##
# Install precompiled SDL binaries
##
VERSION=1.2.12
# Cf. http://libsdl.org/download-1.2.php
wget http://libsdl.org/release/SDL-devel-$VERSION-mingw32.tar.gz
tar xzf SDL-devel-$VERSION-mingw32.tar.gz
mv SDL-$VERSION/* i386-mingw32msvc/
rmdir SDL-$VERSION
# Install precompiled SDL_mixer binaries
VERSION=1.2.8
wget http://libsdl.org/projects/SDL_mixer/release/SDL_mixer-devel-$VERSION-VC8.zip
unzip SDL_mixer-devel-$VERSION-VC8.zip
cp -r SDL_mixer-$VERSION/include/* i386-mingw32msvc/include/SDL/
cp -r SDL_mixer-$VERSION/lib/* i386-mingw32msvc/lib/
rm -rf SDL_mixer-$VERSION/
# Install precompiled SDL_mixer binaries
VERSION=2.0.9
wget http://libsdl.org/projects/SDL_ttf/release/SDL_ttf-devel-$VERSION-VC8.zip
unzip SDL_ttf-devel-$VERSION-VC8.zip
cp -r SDL_ttf-$VERSION/include/* i386-mingw32msvc/include/SDL/
cp -r SDL_ttf-$VERSION/lib/* i386-mingw32msvc/lib/
rm -rf SDL_ttf-$VERSION/
# Cross-compile SDL_gfx (no binaries available)
cd /usr/src
VERSION=2.0.16
wget http://www.ferzkopp.net/Software/SDL_gfx-2.0/SDL_gfx-$VERSION.tar.gz
tar xzf SDL_gfx-$VERSION.tar.gz
cd SDL_gfx-$VERSION
# Refresh and mark as DLL-compliant (patch sent)
rm -f acinclude.m4
sed -i -e 's/-version-info/-no-undefined -version-info/' Makefile.am
autoreconf --force --install --symlink
patch -p1 < /tmp/SDL_gfx-libtool.diff # see below
export SDL_CONFIG=/usr/local/cross-tools/i386-mingw32msvc/bin/sdl-config
./configure --host=i586-mingw32msvc --build=i686-pc-linux-gnu
make
make install
##
# Cross-compile FreeDink
##
cd ~/freedink/
mkdir cross
cd cross/
SDL_CONFIG=/usr/local/cross-tools/i386-mingw32msvc/bin/sdl-config \
../configure --host=i586-mingw32msvc --build=i686-pc-linux-gnu
make clean # just in case
make
make install-strip DESTDIR=/tmp/distribute/
Alternative: cross-compile yourself
===================================
Among others, necessary for static builds (not static libraries with
the official releases).
# SDL
VERSION=1.2.12
wget http://libsdl.org/release/SDL-$VERSION.tar.gz
tar xzf SDL-$VERSION.tar.gz
cd SDL-$VERSION
./configure --host=i586-mingw32msvc --build=i686-pc-linux-gnu
make
make install # /usr/local/cross-tools/i386-mingw32/ by default
# SDL_mixer
VERSION=1.2.8
wget http://libsdl.org/projects/SDL_mixer/release/SDL_mixer-$VERSION.tar.gz
tar xzf SDL_mixer-$VERSION.tar.gz
cd SDL_mixer-$VERSION
# Disable MP3 support (not needed in FreeDink and avoid a dependency)
SDL_CONFIG=/usr/local/cross-tools/i386-mingw32msvc/bin/sdl-config ./configure \
--host=i586-mingw32msvc --build=i686-pc-linux-gnu \
--disable-music-mp3
make
make install # /usr/local/cross-tools/i386-mingw32/ by default
# FreeType (SDL_ttf dependency)
VERSION=2.3.5
wget http://download.savannah.gnu.org/releases/freetype/freetype-$VERSION.tar.bz2
tar xjf freetype-$VERSION.tar.bz2
cd freetype-$VERSION
./configure --host=i586-mingw32msvc --build=i686-pc-linux-gnu --prefix=/usr/local/cross-tools/i386-mingw32msvc
make
make install
# SDL_ttf
VERSION=2.0.9
wget http://libsdl.org/projects/SDL_ttf/release/SDL_ttf-$VERSION.tar.gz
tar xzf SDL_ttf-$VERSION.tar.gz
cd SDL_ttf-$VERSION
SDL_CONFIG=/usr/local/cross-tools/i386-mingw32msvc/bin/sdl-config \
FREETYPE_CONFIG=/usr/local/cross-tools/i386-mingw32msvc/bin/freetype-config \
./configure --host=i586-mingw32msvc --build=i686-pc-linux-gnu
make
make install # /usr/local/cross-tools/i386-mingw32/ by default
Static build
============
I want to cross-compile statically, to provide a single .exe that
includes SDL and SDL_* :)
- You need to add -lwinmm
i586-mingw32msvc-gcc mousetest.c \
`/usr/local/cross-tools/i386-mingw32msvc/bin/sdl-config --cflags \
--static-libs` -lwinmm
- If you have some troubles with SDL_gfx which tries to use
__imp__SDL_setFramerate, you need a build system patch (see below) -
maybe it will make it to 2.0.17 ;)
- You need to specify -lfreetype, a dependency of SDL_ttf
You get a 1.1MB standalone stripped executable.
Now we need to integrate the additional library in our build system
and provide ./configure option to build statically (LIBS+="-lfreetype
-lwinmm", LDFLAGS+="-static")
diff -ru SDL_gfx-2.0.16/SDL_framerate.h SDL_gfx-2.0.16.beuc/SDL_framerate.h
--- SDL_gfx-2.0.16/SDL_framerate.h 2006-12-22 13:36:10.000000000 +0100
+++ SDL_gfx-2.0.16.beuc/SDL_framerate.h 2007-09-27 01:46:10.000000000 +0200
@@ -39,21 +39,24 @@
/* --------- Function prototypes */
#ifdef WIN32
-#ifdef BUILD_DLL
-#define DLLINTERFACE __declspec(dllexport)
-#else
-#define DLLINTERFACE __declspec(dllimport)
+# ifdef DLL_EXPORT
+# define SDL_FRAMERATE_SCOPE __declspec(dllexport)
+# else
+# ifdef LIBSDL_GFX_DLL_IMPORT
+# define SDL_FRAMERATE_SCOPE __declspec(dllimport)
+# endif
+# endif
#endif
-#else
-#define DLLINTERFACE
+#ifndef SDL_FRAMERATE_SCOPE
+# define SDL_FRAMERATE_SCOPE extern
#endif
/* Functions return 0 or value for sucess and -1 for error */
- DLLINTERFACE void SDL_initFramerate(FPSmanager * manager);
- DLLINTERFACE int SDL_setFramerate(FPSmanager * manager, int rate);
- DLLINTERFACE int SDL_getFramerate(FPSmanager * manager);
- DLLINTERFACE void SDL_framerateDelay(FPSmanager * manager);
+ SDL_FRAMERATE_SCOPE void SDL_initFramerate(FPSmanager * manager);
+ SDL_FRAMERATE_SCOPE int SDL_setFramerate(FPSmanager * manager, int rate);
+ SDL_FRAMERATE_SCOPE int SDL_getFramerate(FPSmanager * manager);
+ SDL_FRAMERATE_SCOPE void SDL_framerateDelay(FPSmanager * manager);
/* --- */
diff -ru SDL_gfx-2.0.16/SDL_rotozoom.h SDL_gfx-2.0.16.beuc/SDL_rotozoom.h
--- SDL_gfx-2.0.16/SDL_rotozoom.h 2006-12-22 13:36:10.000000000 +0100
+++ SDL_gfx-2.0.16.beuc/SDL_rotozoom.h 2007-09-27 01:45:58.000000000 +0200
@@ -45,13 +45,16 @@
/* ---- Prototypes */
#ifdef WIN32
-#ifdef BUILD_DLL
-#define DLLINTERFACE __declspec(dllexport)
-#else
-#define DLLINTERFACE __declspec(dllimport)
+# ifdef DLL_EXPORT
+# define SDL_ROTOZOOM_SCOPE __declspec(dllexport)
+# else
+# ifdef LIBSDL_GFX_DLL_IMPORT
+# define SDL_ROTOZOOM_SCOPE __declspec(dllimport)
+# endif
+# endif
#endif
-#else
-#define DLLINTERFACE
+#ifndef SDL_ROTOZOOM_SCOPE
+# define SDL_ROTOZOOM_SCOPE extern
#endif
/*
@@ -65,17 +68,17 @@
*/
- DLLINTERFACE SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth);
+ SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth);
- DLLINTERFACE SDL_Surface *rotozoomSurfaceXY
+ SDL_ROTOZOOM_SCOPE SDL_Surface *rotozoomSurfaceXY
(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth);
/* Returns the size of the target surface for a rotozoomSurface() call */
- DLLINTERFACE void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth,
+ SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth,
int *dstheight);
- DLLINTERFACE void rotozoomSurfaceSizeXY
+ SDL_ROTOZOOM_SCOPE void rotozoomSurfaceSizeXY
(int width, int height, double angle, double zoomx, double zoomy,
int *dstwidth, int *dstheight);
@@ -90,11 +93,11 @@
*/
- DLLINTERFACE SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth);
+ SDL_ROTOZOOM_SCOPE SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth);
/* Returns the size of the target surface for a zoomSurface() call */
- DLLINTERFACE void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
+ SDL_ROTOZOOM_SCOPE void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
/*
@@ -107,7 +110,7 @@
or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
*/
- DLLINTERFACE SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory);
+ SDL_ROTOZOOM_SCOPE SDL_Surface *shrinkSurface(SDL_Surface * src, int factorx, int factory);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
More information about the SDL
mailing list