HOW TO CREATE A LIBRARY OF YOUR OWN C FUNCTIONS
After you have written the canonical "Hello World!" program or one that blinks LEDs, you will probably start to collect a number of home-grown functions that you use repeatedly. You've probably added the source for these to each of your programs that use them, but find that updating them is time-consuming and prone to error or worse, allows the code for your functions to diverge over time.
Now is the time to take the next step and create a library that contains all your functions in a form that can be linked at compile time. This means a single central library of your functions with the ability for any program to link and use them. At the same time you should create a set of corresponding header files that, as a minimum, declare your function names.
This page does not explain the intricacies of separating function source code and header files, nor details on using extern.
THINGS TO CONSIDER
You need to decide whether to create a static or dynamic library.
- A dynamic library is a standalone collection of executable functions that can be referenced by a program and called upon when the program requires them - the operating system deals with this. If the program is moved to another system or the library deleted, moved or renamed then the program will not work as it cannot find the functions in the location expected. However, with dynamic linking if you make changes to the library, then they will be used when the program is run as the functions are accessed at run time.
- A static library is merged into the executable file that GCC creates. This means that the program is entirely self-supporting and contains everything it needs to run, either on the system on which it was created, or any other compatible one. The downside however, is that any changes you make to your library are not accessible to the program because the older library is included. You would need to recompile and link your program to incorporate the changes in the updated library.
Here, we will use dynamically-linked libraries. Dynamic libraries have a .so suffix, static ones a .a suffix.
Sort out and correct your C functions, adding extern if you are splitting them up and need to share variables. extern means that some other file will define the variable but this function needs to be able to reference it. An extern variable declaration can be placed in, say, a header file and the actual definition added (without the extern or static attributes) to a source file somewhere else.
Create a C header file (.h) and put in it a declaration of the function with its correct return and argument types. If the function uses any #defines then put them in the header file with protection around them to stop attempts to #define them more than once. Use #ifndef something-unique and #endif to prevent duplicate #defines and put a #define something-unique just before the #endif to prevent any attempts to redefine them later. You must decide what to use for something-unique as it must not conflict with anything else associated with your program or anything that the system uses. There's a good explanation here.
Compile your C function, which for this example is called func.c, with the options for compile-only and position-independent-code:
gcc func.c -c -fpic
This creates a file func.o that contains object code.
Create a shared library from the object file. Library files usually begin with lib. If they do, this means that when you compile a program you can link it with your library by specifying -lname rather than giving the whole name - the lib and .so are implied.
gcc -shared -o libfunc.so func.o
This creates a library called libfunc.so. The linker needs to be told where to find libraries; you have a number of options. You can:
- use the gcc option -L followed immediately by the path to libfunc.so when you compile your program
- add to the environment variable LD_LIBRARY_PATH the path to the directory where your library is located
- copy or move your library to one of the default library folders, e.g. /usr/local/lib. This requires some additional work that is explained later in Step 6, but continue with the next step for now.
You can now compile a program and link it with your library. The linker presumes that the library name ends with .so, so you can omit that along with the lib part. The following three methods are all equivalent:
If your library is in your home directory:
gcc prog.c -o prog -lfunc -L/home/~
If you have added the path to the directory where your library is located to the environment variable LD_LIBRARY_PATH:
gcc prog.c -o prog -lfunc
If you have copied the library to a default directory and updated the config file and cache:
gcc prog.c -o prog -lfunc
At this point you have compiled your C function, created a library and put it in a default location or changed the LD_LIBRARY_PATH to point to the it. The next step is to put the header file in the correct location. The best place is in /usr/include. Using this location means you can put #include <func.h> in your C source rather than #include "potentially-long-path-to-your-file/func.h".
Once your header file is completed and tested, you can simply copy it to its final location:
cp func.h /usr/include
This section explains how to make your library available across all users on the system. You will need root privileges for this - prefix each command with sudo. Copy the library to /usr/local/lib. Note that /usr/lib is reserved for libraries that come with the operating system while /usr/local/lib is intended for third party libraries like yours.
sudo cp /home/~/libfunc.so /usr/local/lib
Change the mode so that other users have read and execute access but not write:
sudo chmod 0755 /usr/local/lib/libfunc.so
Create a link to the new library and update the cache so that it is available for use immediately:
The last step is to check that your library is configured for use. You can do this using the ldconfig -p command and piping the output to grep to filter it. If your library is not listed then there's a problem with its name, location or an error with the ldconfig command.
ldconfig -p | grep libfunc
libfunc.so (libc6,hard-float) => /usr/local/lib/libfunc.so