My next question is about the end user's setup. If I make a game using SDL2 and distribute it in binary form, how does it know where to find SDL2 on the end user's machine? When linking to the SDL2 library I put the following line in my Qt creator project file:
LIBS += -L /usr/local/lib -lSDL2
I guess that -lSDL2 is what tells the linker to link against the SDL library, but how does it know where to actually find the library? As a long time windows developer, I am used to DLLs and linker libraries, and I usually just put the DLLs next to the EXEs.
When you link your program, the linker remembers all of the DSOs (shared libraries) used to resolve external symbols. In your case, it used the DSO search path (-L/usr/local/lib) and the library name (-lSDL2 means libSDL2.so) to find libSDL2.so, which is a soft link to /usr/local/lib/libSDL2-2.0.so.0.1.1 (or something like that). It opens that file and reads a tag from the DYNAMIC header of type SONAME, which would contain the string libSDL2-2.0.so.0. The linker emits that string as a tag of type NEEDED into the DSO it's building. A DSO could be a shared library or an executable, they work the same in ELF systems.
At runtime when the dynamic link-loader (as determined by the INTERP tag, on my systems it's /lib64/ld-linux-x86-64.so.2) loads the program and tries to resolve external symbols, it reads all the NEEDED tags and looks for files that satisfy them through a set of configured search paths. the configuration is done through a program called ldconfig, which reads a set of configuration files in /etc/ld.conf.d and the file ld.so.conf and writes the results out to the file ld.so.cache. That list of libraries is augmented by the environment variable LD_LIBRARY_PATH. Those sources are search in order until a matching filename is loaded or the startup fails.
So, to summarize: when a shared library is built, it gets a special tag added called its SONAME. When something is built against that library, the SONAME is saved in that something as a NEEDED tag. When the time comes to resolve runtime dependencies in that something, the NEEDED tags are matched against a set of directories to find the original libraries (or a replacement).
The -rpath embeds a specific path into the final executable. It's not a good idea to use it for anything except private libraries (eg. plugins).