1
$\begingroup$

A quick search on the role of compiler brings up the following:

A compiler is a special program that processes statements written in a particular programming language and turns them into machine language or "code" that a computer's processor uses.

However, I also read that every language needs to have a target runtime system and programs written in that language execute in the context of the runtime system.

Adding up the two, it appears that a compiler converts programs into bits understandable by the runtime system and the runtime system acts as the agent interpreting the bits, translating them to the processor intructions. Is this correct? If not, how else are compiler and runtime system related?

And if the above is correct, it would imply the following:

  1. two executables compiled from programs with identical logic written in different languages would not be identical
  2. with people typically installing several programs from disparate sources, an average machine would have to have dozens of runtimes which doesn't seem to be the case.

What am I missing here?

$\endgroup$
3
$\begingroup$

I just looked on my machine (which is running macOS Sierra), and I found four runtime systems for C and C++ alone:

/usr/lib/crt1.10.5.o
/usr/lib/crt1.10.6.o
/usr/lib/crt1.o
/usr/lib/gcrt1.o

They're not huge; only about 10kB each. Small enough that if you statically linked them to a typical program they would barely register. Still, there they are.

I'm certain that I have a bunch of others for different languages, too: Python and Java are fairly standard. Emacs seems to come pre-installed so there's a Lisp-like language. There's probably a Swift runtime if I look hard enough. And, of course, that's not including all the languages I installed myself because I like collecting programming languages.

Many modern operating systems are designed with C in mind (in that their system call APIs are C calls), and many languages with a "foreign function" interface support C natively because so many third-party libraries support a C API. So runtimes for many languages are often built on top of the C runtime.

It's useful to think of a runtime system as some kind of virtual machine. However, many programming languages do compile to machine code, so the job that the runtime system has to do can be as simple as initialisation and shutdown only, with nothing further needed while the program is running.

For example, a typical runtime for C and C++ (they are often shared these days) has to perform the following initialisation before any C code is run:

  • Set up the C stack.
  • Initialise any standard library data structures that need to be initialised (e.g. atexit or stdin/stdout/stderr).
  • Invoke static constructors (e.g. for C++).
  • Process command-line arguments and environment variables to pass to main().
  • Call main().

There's nothing here that really corresponds to interpreting the output of the compiler, with the possible exception of information that the compiler generates about static constructors.

Even for compiled languages, however, the runtime may provide subroutines to support source-level operations for which it would be wasteful or inconvenient for the compiler to generate code.

Exceptions in C++ are one example. Another is where some particular platform doesn't have a suitable instruction; many 32-bit platforms don't have a native 64-bit division instruction, but the compiler may still want to support 64-bit integers.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.