Examples of non-separate compilation?

211 Views Asked by At

From section 1.1 of "The C Book":

At the coarsest level, an obvious feature is the multi-file structure of a program. The language permits separate compilation, where the parts of a complete program can be kept in one or more source files and compiled independently of each other. The idea is that the compilation process will produce files which can then be linked together using whatever link editor or loader that your system provides. The block structure of the Algol-like languages makes this harder by insisting that the whole program comes in one chunk, although there are usually ways of getting around it.

Can anyone provide some basic examples / overview of programming in this nature ?

4

There are 4 best solutions below

0
On BEST ANSWER

Example Algol program, which does nothing useful but is here to illustrate the point:

   begin
   int x; x:=3;

   procedure p;
       begin
       integer y; y:=4;

       procedure q(n);
          value n; integer n;
          if n > 0
          then q(n-1)
          else begin
              integer z; z:=x+y;
              print(z)
              end;

       q(1)
       end;

    p; comment a parameterless procedure call;
    end;

The basic problem here is nested scopes. The procedure q depends on the surrounding blocks that define integers x and y. The procedure p likewise depends (by virtue of containing q) on the block that defines x.

You'll see, then, that each part of this stupid example program is inseparable from the surrounding text. This is the natural mode of expression to Algolers; to nest procedures in a way that makes sense for the program being written. In general this makes separate compilation quite complicated. This differs from C-like languages which have no nested procedures (functions, whatever) because the only non-local identifiers they can refer to are file scope or global scope (if I have those terms correct).

Here, the variables x and y are local to some procedure and are therefore on the stack. Just to make it more complicated, q is recursive, which makes the "distance down the stack" from its innermost invocation to the locations of x and y a variable quantity, so it's not just a matter of compiling a fixed value off some stack-frame pointer.

Nevertheless, there were some systems that allowed separate compilation. As far as I recall, there were restrictions, such as the unit of compilation (a file, if you like) having to contain only procedures 'at the top level'. They might also have needed some extended syntax (like 'external procedure foo') to tell the compiler that something being referenced was not expected to be defined in the current file.

0
On

Smallest example of non separate compilation, the alone file m.c containing :

int main() {}

compilation : gcc m.cproducing the executable a.out


In C we are free to put all in one file or in several files and also to compile in one or several steps, if this is your question

Example with 2 functions in the alone file m.c :

#include <stdio.h>

void hw()
{
   puts("hello world");
}

int main()
{
   hw();
}

Compilation, we are also free to do in one or several steps

  • gcc m.c producing the executable a.out
  • or gcc -c m.c producing m.o then gcc m.o producing executable a.out

Same program using several files, hw.c containing

#include <stdio.h>
#include "hw.h" /* not mandatory in current case but recommended to check signature compatibility */

void hw()
{
   puts("hello world");
}

and hw.h containing

#ifndef _HW_H
#define _Hw_H
extern void hw();
#endif

and m.c containing

#include "hw.h"

int main()
{
   hw();
}

Compilation, using one or several steps :

  • gcc m.c hw.c producing executable a.out
  • or gcc -c m.c hw.c producing objects m.o and hw.o, then gcc m.o hw.o to produce executable a.out
  • or gcc -c m.c producing objects m.o then gcc -c hw.c producing object hw.o then gcc m.o hw.o to produce executable a.out

It is also possible to create and use a library, here a static library containing only hw.o :

  • gcc -c m.c hw.c producing objects m.o and hw.o (or two gcc commands, one by object)
  • ar rcs hw.a hw.o to make the static library containing hw.o
  • gcc m.o hw.a to produce the executable a.out
0
On

Can anyone provide some basic examples / overview of programming in this nature ?

Have one file called add.c that contains the following code:

int add(int a, int b){
    return a+b;
}

Compile it with:

gcc -c add.c

This creates add.o. Now have a file with following code called main.c:

#include <stdio.h>
int add(int, int); // declares "add", but doesn't implement it!

int main( int argc, char **argv){
    printf("3 + 2 = %d\n", add(3,2));
    return 0;
}

This declares add, but doesn't implement it. It won't run on its own. But you can still compile it with

gcc -c main.c

And then you can link them with:

gcc add.o main.o 

If you run the resulting program (might be called a.exe` or something similar) you will get the following result:

3 + 2 = 5

The advantage of this is that you can modify one of the parts, recompile it, then link it again without having to touch the other parts. If you want a more detailed explanation on the matter, I recommend reading this answer.

1
On

I am not sure what the book means with "The block structure of the Algol-like languages makes this harder by insisting that the whole program comes in one chunk." But I can imagine that an Algol-like language allows or requires that functions and procedures are declared within the main program block, implying that there is only one program block and this will not allow partitioning the program in compilable units, as C does. But again, I don't know what the book means with that statement.

Hypothetical example:

AlgolMain
Begin
    procedure x
    Begin
        ....
    End
    ....
End