How to statically compile an SDL game on Windows - windows

I have been trying to produce a statically linked "single binary" version of my game for windows. I want to link with sdl, sdl_image and sdl_mixer which in turn pull in a few support libraries. Unfortunately I haven't found a way to get them all to compile and link using cygwin/mingw/gcc. As far as I can tell all existing public versions are only shared libraries / dlls.
Please note that I'm not talking about licencing here. The source will be open thus the GPL/LGPLness of sdl is not relevant.

When compiling your project, you need to make just a couple changes to your makefile.
Instead of sdl-config --libs, use sdl-config --static-libs
Surround the use of the above-mentioned sdl-config --static-libs with -Wl,-Bstatic and -Wl,-Bdynamic. This tells GCC to force static linking, but only for the libraries specified between them.
If your makefile currently looks like:
SDLLIBS=`sdl-config --libs`
Change it to:
SDLLIBS=-Wl,-Bstatic `sdl-config --static-libs` -Wl,-Bdynamic
These are actually the same things you should do on Unix-like systems, but it usually doesn't cause as many errors on Unix-likes if you use the simpler -static flag to GCC, like it does on Windows.

Via this SDL mailing list post it seems that the sdl development tools ship with a sdl-config script that you can use with the --static-libs flag to determine what linker flags you need to use.

Environment: VMWare Virtual Machine with Windows 7 x64 and Equipment we Dev c + + build 7.4.2.569, complilador g+ + (tdm-1) 4.6.1
Once, SDL2-2.0.3 API installed as configuration Dev c ++ is not very clear what I've done as tradition requires command line.
The first problem is that Windows 7 appears to have changed the methodology and they go to his ball. Inventory. Ref. https://stackoverflow.com/users/464581/cheers-and-hth-alf
After the first hurdle, SDL_platform.h is that bad, it's down another, I do not remember where I downloaded, but the next does not work in the indicated version.
We must put SDL2.h ls in the directory of the executable.
D:\prg_desa\zsdl2>g++ bar.cpp main.cpp -o pepe1 -ID:\SDL2-2.0.3\i686-w64-mingw32\include\SDL2 -LD:\SDL2-2.0.3\i686-w64-mingw32\lib -lmingw32 -lSDL2main -lSDL2 -mwindow
I've finally compiled and works SDL2 testing.

That's because the SDL libs are under the LGPL-license.
If you want to static link the libs (you can do that if your recompile them. It needs some hacking into the makefiles though) you have to place your game under some compatible open source license as well.
The SDL-libs come as shared libraries because most programs that use them are closed source. The binary distribution comes in a form that most people need.

On my system (Ubuntu) I have to use the following flags:
-Wl,Bstatic -lSDL_image `sdl-config --libs` -lpng12 -lz -ltiff -ljpeg -lasound -laudio -lesd -Wl,-Bdynamic `directfb-config --libs` -lpulse-simple -lcaca -laa -ldl
That links SDL, SDL_image, and many of their dependencies as static. libdl you never want static, so making a fully-static binary that uses SDL_image is a poor idea. pulse,caca,aa, and directfb can probably be made static. I haven't got far enough to figure them out yet.

Related

Modify default library search dirs that gcc passes to ld

I want to force new GCC 12 on my old debian (that only has GCC 6 by default) to use fresh libstdc++ headers with new header-only features, but link with old stdlibc++,gcc_s (and other system/compiler libs used by GCC6) to keep binary compatibility with native runtime of old debian (so that users of old GCC6 can link with my binaries without having GCC12).
Of course I know that some functionality in the old runtime will be missing, and ABI is also different, but I guess I can fight with that. Afterall RedHat seems to be using similar scheme for their devtoolset packages (they try to link missing functionality of new runtime statically to your binary if these symbols are not found in native old runtime)
So far I am stuck with -L arguments that GCC is passing to ld.
Here is complete output of /usr/local/gcc12/bin/x86_64-linux-gnu-gcc-12 main.cpp -Wl,-v -v command for simple hello-world main.cpp:
https://pastebin.com/JhYSfg4x
The question: Where does GCC take all these -L paths from, and how do I remove/modify them? I don't want to accidentally link with new version of libraries that were built with GCC12:
-L/usr/lib/gcc/x86_64-linux-gnu -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12 -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../.. /tmp/ccXfhCs4.o
System ld.conf does not mention any paths to /usr/local/gcc12 folder.
-nostdlib and -nodefaultlibs are removing some standard -l flags, but they are not doing anything to -L flags.
Update: I ended up just removing all *.a, .so, *.la files from include, lib and lib64 folders of gcc12, and I also added -L path to native libraries. This way I am sure gcc12 can't pickup one of its libraries for li nking. Not sure if this is good solution, but it works.

