6

I built a bunch of simple C programs for school on my Mac (OSX). I had compiled all of the programs and tested them all on my Mac with a Makefile. Everything worked well.

To prep for an assignment tomorrow, I decided to transfer all of these files (compiled and source code) via SSH to the class network (OS is Ubuntu). I wanted to make sure everything worked as expected there.

Once I transferred everything, when I tried to use the Emacs shell to run the compiled programs, I got a Cannot execute binary file error. Then, once I recompiled via my Makefile over SSH on the Ubuntu machine, it worked fine. But why not before?

I know this is obvious to some of you, but I don't know why a compiled C program will run fine on my machine, but then have to be recompiled on a different machine even with the operating systems being different?

Here is an example of my Makefile compile commands:

example:    example.c
    gcc -Wall -pedantic -ansi example.c -o example

I'm pretty new to C (obviously). This question, Why does my program run on Ubuntu gcc but not OSX gcc?, seems similar but I don't understand the answer.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
joshmcode
  • 3,471
  • 1
  • 35
  • 50
  • 9
    Because OSX and Ubuntu are two different operating systems. They don't run the exact same format executable. There are underlying differences in the OS. You'll also have to recompile to run on Windows, or Android or iOS. – Ken White May 02 '16 at 02:12
  • 4
    Different operating systems generally (not always) require different binary formats for their executables. Even when two systems use the same binary format, they typically have different expectations for where system calls live and how they're accessed. This makes compiling / linking using tools that know the correct expectations of the system you wish to run on paramount. – mah May 02 '16 at 02:16
  • @KenWhite So when you distribute C programs, do you just always have a different version for each OS then? – joshmcode May 02 '16 at 02:29
  • 6
    The C code is often the same, but you need a different executable for each OS. Executable formats are different, as are the underlying system calls. When your C code uses `fopen()`, what actually happens at the OS level is usually vastly different between OSes, and recompiling and relinking brings in the correct library code and produces the proper executable file format. – Ken White May 02 '16 at 02:32
  • 1
    Relevant duplicate: [Why is software OS specific?](http://programmers.stackexchange.com/q/247183/108326) – Elliott Frisch May 02 '16 at 02:32
  • @KenWhite oh yes, I remember reading about some of that when we were covering Linux/Unix/Multics. – joshmcode May 02 '16 at 02:37
  • You could run a Mac OSX binary in Linux provided that there is a proper emulation layer available. However it is just simpler to recompile the software from source than to make use of an emulation layer. Almost all *nix operating systems have a C compiler present or at least installable on the system. – Antti Haapala -- Слава Україні May 02 '16 at 06:14
  • 1
    **C** language assures a very high probability that a simple program would be **source compatible** on unix-like systems, which are both, OSX and Ubuntu. Executable code being **binary compatible** even on different revisions of the same operating system is not granted. – user3078414 May 02 '16 at 22:36

2 Answers2

8

Like other have mentioned the C code might be compatible but Linux and OSX use different binary formats which are not compatible. Thus you will need to recompile to make your code run on the other platform.

Linux uses a binary format called ELF

OSX uses a binary format called Mach-O

See Is a Linux executable “compatible” with OS X? for a more in depth explanation.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
Marius
  • 380
  • 3
  • 10
3

so to add to Marius's very good explanation:

they actually use the same x86-64 (amd64) calling convention (ABI) so they are compatible on another level, deeper than just C... but they are packaged in different object file formats (as described by Marius).

The other major difference is the linker... so while they both implement std C functions, they are in different libraries so if they are dynamically linked the symbols are in the wrong place.

Grady Player
  • 14,399
  • 2
  • 48
  • 76