For one thing, some distros use a different processor architecture,
I'm assuming we're talking about x86 here, which is what the vast majority uses. (If you want to support ppc or arm or whatever too, fine, but you can worry about that later. Linux doesn't support fat executables (
at least not officially), so they'll be different executables anyway.)
others have different versions of libraries in different locations, and so on.
Which is why including libraries is a good idea, similar to how you'd include .dlls in windows.
Linux releases are generally done as source, and users compile it themselves, or you find someone to make packages for various distros.
No. Please stop saying this. Even if he
can release source, most Linux people like not having to compile everything too, and it's not an option for closed-source stuff in any case.
~
Anyway, it's very possible to make executables that run on pretty much all Linux distros (obviously only for compatible cpu architectures, and assuming the distro isn't extremely old), but you have to work a little more for it than just compiling and hoping it'll go.
First off, make sure your executable or any of the libraries you'll include doesn't depend on a too new version of glibc. You can check this with objdump:
objdump -x my-executable | grep GLIBC
You'll get a list of glibc version numbers. The highest of these is the minimum required glibc version that your game (and libraries, if you check those (which you should)) require to run. If it's too high (i tend to go with around 2.3-2.3.6 max, but that's pretty old by now so you can probably go a little higher), you can use a little trick to build files that depend on an earlier version of glibc. gcc unfortunately doesn't support this directly, but you can use
gensymoverride to generate a special include file you can force-include with your compiles to force the earlier glibc. Run gensymoverride without arguments for usage info. Once you've got your header, use it by passing -include your-header.h to every gcc command (ie gcc -include overrides.h ...). I recommend setting up a script to do this for you and set that script as the compiler to use. Remember you'll have to do this for any offending libraries you use as well. When done, double-check that it worked with objdump again as above.
Secondly, statically link what you can. Do
not statically link glibc, but if you use libstdc++ and don't use any dynamically linked libraries that use c++, you can statically link that if you want (get the static version of libstdc++ with "g++ -print-file-name=libstdc++.a", and pass "-static-libgcc" and "-Wl,--as-needed" when linking. if unsure just include the libstdc++ .so with your package like any other lib).
Thirdly, include
all dynamic dependencies in the download, except for glibc (again, don't statically link this), X (parts of this can be statically linked, but leave the .so's), or libgcc_s.so (can be safely statically linked with -static-libgcc if you also either don't use libstdc++ or statically link it as well). Check what your executable and libraries depend on with ldd (all dependencies, recursive) or objdump (direct dependencies only):
ldd my-executable
objdump -x my-executable | grep NEEDED
This isn't anything special btw; you include .dlls for Windows, you include .so's for Linux. Unlike windows though, linux doesn't load libraries from the executable's directory by default, so you have to tell it to do that. You can either use a wrapper script that sets LD_LIBRARY_PATH to the path where they can be located (works similar to PATH) and then executes your real executable, or you can set RPATH on your main executable using a path relative to '$ORIGIN' where origin is expanded to the executable's containing directory by the linker. Pass -Wl,-rpath,$ORIGIN to gcc to do that, but remember to protect $ORIGIN from the shell and make etc, or they'll think it's an environment variable and ruin everything. You can verify that you did it right by checking for RPATH with objdump:
objdump -x my-executable | grep RPATH
If it's missing the $ORIGIN part or is set to "RIGIN" or something you didn't protect $ORIGIN sufficiently from the shell/make/etc. Also, running ldd on an execuable with rpath set in this way will use the rpath to locate the libraries, so you can verify that you did everything right with that.
Fourthly, make sure that libraries you include do
not have an absolute RPATH, as this may prevent them from working unless installed in that particular location, which you obviously don't want. Check with objdump -x my-executable | grep RPATH as for executables. (Rpaths relative to $ORIGIN like for the executable are fine.)
Fiftly, make sure you've covered dynamic runtime-loaded libraries (ie anything loaded with dlopen at runtime) as well, and that your executable can locate them. RPATH doesn't update the path used by dlopen, LD_LIBRARY_PATH does, so if you use the RPATH way to locate libraries to avoid the wrapper script your executable may set LD_LIBRARY_PATH to be sure these can be located. Detecting runtime-loaded libraries is a bit more tricky since they won't be listed by ldd or objdump, you'll just have to read the documentation of the things you use. An example of this is SDL_mixer which can load libogg, libvorbis and libvorbisfile at runtime (though it can be configured to depend on them "normally" as well, this is probably the best option for game purposes).
Finally, sorry if this was a little dense. It's a bit more work than "compile and go", but it's not really as complicated as it sounds either. Let me know if you've any questions.