How to compile fortran code to run without gfortran installed

I have downloaded Bellhop, which is an underwater acoustic simulator written in Fortran. It can be found here with the Makefile.
Question 1: I would like to know if it is possible to compile Fortran code, including everything needed, so a user without gfortran installed, can run it.
I have read here the following:
static linking
This section does not apply to Windows users, except for Cygwin users with gcc4-4.3.2-2 or later.
gfortran is composed of two main parts: the compiler, which creates the executable program from your code, and the library, which is used when you run your program afterwards. That explains why, if gfortran is installed in a non-standard directory, it may compile your code fine but the executable may fail with an error message like library not found. One way to avoid this (more ideas can be found on the binaries page) is to use the so-called "static linking", available with option -static gfortran then put the library code inside the program created, thus enabling it to run without the library present (like, on a computer where gfortran is not installed). Complete example is:
gfortran -static myfile.f -o program.exe
Reading this, I suppose that it is possible to do what I'm asking but I'm not very familiarized with fortran and makefiles. I don't understand this:
put the library code inside the program created
Question 2: How can I put the library code inside the program? Where can I find the library? What does "inside the program" means?
I'm running OSX 10.9.4 and gfortran
I solved my problem about compiling Fortran code with gfortran using static libraries.
As #M.S.B. said, using static-libgfortran worked for me under MacOS.
If somebody is having issues with linking the libquadmath.0.dylb library, remove libquadmath.0.dylib and libquadmath.dylib from /usr/local/gfortran/lib/
This doest the trick. Further information can be found here
I think the meaning of the bold part is actually
gfortran then puts the library code inside the
program created
That means using -static should be enough, there is no additional step. Just be advised you will need a static version of all the libraries that you link with.
I know this is very old tracker, but maybe somebody will be still interested in the solution that works.
Let's say we have code:
! fort_sample.f90
program main
write (*,*) 'Hello'
stop
end
First, compile the stuff:
gfortran -c -o fort_sample.o fort_sample.f90
Then, link stuff
ld -o ./fort_sample -no_compact_unwind \
-arch x86_64 -macosx_version_min 10.12.0 \
-lSystem \
/usr/local/gfortran/lib/libgfortran.a \
/usr/local/gfortran/lib/libquadmath.a \
/usr/local/gfortran/lib/gcc/x86_64-apple-darwin16/6.3.0/libgcc.a \
fort_sample.o
You can execute it
./fort_sample
Hello
You can notice that quadmath is no longer there
> otool -L fort_sample
fort_sample:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.51.1)
I guess this is what you were looking for in a first place. No removing dylibs, no symbolic links, etc.
The current version of the option is -static-libgfortran. This means that the Fortran specific libraries of gfortran will be included into the executable. These are libraries are automatically found for a good installation of gfortran. This should produce an executable that should run on other computers with the same OS, even if that computer doesn't have gfortran installed. This option likely doesn't statically link all libraries, so there is some risk that some other shared library used on your computer won't be available on the other computer.

Force CMake to use static libraries

