I'm studying computer architecture and I don't understand what really makes a software for one machine "compatible" with another machine. Let's take for example two machine like Mac Os and Windows that use the same intel cpu. Now, if the opcodes are the same how is it possible that their software are incompatible with each other ?
1 ) Can someone give an outline of what the compatibility word involves ?
2 ) What are the elements that make two machines compatible with each other other than the opcodes of the cpu ?
Besides the other hardware components and as already pointed out, the software itself is a huge source of compatibility issues.
This is nothing new, you cannot always open a proprietary file format with a different application.
The format of the Linux executables is ELF, that of Windows is PE and macOS uses mach-o.
Read the linked pages and see how much the formats share and differ.
However, nothing stops an OS from supporting multiple executable formats (Linux actually does and so does Windows, probably also macOS).
If we ignore the file format issue, there's still a library problem. A program made for Linux may be written to use Linux-only libraries.
Even when there is a port, you need recompilation due to different calling conventions.
For example, calling a C standard function under Windows looks like this:
Under Linux you have to use:
If you ship all the needed libraries (with the right calling convention) with an application, there's still another problem.
The libraries need to talk to the OS and the way this is done is OS-specific.
For example, 32-bit applications used
int 80hunder Linux andint 2ehunder Windows.You can still fix this by porting the library, it now has to use the calling convention of the native OS but the interface of the host OS (e.g. the Linux SYS V ABI but the Windows syscall numbers).
This is already getting exponentially complex in the number of variables but, the real problem is not how to call the system calls, it's the interface they offer.
Trivially, the GUI system is pretty much a monolithic piece of Windows but under Linux you can use any Window manager you like. So if you have a program that calls a function that is specific to the Windows GUI, how do you translate that to Linux?
High-level operations, like create a window, can be translated (this is what libraries like Gtk and Qt do) but low-level operations (say:
RegisterClassEx) do not map one to one.This is getting even messier if you consider how different are some kernel interfaces.
For example, the uid/gid/permissions thing in Linux and the SID/DACL thing in Windows.
However, you can still fix this: you have to reimplement the other OS interface. This is a massive amount of work, but can be side skipped with a trick: run the other OS in a virtual machine.
This is how WLS2 works and it's why it allows you to use Linux binary under Windows.
Note that WLS2 is possible because:
This is not always the case, Linux cannot run a Windows kernel in a VM to support Windows binaries, it has to emulate it (see: Wine) and that's akin to reimplementing a big part of Windows!