How can I compile SDL2 and GLEW applications statically on Linux? - c++

I am attempting to compile an OpenGl application that uses SDL2 and GLEW in such a way that it will run on any version of Linux it may find itself -- not just where it was originally compiled. To do this, I have tried several things none of which work.
I have tried directly linking to .a files produced by running make in the extracted root directory of GLEW and SDL from each library's website download. This produces the following errors:
/usr/bin/ld: /opt/SDL2-2.0.4/build/.libs/libSDL2.a(SDL_syssem.o): undefined reference to symbol 'sem_getvalue##GLIBC_2.2.5'
//lib/x86_64-linux-gnu/libpthread.so.0: error adding symbols: DSO missing from command line
I have tried building as I do with dynamically linked libraries, which works fine except for the cross-platform capabilities, (with pkg-config --libs sdl2 and pkg-config --libs glew) but adding -static, at which point I get the following errors:
/usr/bin/ld: cannot find -lGLEW
/usr/bin/ld: cannot find -lGL
When I change the previous scenario to point to my statically compiled GLEW libraries, I get undefined reference errors to OpenGl functions along with undefined reference errors like the following from many SDL functions. Adding -lGL does not change anything.
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_dynapi.o): In function `SDL_InitDynamicAPI':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_dynapi.o): In function `SDL_InitDynamicAPI':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_dynapi.o): In function `SDL_InitDynamicAPI':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_sysloadso.o): In function `SDL_LoadObject_REAL':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_sysloadso.o): In function `SDL_LoadObject_REAL':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_sysloadso.o): In function `SDL_LoadFunction_REAL':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_sysloadso.o): In function `SDL_LoadFunction_REAL':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_sysloadso.o): In function `SDL_LoadFunction_REAL':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_sysloadso.o): In function `SDL_UnloadObject_REAL':
When I try using pkg-config --libs --static <library name> for all libraries, I get the following error:
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libSDL2.a(SDL_dynapi.o): In function `SDL_InitDynamicAPI':
/usr/bin/ld: cannot find -lasound
/usr/bin/ld: cannot find -lpulse-simple
/usr/bin/ld: cannot find -lpulse
/usr/bin/ld: cannot find -lsndio
/usr/bin/ld: cannot find -lwayland-egl
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libwayland-cursor.a(libwayland_cursor_la-xcursor.o): In function `XcursorImagesDestroy':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libXcursor.a(file.o):(.text+0x7d0): first defined here
/usr/bin/ld: cannot find -lGLEW
/usr/bin/ld: cannot find -lGL
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libX11.a(GetDflt.o): In function `GetHomeDir.part.0':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libX11.a(GetDflt.o): In function `GetHomeDir.part.0':
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libX11.a(xim_trans.o): In function `_XimXTransSocketINETConnect':
collect2: error: ld returned 1 exit status
NOTE: All of the output above is from the command g++ -o /path/to/outputExecutable <list of object files>.o <libraries as described above>
NOTE: I do not think this question is a duplicate of any other question on the Stack Exchange network because I have been trying to figure this out for about one and a half months and I have seen a very large number of these questions and tried everything in them, thus, even if the symptoms are the same the underlying problem is different.
NOTE: This is a closed-source application so dynamic linking is not an option for it requires distributing the source code to allow users to build the binaries on their own systems.
NOTE: I am currently trying to get this to compile with Linux via g++, but, I do intend to use mingw to distribute this application for Windows as well. Any advice that works there is preferable to Linux only advice, but, I can ask another question if I can't figure out that part from what will end up here.
NOTE: I am using Ubuntu 16.04 LTS x64 to compile.
Thank you in advance for even getting this far in this question. Sorry for the wall of text, but, I wanted to provide as much information as possible. I look forward to any answers!

Older Loki games did full static linking. Probably not worth it anymore, and far more difficult if you use external libraries.
Libraries are often not self-sufficient, requiring other libraries, .... Dynamic library have dependency information built-in, but static library is just an archive of .o files - it may depend on something but there is no special section that describes what extra libraries should be used. Your first error says that libSDL2.a uses symbol sem_getvalue##GLIBC_2.2.5 (sem_getvalue function, marked with glibc version) that cannot be resolved - most likely because you didn't add -lpthread to your linker flags. (libSDL.so depends on some version of pthrtead among other things - that's why you don't need to manually link with it if you don't use it directly).
GLEW should have no problems with static linking. You need to be more specific on errors you're getting. Maybe you got your libraries order wrong and linker cannot resolve GL functions. Need to see actual linking line and some 'undefined reference' errors to be more specific.
pkg-config's --static flag should give you dependencies list (e.g. -lpthread should be in the output of sdl2-config --static-libs among many others), but it does not by itself produce static linking with given library. To request static linking, there are -static gcc flag that generates static executable (hard!) and -Bstatic linker flag to use static version for all libraries specified after it (so that way you can use some static libraries and some dynamic). -Bdynamic is a counterpart, asking to use dynamic libraries. E.g. to use static SDL and GLEW but dynamic GL linking line should be something like (if you use gcc to link, not ld directly) gcc ${OBJECT_FILES} -Wl,-Bstatic -lSDL2 -lGLEW -Wl,-Bdynamic -lGL -lpthread -ldl -lm <everything else SDL2 requires - query with sdl2-config>.
Your /usr/bin/ld: cannot find -lasound lines may have two reasons - static linking or related to the fact that you don't have development libraries installed (e.g. libasound2-dev, libpulse-dev, ... - at least they called that on debian, it is unlikely ubuntu have different names). 'User' libraries usually contains e.g. libasound.so.2 but linker will not find this library as it have a version in it. Development package contains headers and symlink libasound.so -> libasound.so.2 - that way linker knows what to use. If you use it indirectly via SDL2 - you don't need that, shared SDL2 already have a link to versioned library.
However there may be little point in doing so at all. You can distribute requred shared libraries with your software and use them either via rpath or LD_LIBRARY_PATH environment variable (maya, steam, etc... - almost everyone doing these this days). Moreover, even with static SDL2 end user can override SDL2 with their own (this is a feature intentionally implemented in SDL2). If there is a bug (or just very different environment) and your software is no longer gets updates - there is a chance that problem may be fixed by just replacing shared libraries. Would you really mind people running your program on wayland or mir if your original SDL2 had only X11 support?
in such a way that it will run on any version of Linux it may find itself -- not just where it was originally compiled is far more complicated, and honestly almost unrealistic (unless you have quite small program and use only very limited set of libraries with a good forward/backward compatibility - but even then it may be hard). One of big problems is glibc; usually it is a good idea to use lowest possible version of glibc to compile your program.
To sum it up, it is possible, but it does not help much.

Related

Buildroot cross-compiling - compile works but linking can't find various SDL functions

I have some code that I could cross-compile with an older toolchain that used uClibc, but the project is moving to musl libc, and I can't seem to get the code to compile with that toolchain. It always fails during the linking stage with a bunch of errors along these lines:
/opt/miyoo/bin/../lib/gcc/arm-buildroot-linux-musleabi/11.2.0/../../../../arm-buildroot-linux-musleabi/bin/ld: objs/miyoo/src/touchscreen.o: in function `Touchscreen::poll()':
/__w/gmenunx/gmenunx/src/touchscreen.cpp:87: undefined reference to `SDL_PumpEvents'
/opt/miyoo/bin/../lib/gcc/arm-buildroot-linux-musleabi/11.2.0/../../../../arm-buildroot-linux-musleabi/bin/ld: /__w/gmenunx/gmenunx/src/touchscreen.cpp:89: undefined reference to `SDL_GetMouseState'
/opt/miyoo/bin/../lib/gcc/arm-buildroot-linux-musleabi/11.2.0/../../../../arm-buildroot-linux-musleabi/bin/ld: objs/miyoo/src/surface.o: in function `Surface::Surface(SDL_Surface*, SDL_PixelFormat*, unsigned int)':
/__w/gmenunx/gmenunx/src/surface.cpp:74: undefined reference to `SDL_ConvertSurface'
There are a couple that I'm not sure are SDL things, such as IMG_LoadPNG_RW and TTF_Init, but for the most part, it's all SDL_Whatever that the linker can't find, right after the compiler just found it.
You can see the full output from the failing musl build (linking starts on line 857), and compare it to a working uClibc build (linking starts on line 863).
I tried messing around with changing the buildroot settings from static to dynamic, and also both, but that didn't change anything. I also tried adding SDL2, even though I'm fairly certain the code actually depends on SDL 1, but I couldn't get buildroot to make the toolchain when I had SDL2 enabled. I tried some other things like switching around argument orders, but none of it seemed to solve the issue.
For context, I'm trying to build a docker image that can be used to cross-compile software for MiyooCFW in GitHub Actions.
I tweaked a docker image with the old toolchain and created a new one with the new toolchain so that we could build both in GitHub Actions.
This is the buildroot repo I used for the musl toolchain: https://github.com/nfriedly/buildroot
The uClibc toolchain is available in a .7z file on google drive, but I'm not sure where the source for it is. There is also some (incomplete) documentation.
I'm a noob when it comes to most of this stuff, so there may very well be something obvious that I'm just missing.
#user17732522 helped me work through a couple of issues:
several flags were out of order:
.o files should come before -l options
-lfreetype must come after -lSDL_ttf)
several flags were missing:
-ljpeg -lpng -lz after -lSDL_image
-lvorbisfile -lvorbis -logg after -lSDL_mixer
-lbz2 -lmpg123 at the end
This PR has the fixes that allow it to compile on the new toolchain (without breaking compiling on the old one): https://github.com/MiyooCFW/gmenunx/pull/12