[Shamelessly cross-posted from the CMake help list]
I'm trying to create binaries as statically as possible. The fortran code I've got has got X11 and quadmath as dependencies, and I've come across a number of issues (maybe each of these issues should be in a different question?):
My variables are currently
set(CMAKE_LIBRARY_PATH /usr/X11/lib /usr/X11/include/X11 ${CMAKE_LIBRARY_PATH})
find_package(X11 REQUIRED)
find_library(X11 NAMES X11.a PATHS /usr/X11/include/X11/ /usr/X11/lib)
find_library(X11_Xaw_LIB NAMES Xaw Xaw /usr/X11/include/X11/ /usr/X11/lib ${X11_LIB_SEARCH_PATH})
find_library(Xaw Xaw7 PATHS ${X11_LIB_SEARCH_PATH})
set(CMAKE_LIBRARY_PATH /usr/lib/gcc/x86_64-linux-gnu/4.7 /usr/lib/gcc/x86_64-linux-gnu/4.7/x32 /usr/lib/gcc/x86_64-linux-gnu/4.7/32 ${CMAKE_LIBRARY_PATH})
find_library(quadmath NAMES quadmath.a)
set(BUILD_SHARED_LIBS ON)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(LINK_SEARCH_START_STATIC TRUE)
set(LINK_SEARCH_END_STATIC TRUE)
set(SHARED_LIBS OFF)
set(STATIC_LIBS ON)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
Using these, CMake attempts to build every program statically (as expected) - however, it fails because I don't have Xaw.a - I can't find out whether this actually should exist. I have installed the latest libxaw7-dev which I was expecting to fix it. One option would be to compile the X11 libraries myself, but I don't really want to do that...
if I comment out only set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static"), then CMake compiles everything, but uses shared libraries for every program, even though I specify the location of .a X11 libraries in my find_library() calls. I was expecting CMake to use the .a files where it could and then only use shared libraries - is there a way to force this behaviour?
does anyone know yet of a fix for the bug described here: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46539; whereby gfortran seemingly can't statically link libquadmath? I tried the fix using gcc but I can't get CMake to recognise the libgfortran flag:
cmake -DCMAKE_Fortran_COMPILER=gcc -DCMAKE_Fortran_FLAGS=-gfortran
results in
-- The Fortran compiler identification is unknown
-- Check for working Fortran compiler: /usr/bin/gcc
-- Check for working Fortran compiler: /usr/bin/gcc -- broken
CMake Error at /usr/share/cmake-2.8/Modules/CMakeTestFortranCompiler.cmake:54 (message):
The Fortran compiler "/usr/bin/gcc" is not able to compile a simple test program.
However, as you might have noticed, I set the location of the libquadmath.a; when I build a program which doesn't use X11 but does use quadmath when I use
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
then the program does compile successfully (running ldd reports 'not a dynamic executable') - does this mean that the bug has been fixed, or does it only work because I set the location in CMake?
I was having a similar problem. Turns out that cmake was implicitly linking against libgfortran and libquadmath. To fix this I put the following in my top level CMakeLists.txt:
unset(CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES)
I could then explicitly link again the libraries using:
SET_TARGET_PROPERTIES(main_f PROPERTIES LINKER_LANGUAGE "C"
LINK_FLAGS
"/usr/local/Cellar/gcc/7.1.0/lib/gcc/7/libgfortran.a
/usr/local/Cellar/gcc/7.1.0/lib/gcc/7/libquadmath.a -lm -lgcc"
)
The static version of libgfortran is necessary because the shared library also depends on libquadmath. The added "-lm" and "-lgcc" bring in the system dynamic versions of these libraries. On a mac system, you would want to use the full path to your libm.a as well.
I guess your questions are not that much related, I don't know the answer for all of them.
For your static linking problems, since you're using GCC, you can pass multiple -static and -dynamic flags to it:
set(CMAKE_EXE_LINKER_FLAGS "-static ${STATIC_LIBS} -dynamic ${EVERYTHING ELSE} -static ${MORE_STATIC_LIBS}")
I don't know why Xaw.a isn't available on your system, probably because the package maintainer of your Linux distribution didn't really make them available.
Also, compiling everything static might make things not compatible between all distros out there and you cripple the ability for others to use improved, up-to-date libraries with your program, it might not be what you want.
If you intend to make a self-contained package of your program, it might be better just to include the shared libraries you used together, like Dropbox and many other proprietary applications do (Humble Bundle games are other example).

