Partial Linking In C¶
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #ifndef __PLIC_MATH__ #define __PLIC_MATH__ #ifdef __cplusplus extern "C" { #endif int plic_add(int a, int b); int plic_sub(int a, int b); int plic_mul(int a, int b); #ifdef __cplusplus } #endif #endif /* __PLIC_MATH__ */
plic_add.c
1 2 3 4 5 6 #include <stdio.h> #include "plic_math.h" int plic_add(int a, int b) { return a + b; }
plic_sub.c
1 2 3 4 5 6 #include <stdio.h> #include "math.h" int plic_sub(int a, int b) { return a - b; }
plic_mul.c
1 2 3 4 5 6 #include <stdio.h> #include "plic_math.h" int plic_mul(int a, int b) { return a * b; }
Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CC ?= gcc all: libplic_math.a plic_add.o: plic_add.c plic_math.h $(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $< plic_sub.o: plic_sub.c plic_math.h $(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $< plic_mul.o: plic_mul.c plic_math.h $(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $< libplic_math.a: plic_add.o plic_sub.o plic_mul.o ar rcUs $@ $^ clean: rm -fr *.o *.a .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 2 3 4 5 6 7 8 9 10 11 12 13 14 #ifndef __PLIC_SUM__ #define __PLIC_SUM__ #ifdef __cplusplus extern "C" { #endif int plic_sum(int i, int j); #ifdef __cplusplus } #endif #endif /* __PLIC_MATH__ */
plic_sum.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> #include <plic_math.h> #include "plic_sum.h" int plic_sum(int i, int j) { int n = 0; int sum = 0; for(n = i; n < j; n++) { sum = plic_add(sum, n); } return sum; }
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 2 3 4 5 6 7 #include <stdio.h> #include "plic_sum.h" int main(int argc, char *argv[]) { printf("sum: %d\n", plic_sum(10, 20)); return 0; }
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 CC ?= gcc all: libplic_sum.a libplic_sum_nodeps.a plic_sum_elf plic_sum.o: plic_sum.c plic_sum.h $(CROSS_COMPILE)$(CC) $(CFLAGS) -fPIC -c -o $@ $< -I../plic-math libplic_sum.a: plic_sum.o ar rcUs $@ $^ plic_sum_nodeps.o: plic_sum.o $(CROSS_COMPILE)$(CC) $(LDFLAGS) -r -o $@ $< -L../plic-math -lplic_math libplic_sum_nodeps.a: plic_sum_nodeps.o ar rcUs $@ $^ plic_sum_elf: plic_sum_elf.c libplic_sum_nodeps.a $(CROSS_COMPILE)$(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< -L. -lplic_sum_nodeps clean: rm -fr *.o *.a plic_sum_elf .PHONY: clean