Even then, you still need ABI consistency between compilers if you want to link together codebases written in different languages (e.g. C and Rust).
In practice this almost always 'just works' because most cross-language calls simply don't use the kinds of complicated types discussed in the blog post. They tend to stick to simple integer and pointer types, where ABI consistency is usually a given.
Though you can still get into trouble when passing function pointers, especially when combined with some modern control-flow integrity systems.
You _still_ need a consistent way to talk about values; IPC systems tackle the same problems under the name marshalling & de/serialisation. They just tend to take much more conservative options to deal with exactly this kind of problem (you don't have to care about integer endian-ness if integers are expressed as strings).
In practice this almost always 'just works' because most cross-language calls simply don't use the kinds of complicated types discussed in the blog post. They tend to stick to simple integer and pointer types, where ABI consistency is usually a given.
Though you can still get into trouble when passing function pointers, especially when combined with some modern control-flow integrity systems.