First of all, different operating systems use different
file formats for their executable files.
Windows uses the
PE format (which comes as
.exe files), while
Linux uses the
ELF format. That is the reason why Windows executable files cannot run on Linux and vice versa – except by an emulation layer like Wine – even when both file formats essentially contain compiled "x86" (or "x64") binary machine code.
Another important difference is the operating system's
API. In Windows, applications use the
Win32 API and/or
COM interfaces to call services from the operating system, whereas Linux provides an API that is mostly
POSIX compliant; even though Linux has many extensions that go beyond the POSIX standard.
😱 Neither has Windows a POSIX-compatible API, nor does Linux have a Win32 API. They're incompatible!
Windows executables certainly are
not "automatically" guaranteed to run on
every version of Windows that has ever existed! But it is relatively easy to make a Win32 executable that runs on
all somewhat recent Windows versions, because there is only
one "flavor" of Windows – the one that you can buy from Microsoft.
With Linux the situation is
way more complicated/heterogeneous. That is because Linux is
OpenSource, and because Linux is just a
kernel. Linux is
not a fully-fledged operating system by itself. Consequently, there are many different
Linux distributions that create a "complete" operating system based on the Linux kernel – such as
Debian/Ubuntu,
RHEL/Fedora,
Arch and many more – all of which are somewhat different !!!
Yet another thing to consider: On Windows, it is a common practice that executable files come "bundled" with all the required libraries (DLL files). Only some fundamental system libraries (
kernel32.dll, etc. pp.) are provided by Windows itself. On Linux, however, it is common that
all executables as well as
all libraries are managed by the "centralized" package manager of the respective distribution. This can easily lead to
library-incompatibilities, if you "transplant" a pre-compiled executable from one Linux distribution to another!
Anyhow, it
is possible to create a Linux executable which runs on almost every Linux distribution that has a somewhat up-to-date Linux kernel. But, to make this possible, you need to link in
all libraries
statically. However, because
glibc – the "default" C runtime library on most Linux distributions – is
not well suited for
static linking, you have to use an "alternative" C runtime library that supports
static linking, e.g.
musl.
https://musl.libc.org/
Finally, "container" technologies – like
snap or
flatpak – make it possible to package Linux executables in such a way that they can run on a wide range of
different Linux distributions. But that's another topic.