When we talk about compatibility, three objects/entities are involved. We say object2 is compatible with object1 if object3 that uses object1 is still working when it switches object1 to object2. When there is a time relationship between object1 and object2, we can have backwards compatibility and forwards compatibility. If object1 is prior to object2, we say object2 is backwards compatible with object1. If object1 is after object2, we say object2 is forwards compatible with object1.
When this principle is applied to software library, we have the concepts of backwards compatibility and forwards compatibility for libraries. If programs that are linked against the older version of the lib can still run in the environment where newer version of the lib is deployed, we say the newer version of the lib is backwards compatible with the older version of the lib. For example, Qt libs have backwards compatibility across minor versions. Your program that is built against Qt 5.0 can run without a problem under Qt 5.12. But different minor versions of Qt libs do not have the forwards compatibility. Your program built with Qt 5.13 cannot run under Qt 5.12. The patch version(the third number of version string) has both backwards compatibility and forwards compatibility. In other words, your program linked against Qt 5.8.2 can run normally under Qt 5.8.1 and Qt 5.8.3.
In the above example, the 3 entities involved are binaries. Thus the compatibility is called binary compatibility. If we talk about the source code, we have source compatibility. If we can recompile the source code of our program using the newer version of the lib without any modification and the semantics are also kept, we call the newer version of the lib is source compatible with the older version of the lib. Likewise, if we can recompile the source code of our app that was originally compiled under the newer version of the lib, in older version of the lib this time, we say the older version of the lib is source forwards compatible with the newer version of the lib.
We talk more about backwards compatibility than forwards compatibility because we hope existing programs can still run when we upgrade the libs they use. We want the the old source code still compiles under new libs without modification. Thus, when we talk about just the compatibility, we imply the backwards compatibility. Forwards compatibility is useful in expanding the working scenarios of app, i.e., we develop apps in latest development environment but we can still deploy the app in a relatively old environment.
There are multiple ways to implement the compatibility. For example, glibc uses the version mechanism to handle backwards compatibility.