Object Code Archives/Static Libraries

Code Bases Become Larger (1)

New feature in our code base 🤡 …

  • more flexible greeting, in a separate file pair, hello-flexible.{h,c}. Takes the name to be greeted from the commandline. (See Object Code Archives/Static Libraries for details on commandline argument processing.)

  • used by hello-second.c

Users

Valuable and rock-stable code

#include "hello.h"

int main(void)
{
    hello();   // <--- HERE
    return 0;
}
#include "hello-flexible.h"
#include <stdio.h>

int main(int argc, char* argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <whom>\n", argv[0]);
        return 1;
    }

    hello_flexible(argv[1]);   // <--- HERE: new functionality used
    return 0;
}
#ifndef HELLO_H
#define HELLO_H

void hello(void);

#endif
#include "hello.h"
#include <stdio.h>

void hello(void)
{
    printf("Hello World\n");
}
#ifndef HELLO_FLEXIBLE_H
#define HELLO_FLEXIBLE_H

void hello_flexible(const char* whom);

#endif
#include "hello-flexible.h"
#include <stdio.h>

void hello_flexible(const char* whom)
{
    printf("Hello %s\n", whom);
}

Code Bases Become Larger (2)

Build instructions need to be updated

  • Build hello-flexible.o from hello-flexible.c

  • Link hello-second against hello-flexible.o (and not hello.o)

Smaller

Larger

digraph foo {
   "hello.o" -> "hello.c";
   "hello-first.o" -> "hello-first.c";
   "hello-second.o" -> "hello-second.c";
   "hello-first" -> "hello-first.o";
   "hello-first" -> "hello.o";
   "hello-second" -> "hello-second.o";
   "hello-second" -> "hello.o";
   "all" -> "hello-first";
   "all" -> "hello-second";
}
digraph foo {
   "hello.o" -> "hello.c";
   "hello-flexible.o" -> "hello-flexible.c";
   "hello-first.o" -> "hello-first.c";
   "hello-second.o" -> "hello-second.c";
   "hello-first" -> "hello-first.o";
   "hello-first" -> "hello.o";
   "hello-second" -> "hello-second.o";
   "hello-second" -> "hello-flexible.o";
   "all" -> "hello-first";
   "all" -> "hello-second";
}
.PHONY: all
all: hello-first hello-second

hello.o: hello.c
	gcc -c -o hello.o hello.c

hello-flexible.o: hello-flexible.c
	gcc -c -o hello-flexible.o hello-flexible.c

hello-first.o: hello-first.c
	gcc -c -o hello-first.o hello-first.c

hello-second.o: hello-second.c
	gcc -c -o hello-second.o hello-second.c 

hello-first: hello-first.o hello.o
	gcc -o hello-first hello-first.o hello.o

hello-second: hello-second.o hello-flexible.o
	gcc -o hello-second hello-second.o hello-flexible.o

Problem: Structure

  • Two similar routines with similar purpose in different implementation files

  • ⟶ Frontend programs hello-first and hello-second must know which one they have to link against

  • ⟶ cannot easily rename a single file, or move implementations around, from one file into another

Solution: Libraries

  • Archives of object code

  • Executables are linked against those instead

  • ⟶ single point of dependency

Building a library from two object files, hello.o and hello-flexible.o

$ ar cq libgreet.a hello.o hello-flexible.o

What’s in it?

$ nm libgreet.a

hello.o:
0000000000000000 T hello
                 U puts

hello-flexible.o:
0000000000000000 T hello_flexible
                 U printf

Linking a executable against the library

$ gcc -o hello-second hello-second.o libgreet.a

Build Instructions: Building A Library

digraph foo {
   "hello.o" -> "hello.c";
   "hello-flexible.o" -> "hello-flexible.c";
   "libgreet.a" -> "hello.o";
   "libgreet.a" -> "hello-flexible.o";
   "hello-first.o" -> "hello-first.c";
   "hello-second.o" -> "hello-second.c";
   "hello-first" -> "hello-first.o";
   "hello-first" -> "libgreet.a";
   "hello-second" -> "hello-second.o";
   "hello-second" -> "libgreet.a";
   "all" -> "hello-first";
   "all" -> "hello-second";
}
.PHONY: all
all: hello-first hello-second

hello.o: hello.c
	gcc -c -o hello.o hello.c

hello-flexible.o: hello-flexible.c
	gcc -c -o hello-flexible.o hello-flexible.c

libgreet.a: hello.o hello-flexible.o
	ar cq libgreet.a hello.o hello-flexible.o

hello-first.o: hello-first.c
	gcc -c -o hello-first.o hello-first.c

hello-second.o: hello-second.c
	gcc -c -o hello-second.o hello-second.c 

hello-first: hello-first.o libgreet.a
	gcc -o hello-first hello-first.o libgreet.a

hello-second: hello-second.o libgreet.a
	gcc -o hello-second hello-second.o libgreet.a