├── .gitignore ├── README.md ├── bin ├── .gitignore ├── shared │ └── .gitignore └── static │ └── .gitignore ├── meson.build ├── run-meson-dynamic.sh ├── run-meson-shared.sh ├── run-meson-static.sh ├── run-steps.sh ├── src ├── dynamic-library-loader.c ├── main.c ├── meson.build └── tq84 │ ├── add.c │ ├── add.h │ ├── answer.c │ ├── answer.h │ └── meson.build └── steps ├── LD_DEBUG ├── cleanup ├── create-dynamic-library-loader ├── create-object-files ├── create-shared-library ├── create-soname-library ├── create-static-library ├── install-soname-library ├── link-dynamically ├── link-soname-library ├── link-statically ├── list-symbols ├── move-shared-object ├── readelf-relocs ├── show-difference-PIC ├── use-shared-library-LD_LIBRARY_PATH └── use-shared-library-no-LD_LIBRARY_PATH /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | use-shared-object 3 | statically-linked* 4 | dlopen 5 | build-meson-* 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gcc-create-library 2 | 3 | Creating a shared and static library with the gnu compiler. 4 | 5 | ## Running 6 | 7 | Try different `run-*.sh` scripts to build, static, shared, dynamic libraries examples. There's one option with meson and same without it 8 | 9 | The `run-steps.sh` creates the shared objects and exectables without any build system but rather by executing the necessary `gcc` invocations. 10 | 11 | The `run-meson-*.sh` use the *Meson* build system. 12 | 13 | ## Links 14 | 15 | - https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/GCC/create-libraries 16 | 17 | ## Thanks 18 | 19 | [Alberto Fanul](https://github.com/albfan) has contributed the necessary files to demonstrate the Meson build system. 20 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /bin/shared/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /bin/static/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('sum', 'c', 2 | version : '1.0.0', 3 | license : 'GPL') 4 | subdir('src') 5 | -------------------------------------------------------------------------------- /run-meson-dynamic.sh: -------------------------------------------------------------------------------- 1 | rm -rf build-meson-dynamic 2 | meson build-meson-dynamic 3 | ninja -C build-meson-dynamic 4 | LD_LIBRARY_PATH=$(pwd)/build/src/tq84 ./build-meson-dynamic/src/dynamic-library-loader 5 | -------------------------------------------------------------------------------- /run-meson-shared.sh: -------------------------------------------------------------------------------- 1 | rm -rf build-meson-shared 2 | meson build-meson-shared 3 | ninja -C build-meson-shared 4 | ./build-meson-shared/src/use-shared-library 5 | # If you want to see how it locates directly so file 6 | #LD_DEBUG=files ./build/src/use-shared-library 7 | -------------------------------------------------------------------------------- /run-meson-static.sh: -------------------------------------------------------------------------------- 1 | rm -rf build-meson-static 2 | meson build-meson-static 3 | ninja -C build-meson-static 4 | ./build-meson-static/src/statically-linked 5 | -------------------------------------------------------------------------------- /run-steps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | . steps/create-object-files 4 | 5 | . steps/create-static-library 6 | 7 | . steps/link-statically 8 | 9 | . steps/create-shared-library 10 | 11 | . steps/link-dynamically 12 | 13 | . steps/use-shared-library-LD_LIBRARY_PATH 14 | 15 | . steps/move-shared-object 16 | 17 | . steps/use-shared-library-no-LD_LIBRARY_PATH 18 | 19 | . steps/create-dynamic-library-loader 20 | 21 | . steps/create-soname-library 22 | 23 | . steps/link-soname-library 24 | 25 | . steps/install-soname-library 26 | 27 | . steps/LD_DEBUG 28 | 29 | . steps/show-difference-PIC 30 | 31 | . steps/readelf-relocs 32 | 33 | . steps/list-symbols 34 | 35 | . steps/cleanup 36 | -------------------------------------------------------------------------------- /src/dynamic-library-loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Note, add.h and answer.h 6 | // need not be #include'd 7 | 8 | 9 | void* getFunctionPointer(void* lib, const char* funcName) { 10 | // 11 | // Get the function pointer to the function 12 | void* fptr = dlsym(lib, funcName); 13 | if (!fptr) { 14 | fprintf(stderr, "Could not get function pointer for %s\n error is: %s\n\n", funcName, dlerror()); 15 | return NULL; 16 | } 17 | return fptr; 18 | } 19 | 20 | int main(int argc, char* argv[]) { 21 | 22 | // 23 | // Declare the function pointers: 24 | #pragma GCC diagnostic push 25 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" 26 | void (*fptr_null )(int); 27 | #pragma GCC diagnostic pop 28 | void (*fptr_setSummand)(int); 29 | int (*fptr_add )(int); 30 | 31 | 32 | // 33 | // Open the dynamic library 34 | void* tq84_lib = dlopen("libtq84.so", RTLD_LAZY | RTLD_GLOBAL); 35 | 36 | if (!tq84_lib) { 37 | // 38 | // Apparently, the library could not be opened 39 | fprintf(stderr, "Could not open libtq84.so\n"); 40 | exit(1); 41 | } 42 | 43 | 44 | // 45 | // Get the pointers to the functions within the library: 46 | // 47 | // Function doesNotExist does not exist, demonstrate 48 | // calling dlerror() 49 | // 50 | fptr_null =getFunctionPointer(tq84_lib, "doesNotExist"); 51 | fptr_setSummand=getFunctionPointer(tq84_lib, "setSummand"); 52 | fptr_add =getFunctionPointer(tq84_lib, "add" ); 53 | 54 | // 55 | // Call the function via the function pointer 56 | // 57 | fptr_setSummand(42); 58 | 59 | int result = fptr_add(7); 60 | 61 | printf("Result: %d\n", result); 62 | } 63 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tq84/add.h" 3 | #include "tq84/answer.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | 7 | setSummand(5); 8 | 9 | printf("5 + 7 = %d\n", add(7)); 10 | 11 | printf("And the answer is: %d\n", answer()); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | subdir('tq84') 2 | 3 | executable('statically-linked', 'main.c', 4 | link_with: tq84_lib_static) 5 | 6 | executable('use-shared-library', 'main.c', 7 | link_with: tq84_lib_shared) 8 | 9 | 10 | cc = meson.get_compiler('c') 11 | libdl = cc.find_library('dl') 12 | executable('dynamic-library-loader', 'dynamic-library-loader.c', 13 | dependencies: libdl) 14 | -------------------------------------------------------------------------------- /src/tq84/add.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int gSummand; 4 | 5 | 6 | void setSummand(int summand) { 7 | gSummand = summand; 8 | } 9 | 10 | int add(int summand) { 11 | return gSummand + summand; 12 | } 13 | 14 | void __attribute__ ((constructor)) initLibrary(void) { 15 | // 16 | // Function that is called when the library is loaded 17 | // 18 | printf("Library is initialized\n"); 19 | gSummand = 0; 20 | } 21 | void __attribute__ ((destructor)) cleanUpLibrary(void) { 22 | // 23 | // Function that is called when the library is »closed«. 24 | // 25 | printf("Library is exited\n"); 26 | } 27 | -------------------------------------------------------------------------------- /src/tq84/add.h: -------------------------------------------------------------------------------- 1 | 2 | void setSummand(int summand); 3 | int add(int summand); 4 | -------------------------------------------------------------------------------- /src/tq84/answer.c: -------------------------------------------------------------------------------- 1 | #include "add.h" 2 | 3 | int answer() { 4 | 5 | setSummand(20); 6 | return add(22); // Will return 42 (=20+22) 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/tq84/answer.h: -------------------------------------------------------------------------------- 1 | int answer(); 2 | -------------------------------------------------------------------------------- /src/tq84/meson.build: -------------------------------------------------------------------------------- 1 | runtime_sources = ['add.c', 'add.h', 'answer.c', 'answer.h'] 2 | 3 | tq84_lib_static = static_library('runtime', 4 | runtime_sources, 5 | install : true) 6 | 7 | # We use libtool-version numbers because it's easier to understand. 8 | # Before making a release, the libruntime_so_* 9 | # numbers should be modified. The components are of the form C:R:A. 10 | # a) If binary compatibility has been broken (eg removed or changed interfaces) 11 | # change to C+1:0:0. 12 | # b) If interfaces have been changed or added, but binary compatibility has 13 | # been preserved, change to C+1:0:A+1 14 | # c) If the interface is the same as the previous version, change to C:R+1:A 15 | libruntime_lt_c=1 16 | libruntime_lt_r=0 17 | libruntime_lt_a=0 18 | 19 | libruntime_so_version = '@0@.@1@.@2@'.format((libruntime_lt_c - libruntime_lt_a), 20 | libruntime_lt_a, 21 | libruntime_lt_r) 22 | 23 | tq84_lib_shared = shared_library('runtime', 24 | runtime_sources, 25 | version : libruntime_so_version, 26 | install : true) 27 | -------------------------------------------------------------------------------- /steps/LD_DEBUG: -------------------------------------------------------------------------------- 1 | # 2 | # Use LD_DEBUG 3 | # set it to libs to display library search paths 4 | # 5 | LD_DEBUG=libs bin/use-shared-library 6 | 7 | # 8 | # Setting LD_DEBUG to files to display progress for input files 9 | # 10 | LD_DEBUG=files bin/use-shared-library 11 | 12 | # 13 | # Setting LD_DEBUG to reloc to display relocation processing 14 | # 15 | LD_DEBUG=reloc bin/use-shared-library 16 | 17 | LD_DEBUG=symbols bin/use-shared-library 18 | -------------------------------------------------------------------------------- /steps/cleanup: -------------------------------------------------------------------------------- 1 | sudo rm /usr/lib/libtq84* 2 | rm bin/*.o 3 | rm bin/static/*.o 4 | rm bin/shared/*.o 5 | rm bin/statically-linked 6 | rm bin/use-shared-library 7 | -------------------------------------------------------------------------------- /steps/create-dynamic-library-loader: -------------------------------------------------------------------------------- 1 | # 2 | # Using dl functions 3 | # 4 | gcc src/dynamic-library-loader.c -ldl -o bin/dynamic-library-loader 5 | 6 | # 7 | # As long as /usr/lib/libtq84.so exists, LD_LIBRARY_PATH 8 | # needs not be set 9 | # 10 | bin/dynamic-library-loader 11 | -------------------------------------------------------------------------------- /steps/create-object-files: -------------------------------------------------------------------------------- 1 | 2 | gcc -c src/main.c -o bin/main.o 3 | 4 | # 5 | # Create the object files for the static library (without -fPIC) 6 | # 7 | gcc -c src/tq84/add.c -o bin/static/add.o 8 | gcc -c src/tq84/answer.c -o bin/static/answer.o 9 | 10 | # 11 | # object files for shared libraries need to be compiled as position independent 12 | # code (-fPIC) because they are mapped to any position in the address space. 13 | # 14 | gcc -c -fPIC src/tq84/add.c -o bin/shared/add.o 15 | gcc -c -fPIC src/tq84/answer.c -o bin/shared/answer.o 16 | -------------------------------------------------------------------------------- /steps/create-shared-library: -------------------------------------------------------------------------------- 1 | gcc -shared bin/shared/add.o bin/shared/answer.o -o bin/shared/libtq84.so 2 | 3 | # 4 | # In order to create a shared library, position independent code 5 | # must be generated. This can be achieved with `-fPIC` flag when 6 | # c-files are compiled. 7 | # 8 | # If the object files are created without -fPIC (such as when the static object files are produces), then 9 | # gcc -shared bin/static/add.o bin/static/answer.o -o bin/shared/libtq84.so 10 | # produces this error: 11 | # /usr/bin/ld: bin/tq84.o: relocation R_X86_64_PC32 against symbol `gSummand' can not be used when making a shared object; recompile with -fPIC 12 | # 13 | -------------------------------------------------------------------------------- /steps/create-soname-library: -------------------------------------------------------------------------------- 1 | gcc -shared bin/shared/add.o bin/shared/answer.o -Wl,-soname,libtq84Soname.so.1 -o bin/shared/libtq84Soname.so.1.0.1 2 | ln -s libtq84Soname.so.1.0.1 bin/shared/libtq84Soname.so 3 | -------------------------------------------------------------------------------- /steps/create-static-library: -------------------------------------------------------------------------------- 1 | ar rcs bin/static/libtq84.a bin/static/add.o bin/static/answer.o 2 | -------------------------------------------------------------------------------- /steps/install-soname-library: -------------------------------------------------------------------------------- 1 | sudo cp bin/shared/libtq84Soname.so.1.0.1 /usr/lib 2 | sudo chmod 755 /usr/lib/libtq84Soname.so.1.0.1 3 | 4 | sudo ldconfig -v -n /usr/lib | grep tq84 5 | 6 | # lsconfig basically created the symbolic link 7 | # from /usr/lib/libtq84Soname.so.1 to /usr/lib/libtq84Soname.so.1.0.1: 8 | ls -ltr /usr/lib | tail -10 9 | -------------------------------------------------------------------------------- /steps/link-dynamically: -------------------------------------------------------------------------------- 1 | # Note the order: 2 | # -ltq84-shared needs to be placed AFTER main.c 3 | 4 | gcc bin/main.o -Lbin/shared -ltq84 -o bin/use-shared-library 5 | -------------------------------------------------------------------------------- /steps/link-soname-library: -------------------------------------------------------------------------------- 1 | gcc -Lbin/shared bin/main.o -ltq84Soname -o bin/use-shared-library-soname 2 | 3 | # Alterntatively 4 | # gcc -Lbin src/main.c -ltq84Soname -o bin/use-shared-library-soname 5 | -------------------------------------------------------------------------------- /steps/link-statically: -------------------------------------------------------------------------------- 1 | gcc bin/main.o -Lbin/static -ltq84 -o bin/statically-linked 2 | -------------------------------------------------------------------------------- /steps/list-symbols: -------------------------------------------------------------------------------- 1 | # 2 | # TODO 3 | # 4 | # List symbols in object files 5 | # 6 | nm bin/static/add.o 7 | nm bin/shared/libtq84Soname.so 8 | nm bin/statically-linked 9 | nm bin/dynamic-library-loader 10 | -------------------------------------------------------------------------------- /steps/move-shared-object: -------------------------------------------------------------------------------- 1 | # 2 | # Moving the shared object to a standard location 3 | # 4 | sudo mv bin/shared/libtq84.so /usr/lib 5 | sudo chmod 755 /usr/lib/libtq84.so 6 | -------------------------------------------------------------------------------- /steps/readelf-relocs: -------------------------------------------------------------------------------- 1 | # 2 | # Similar to objdump but more detailed: 3 | # 4 | readelf --relocs bin/shared/add.o 5 | readelf --relocs bin/static/add.o 6 | -------------------------------------------------------------------------------- /steps/show-difference-PIC: -------------------------------------------------------------------------------- 1 | objdump --disassemble bin/shared/add.o | sed -n '//,/^$/p' 2 | objdump --disassemble bin/static/add.o | sed -n '//,/^$/p' 3 | -------------------------------------------------------------------------------- /steps/use-shared-library-LD_LIBRARY_PATH: -------------------------------------------------------------------------------- 1 | # If the shared object is in a non standard location, we 2 | # need to tell where it is via the LD_LIBRARY_PATH 3 | # environment variable 4 | # 5 | # ./use-shared-object 6 | # ./use-shared-object: error while loading shared libraries: libtq84.so: cannot open shared object file: No such file or directory 7 | 8 | LD_LIBRARY_PATH=$(pwd)/bin/shared bin/use-shared-library 9 | -------------------------------------------------------------------------------- /steps/use-shared-library-no-LD_LIBRARY_PATH: -------------------------------------------------------------------------------- 1 | # 2 | # Since the shared library was copied to a standard 3 | # location (/usr/lib), the environment variable LD_LIBRARY_PATH 4 | # does not need to be set to execute the executable: 5 | 6 | bin/use-shared-library 7 | --------------------------------------------------------------------------------