Can't get GCC's -static-libgcc working with DYLIB libraries on Mac OS X

I've installed GCC 4.6.3 into a non-system path on a Mac system and it works fine. However, GCC wants to use code from libgcc for all the binaries I compile, and running otool -L shows that these compiled programs look for libgcc_s.1.dylib in GCC's install path. I can override this by passing -static-libgcc, which just compiles the stuff needed into the binary and that's fine. The problem is this only seems to work with executables, not shared libraries. If I use GCC to compile some third-party lib I want to use in one of my programs as a .dylib, these libraries still look for libgcc_s.1.dylib in the local GCC install path even if I specify -static-libgcc! Needless to say, this is a problem as there's no guarantee that those libraries will find libgcc when run on some other system.
I tried this with ffmpeg. If I look at config.log, the -static-libgcc is most certainly being used. GCC is just not linking libgcc statically with the resulting dylibs. I even tried the -nostdlib, -nostartfiles and -nodefaultlibs options but they were ignored. Again, I checked config.log and they're definitely there!
I believe this is to do with throwing exceptions across the shared library boundary. This page says:
There are several situations in which an application should use the
shared libgcc instead of the static version. The most common of these
is when the application wishes to throw and catch exceptions across
different shared libraries. In that case, each of the libraries as
well as the application itself should use the shared libgcc.
Therefore, the G++ and GCJ drivers automatically add -shared-libgcc
whenever you build a shared library or a main executable, because C++
and Java programs typically use exceptions, so this is the right thing
to do.
The rest of that sections gives a possible workaround (it appears) and that is to use the GCC driver to link your shared library, however if the statically-linked library throws exceptions you'll probably get a Segmentation Violation.

GCC link order changed?

I am trying to link a C++ module using GCC, essentially like this:
gcc -c hello.c
g++ -c world.cpp
gcc -ohello -lstdc++ hello.o world.o
Note that I use -lstdc++ to link the C++ module in, so that I can use gcc instead of g++. The problem is that I'm getting the error:
undefined reference to `operator new(unsigned long)'
(Assuming that world.cpp contains at least one call to new.)
This error is fixed if I put -lstdc++ at the end of the linker line, like this:
gcc -ohello hello.o world.o -lstdc++
I am aware that this question has been asked many times here, but I have a special requirement. I am not directly calling GCC. I am using a build system for a different programming language (Mercury) which is calling GCC on my behalf, and I can't easily modify the way it calls GCC (though I can specify additional libraries using the LDFLAGS environment variable). So I have two additional requirements:
I cannot use g++ to link (only gcc) -- that is why I am doing the -lstdc++ trick above rather than simply linking with g++).
I don't think that I can control the order of the linker commands -- Mercury will put the .o files on the command-line after any libraries.
I understand the basic reason why the order is important, but what is baffling me is why did this break now? I just updated to Ubuntu 11.10 / GCC 4.6.1. I have been successfully compiling this program for years using precisely the above technique (putting -lstdc++ first). Only now has this error come up. An unrelated program of mine links against OpenGL using -lgl and that too broke when I upgraded and I had to move -lgl to the end of the command-line. I'm probably going to discover that dozens of my programs no longer compile. Why did this change? Is there something wrong with my new system or is that the way it is now? Note that these are ordinary shared libraries, not statically linked.
Is there anything I can do to make GCC go back to the old way, where the order of libraries doesn't matter? Is there any other way I can convince GCC to link libstdc++ properly without moving it after the .o files on the command-line?
If Mercury puts object files after libraries, Mercury is broken. Libraries belong after object files - always. You may sometimes get away with the reverse order, but not reliably. (Static libraries must go after the object files that reference symbols in the static library. Sometimes, a linker will note the symbols defined by a shared library even when none of the symbols are used; sometimes, the linker will only note the shared library symbols if the shared library provides at least one symbol.)

Resources