Partial Linking In C

Updated: May 01, 2022

Its better to give an example first then explain. Here is the source code of a library called libplic_math.a, it is a very simple library with addition(plic_add), subtraction(plic_sub) and multiplication(plic_mul) functions.

plic_math.h

 1#ifndef __PLIC_MATH__
 2#define __PLIC_MATH__
 3
 4#ifdef __cplusplus
 5extern "C" {
 6#endif
 7
 8  int plic_add(int a, int b);
 9  int plic_sub(int a, int b);
10  int plic_mul(int a, int b);
11
12#ifdef __cplusplus
13}
14#endif
15
16#endif /* __PLIC_MATH__ */

plic_add.c

1#include <stdio.h>
2#include "plic_math.h"
3
4int plic_add(int a, int b) {
5  return a + b;
6}

plic_sub.c

1#include <stdio.h>
2#include "math.h"
3
4int plic_sub(int a, int b) {
5  return a - b;
6}

plic_mul.c

1#include <stdio.h>
2#include "plic_math.h"
3
4int plic_mul(int a, int b) {
5  return a * b;
6}

Makefile

 1CC ?= gcc
 2
 3all: libplic_math.a
 4
 5plic_add.o: plic_add.c plic_math.h
 6	$(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $<
 7
 8plic_sub.o: plic_sub.c plic_math.h
 9	$(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $<
10
11plic_mul.o: plic_mul.c plic_math.h
12	$(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $<
13
14libplic_math.a: plic_add.o plic_sub.o plic_mul.o
15	ar rcUs $@ $^
16
17clean:
18	rm -fr *.o *.a
19
20.PHONY: clean

Here is the source code of another library called libplic_sum.a, this library uses addition(plic_add) function from libplic_math.a library and provides another function to sum the results(plic_sum).

plic_sum.h

 1#ifndef __PLIC_SUM__
 2#define __PLIC_SUM__
 3
 4#ifdef __cplusplus
 5extern "C" {
 6#endif
 7
 8  int plic_sum(int i, int j);
 9
10#ifdef __cplusplus
11}
12#endif
13
14#endif /* __PLIC_MATH__ */

plic_sum.c

 1#include <stdio.h>
 2#include <plic_math.h>
 3#include "plic_sum.h"
 4
 5int plic_sum(int i, int j) {
 6  int n = 0;
 7  int sum = 0;
 8
 9  for(n = i; n < j; n++) {
10    sum = plic_add(sum, n);
11  }
12
13  return sum;
14}

Here is the source code of one program plic_sum_elf which uses sum(plic_sum) function from libplic_sum.a.

plic_sum_elf.c

1#include <stdio.h>
2#include "plic_sum.h"
3
4int main(int argc, char *argv[]) {
5  printf("sum: %d\n", plic_sum(10, 20));
6  return 0;
7}

In plic_sum_elf.c, The function plic_sum from libplic_sum.a depends on plic_add function from libplic_math.a, so in order to generate plic_sum_elf executable, we have to link both libplic_sum.a and libplic_math.a like this,

$ cc -static -o plic_sum_elf plic-sum_elf.c -L/path/to/libplic_sum_dir -lplic_sum -L/path/to/libplic_math_dir -lplic_math

If we omit -lplic_math, then compiler will throw error saying undefined reference to plic_add symbol. Imagine that you are writing one library like libplic_sum.a which itself depends on various libraries like libplic_math.a, The user of your library also need to be aware of all the libraries which your library depends.

It is unnecessary for the downstream user to know all the details about your library in order to link with your library

Partial Linking with ‘-r’ flag

To simplify and make linking easier for your downstream user, you can provide your library as partially linked library, means, when you generate your library, you can instruct the compiler through -r flag 1 to resolve all the symbols required for your library and generate one big object file in order to generate a partially linked library.

$ cc -r -o plic_sum_nodeps.o plic_sum.c -L/path/to/libplic_math_dir -lplic_math
$ ar rcUs libplic_sum_nodeps.a plic_sum_nodeps.o

Now, it becomes easy to generate plic_sum_elf executable, no need to link with libplic_math.a, downstream user only need to link with libplic_sum_nodeps.a

$ cc -static -o plic_sum_elf plic_sum_elf.c -L/pat/to/libplic_sum_nodeps_dir -lplic_sum_nodeps

Here is the Makefile which generates libplic_sum.a, libplic_sum_nodeps.a as well as plic_sum_elf executable.

Makefile

 1CC ?= gcc
 2
 3all: libplic_sum.a libplic_sum_nodeps.a plic_sum_elf
 4
 5plic_sum.o: plic_sum.c plic_sum.h
 6	$(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $< -I../plic-math
 7
 8libplic_sum.a: plic_sum.o
 9	ar rcUs $@ $^
10
11plic_sum_nodeps.o: plic_sum.o
12	$(CROSS_COMPILE)$(CC) $(LDFLAGS) -r -o $@ $< -L../plic-math -lplic_math
13
14libplic_sum_nodeps.a: plic_sum_nodeps.o
15	ar rcUs $@ $^
16
17plic_sum_elf: plic_sum_elf.c libplic_sum_nodeps.a
18	$(CROSS_COMPILE)$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< -L. -lplic_sum_nodeps
19
20clean:
21	rm -fr *.o *.a plic_sum_elf
22
23.PHONY: clean

1

https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html