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
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
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
. 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
Finally, "container" technologies – like snap
– 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.