GNU/Linux Application Programming (Programming Series)
Let s first look at the simplest type of library development in GNU/Linux. The static library is linked statically with the application image. This means that once the image is built, the external library is not necessary to be present for the image to execute properly as its part of the resulting image.
To demonstrate the construction of libraries, let s look at a sample set of source files. We ll build a simple random number generator wrapper library using the GNU/Linux random functions. Let s first look at the API for our library. The header file,
Listing 6.1: Random Number Wrapper API Header (on the CD-ROM at ./source/ch6/_statshrd/randapi.h)
|
1: /* 2: * randapi.h 3: * 4: * Random Functions API File 5: * 6: */ 7: 8: 9: #ifndef __RAND_API_H 10: #define __RAND_API_H 11: 12: extern void initRand(void); 13: 14: extern float getSRand(void); 15: 16: extern int getRand(int max); 17: 18: #endif /* __RAND_API_H */
|
Our API consists of three functions. The first function, initrand , is an initialization function that prepares our wrapper libraries for use. It must be called once prior to calling any of the random functions. Function getSRand() returns a random floating-point value between 0.0 and 1.0. Finally, function getRand(x) returns a random integer between 0 and ( x “1).
While this functionality could be implemented in a single file, we ll split it between two files for the purposes of demonstration. The next file, initrand.c , provides the initialization function for the wrapper API (see Listing 6.2). The single function, initRand() , simply initializes the random number generator using the current time as a seed.
Listing 6.2: Random Number Initialization API (on the CD-ROM at ./source/ch6/_statshrd/initapi.c )
|
1: /* 2: * Random Init Function API File 3: * 4: */ 5: 6: #include <stdlib.h> 7: #include <time.h> 8: 9: 10: /* 11: * initRand() initializes the random number generator. 12: * 13: */ 14: 15: void initRand() 16: { 17: time_t seed; 18: 19: seed = time(NULL); 20: 21: srand(seed); 22: 23: return; 24: }
|
Our final API file,
Listing 6.3: Random Number Wrapper Functions (on the CD-ROM at ./source/ch6/_statshrd/randapi.c )
|
1: /* 2: * randapi.c 3: * 4: * Random Functions API File 5: * 6: */ 7: 8: #include <stdlib.h> 9: 10: 11: /* 12: * getSRand() returns a number between 0.0 and 1.0. 13: * 14: */ 15: 16: float getSRand() 17: { 18: float randvalue; 19: 20: randvalue = ((float)rand() / (float)RAND_MAX); 21: 22: return randvalue; 23: } 24: 25: 26: /* 27: * getRand() returns a number between 0 and max-1. 28: * 29: */ 30: 31: int getRand(int max) 32: { 33: int randvalue; 34: 35: randvalue = (int)((float)max * rand() / (RAND_MAX+1.0)); 36: 37: return randvalue; 38: }
|
That s it for our API. Note that both
Listing 6.4: Test Application for the Wrapper Function API (on the CD-ROM at ./source/ch6/statshrd/test.c )
|
1: #include "randapi.h" 2: 3: #define ITERATIONS 1000000L 4: 5: int main() 6: { 7: long i; 8: long isum; 9: float fsum; 10: 11: /* Initialize the random number API */ 12: initRand(); 13: 14: /* Find the average of getRand(10) returns (0..9) */ 15: isum = 0L; 16: for (i = 0 ; i < ITERATIONS ; i++) { 17: 18: isum += getRand(10); 19: 20: } 21: 22: printf("getRand() Average %d\n", (int)(isum / ITERATIONS)); 23: 24: 25: /* Find the average of getSRand() returns */ 26: fsum = 0.0; 27: for (i = 0 ; i < ITERATIONS ; i++) { 28: 29: fsum += getSRand(); 30: 31: } 32: 33: printf("getSRand() Average %f\n", (fsum / (float)ITERATIONS)); 34: 35: return; 36: }
|
If we wanted to build all source files discussed here and integrate them into a single image, we could do the following:
$ gcc initapi.c randapi.c test.c -o test
This would compile all three files and then link them together into a single image called test . This use of gcc provides not only compilation of the source files, but also linking to a single image. Upon executing the image, we d see the averages for each of the random number functions:
$ ./test getRand() Average 4 getSRand() Average 0.500001 $
As expected, the random number generated generates an average value that s in the middle of the random number range.
Let s now get back to the subject of libraries, and rather than build the entire source together, we ll build a library for our random number functions. This is achieved using the ar utility (archive). Below, we ll demonstrate the building of our static library along with the construction of the final image.
$ gcc -c -Wall initapi.c $ gcc -c -Wall randapi.c $ ar -cru libmyrand.a initapi.o randapi.o $
In this example, we first compile our two source files (
We now have a new file called libmyrand.a , which is our static library containing two objects: initapi.o and randapi.o . Let s now look at how we can build our application using this static library. Consider the following:
$ gcc test.c -L. -lmyrand -o test $ ./test getRand() Average 4 getSRand() Average 0.499892 $
Here we use gcc to first compile the file
Now that we see how to create a library and use it to build a simple application, let s return to the ar utility to see what other uses it has. We can inspect a static library to see what s contained within it by using the -t option:
$ ar -t libmyrand.a initapi.o randapi.o $
If desired, we can also remove objects from a static library. This is done using the -d option, such as:
$ ar -d libmyrand.a initapi.o $ ar -t libmyrand.a randapi.o $
It s important to note that ar won t actually show a failure for a delete. To see an error message if the delete fails, add a -v option as shown below:
$ ar -d libmyrand.a initapi.o $ ar -dv libmyrand.a initapi.o No member named
Категории