How do I compile gnu libstdc++.a with PIC?

I'm trying to compile a shared library for systems that don't have a libstdc++ new enough to run it, which means I need to statically link libstdc++ into the library. I'm trying to link directly to libstdc++.a (-Wl,-Bstatic -L/path/to/lib64 -lstdc++), but I'm getting an error that seems to indicate that my libstdc++.a wasn't linked with PIC:
/usr/bin/ld: lib64/libstdc++.a(compatibility.o): relocation R_X86_64_32 against `typeinfo for __cxxabiv1::__forced_unwind' can not be used when making a shared object; recompile with -fPIC
lib64/libstdc++.a: could not read symbols: Bad value
I tried recompiling GCC with CFLAGS="-fPIC" and CXXFLAGS="-fPIC", but that didn't seem to do anything.
Help?
The idea is to pass --with-pic option to the configure. GCC build is a very complex beast with multiple stages, so simply passing a CFLAGS variable may not work as intended.
Reading GCC configure documentation. I used this flag --enable-host-shared when building GCC as it said in the description:
Specify that the host code should be built into position-independent
machine code (with -fPIC), allowing it to be used within shared
libraries, but yielding a slightly slower compiler.

Undefined reference to .. error (Linux) - Compiles fine in OSX

Have wasted almost full 4 days trying to compile this package. It compiles fine in OSX 10.6, but gives Undefined reference errors when I try to compile it on a linux (Kubuntu 10.04, 3.8.0.27 kernel) machine.
The error seem to be that the makefiles are ordered wrong, but AFAIK, I am the only one having trouble compiling it. So I'm trying to find what's making the difference. The software package is quite big and editing the Makefiles and moving 30-50 libraries here and there doesn't seem like a good idea.
Here's the differences I think I found so far
Compiler - gcc-4.7 (Linux) and llvm-gcc-4.2 (OSX)
Compiler flags --shared (Linux) and -dynamic -dynamiclib -undefined dynamic_lookup (OSX)
Anyone have any suggestions?
I tried using clang++ and llvm-gcc-4.7 as the compiler, but I think it still used the same linker (ld?). So I could try to specify to use llvm? How do I do that?
is --shared flag somehow different from the dynamic -dynamiclib -undefined dynamic_lookup flags in OSX?
Does the linux kernel or distribution matter? (I think they compiled it fine on a CentOS machine)
Please help.
Thanks a lot.
Compiled it with gcc 4.4 and worked flawlessly. I guess the order doesn't matter on 4.4 for the given package.
The undefined references type of errors can be caused by a symbol not being compiled in, not being linked or being linked out of order. The way to debug this is to check the linker line, the symbol that the linker complains about. The error message will probably tell you what object file has the dependency.
Now, you need to find out whether the symbol is compiled or linked, for that you will need to find if it is in any of the object files or in any of the libraries and which. You can use the nm command line tool to list the symbols that are defined in any given .o or library. If the symbol is not there, then you need to figure out what to add to the linker line and that will solve it.
If the symbol appears in one library, then identify which of the libraries depends on that symbol (from the linker error message) and the library that contains it. The former must be listed before the latter in the linker command line (assuming static linking).
As a simple hack, although I recommend against it, you can instruct the gcc linker to do multiple passes by using the --start-group and --end-group command line options. Although I really recommend that you figure out the order of dependencies, as that will also give you a better insight into your project.

How to optionally depend on a shared object with gcc?

First, I don't know if there is a solution to my problem at all.
I have the following situation:
I have developed a framework library that depends on several other libraries for specific hardware access, etc.
Until now this framework library was only statically linked against.
For the executable that uses the framework library only the dependencies of code that is actually used by the executable have to be linked. (If I don't access a specific hardware at all I don't have to depend on its associated libraries.)
Now I need to also make a shared object of the framework library. Also the dependencies are available as shared libraries, so there is no need for any static linking.
The problem I have now:
When building an application that links dynamically to the framework library I have to either link all dependencies dynamically to the framework library or the application. (Otherwise I get undefined references complaints from ld)
My questions:
Is there any way to ignore certain shared object dependencies if I know that my application will not use any code of the framework library that depends on this shared object?
Is there any way to do this without or with minimal code changes? (linker / compiler switches)
I also need the static linking as described in the original situation to still work.
Additional Info:
Operating system: Linux (Debian Lenny)
Compiler: gcc-4.3
You can, but you basically have to do all of the dynamic library handling yourself. i.e. dlopen the library, and then look up the symbols you need directly with dlsym.
It will make your code more complicated, how much depends on the interface you've got into the libraries.
From man ld
--as-needed
--no-as-needed
This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line after the --as-needed option. Normally,
the linker will add a DT_NEEDED tag for each dynamic library mentioned on the command line, regardless of whether the library is
actually needed. --as-needed causes a DT_NEEDED tag to only be emitted for a library that satisfies a symbol reference from regular
objects which is undefined at the point that the library was linked, or, if the library is not found in the DT_NEEDED lists of other
libraries linked up to that point, a reference from another dynamic library. --no-as-needed restores the default behaviour.
I haven't used it myself but sounds like what you're looking for.
g++ -o your_app -Wl,--as-needed -lframework -la -lb -lc -Wl,--no-as-needed
Edit (suggested by Hanno)
--warn-unresolved-symbols
If the linker is going to report an unresolved symbol (see the option --unresolved-symbols) it will normally generate an error.
This option makes it generate a warning instead.

Problems linking static Intel IPP libraries on Linux with g++

I've been trying to move a project over from Xcode to Linux (Ubuntu x86 for now, but hopefully the statically-linked executable will run on an x86 CentOS machine? I hope I hope?). I have the whole project compiling but it fails at the linking stage-- it's giving me undefined references for all functions defined by IPP. This is probably something really small and silly but I've been beating my head over this for a couple days now and I can't get it to work.
Here's the compile statement (I also have a makefile that's generating the same errors):
g++ -static
/opt/intel/ipp/6.0.1.071/ia32/lib/libippiemerged.a
/opt/intel/ipp/6.0.1.071/ia32/lib/libippimerged.a
/opt/intel/ipp/6.0.1.071/ia32/lib/libippsemerged.a
/opt/intel/ipp/6.0.1.071/ia32/lib/libippsmerged.a
/opt/intel/ipp/6.0.1.071/ia32/lib/libippcore.a
-pthread -I /opt/intel/ipp/6.0.1.071/ia32/include
-I tools/include -o main main.cpp pick_peak.cpp
get_starting_segments.cpp
get_segment_timing_differences.cpp
recast_and_normalize_wave_file.cpp
rhythm_score.cpp pitch_score.cpp
pitch_curve.cpp
tools/source/LocalBuffer.cpp
tools/source/wave.cpp distance.cpp
...and here is the beginning of the long list of linker errors:
./main.o: In function `main':
main.cpp:(.text+0x13f): undefined reference to `ippsMalloc_16s'
main.cpp:(.text+0x166): undefined reference to `ippsMalloc_32f'
main.cpp:(.text+0x213): undefined reference to `ippsMalloc_16s'
Any ideas? FWIW, these are the IPP dependencies in my Xcode project that builds, links, and runs without a problem: "-lippiemerged",
"-lippimerged",
"-lippsemerged",
"-lippsmerged",
"-lippcore",
Thanks!
Your linking problem is likely due to the fact that your link line is completely backwards: archive libraries should follow source and object files on command line, not precede them. To understand why the order matters, read this.
Also note that on Linux statically linked executables are significantly less portable than dynamically linked ones. In general, if you link system libraries dynamically on an older Linux system, it will work on all newer systems (I use ancient RedHat 6.2, and I haven't seen a system on which my executable will not run). This is not true for completely static executables; they may crash in all kinds of "interesting" ways when moved to a system with a different libc from the one against which they were linked.
I had problems with linking code with the v 6 of the ipp; using the v11 version of the compiler (with the included updates to the ipp) mysteriously fixed them. Granted, that was with a windows platform, but I was getting 8u versions of functions to compile and no 32f versions, despite both being listed as valid in the documentation.