11.5. Archiving Modules: arA medium-sized C project typically uses several hundred object modules. Specifying this many object modules on a command can be tedious and error prone, so I recommend that you learn how to use the GNU archive utility, ar, to organize and group your object modules. An archive utility is sometimes known as a librarian. It allows you to perform the following tasks:
Figure 11-2 is a synopsis of ar.
When a set of object modules is stored in an archive file, it may be accessed from the gcc compiler by simply supplying the name of the archive file as an argument. Any object modules that are needed from the archive file are automatically linked as necessary. This greatly reduces the number of parameters to these utilities when linking large numbers of object modules. 11.5.1. Creating or Adding a FileAn archive is automatically created when the first file is added. To add a file to (or replace a file in) a named archive, use the ar utility with the r option (Figure 11-3).
This option adds all of the specified files to the archive file archiveName, replacing files if they already exist. If the archive file doesn't exist, it is automatically created. The name of the archive should have a ".a" suffix. 11.5.2. Appending a FileTo append a file to a named archive, use the ar utility with the q option (Figure 11-4).
This option appends all of the specified files to the archive file archiveName, regardless of whether they already exist. If the archive file doesn't exist, it is automatically created. This option is handy if you know that the file isn't already present, as it allows ar to avoid searching through the archive. 11.5.3. Obtaining a Table of ContentsTo obtain a table of contents of an archive, use the ar utility with the t option (Figure 11-5).
11.5.4. Deleting a FileTo delete a list of files from an archive, use the ar utility with the d option (Figure 11-6).
11.5.5. Extracting a FileTo copy a list of files from an archive to the current directory, use the ar utility with the x option (Figure 11-7). If you don't specify a list of files, then all of the files in the archive are copied.
11.5.6. Maintaining an Archive from the Command LineHere is an example that illustrates how an archive may be built and manipulated from the command line, using the object modules built earlier in this chapter. First, I built an archive file called "string.a" to hold all of my string-related object modules. Next, I added each module in turn using the r option. Finally, I demonstrated the various different ar options: $ gcc -c reverse.c palindrome.c main2.c ...create object files. $ ls *.o ...confirm. main2.o palindrome.o reverse.o $ ar r string.a reverse.o palindrome.o ...add to an archive. ar: creating string.a $ ar t string.a ...obtain a table of contents. reverse.o palindrome.o $ gcc main2.o string.a -o main2 ...link the object modules. $ main2 ...execute the program. palindrome ("cat") = 0 palindrome ("noon") = 1 $ ar d string.a reverse.o ...delete a module. $ ar t string.a ...confirm deletion. palindrome.o $ ar r string.a reverse.o ...put it back again. $ ar t string.a ...confirm addition. palindrome.o reverse.o $ rm palindrome.o reverse.o ...delete originals. $ ls *.o ...confirm. main2.o $ ar x string.a reverse.o ...copy them back again. $ ls *.o ...confirm. main2.o reverse.o $ _ 11.5.7. Indexing ArchivesThe ar utility does not maintain any particular order in an archive file. This is usually fine, because gcc and its linker are able to extract object modules and resolve external references regardless of order. However, you could have a problem if functions in the archive call each other, depending on the order in which they are found by the linker. If object module A contains a function that calls a function in object module B, then B must appear before A in the archive. Even if you maintained your ordering properly, you could get into a circular organization where one of the modules couldn't find another one and you would wind up with an error about unresolved references to functions that you know you have in your library. You can help the linker to resolve out-of-order object modules by adding a table of contents to each archive. This also speeds up the linking process, since it doesn't have to search through the archive for each function. On UNIX systems this is often done with the ranlib utility. On Linux, you need only add the s option to your ar command line, like this: $ ar rs string.a reverse.o palindrome.o 11.5.8. Shared LibrariesStatic libraries work just fine for many applications. However, as processor speed increases and the prices of disk and memory come down, code has been allowed to become more complex. Programs linked with large archive libraries will result in very large executable files (a small program that creates a single X window can be a megabyte when linked with the required X libraries). To reduce the size of your generated object code, you can link your program with a shared library instead. A shared (or dynamic) library is associated with a compiled program, but its functions are loaded in dynamically as they are needed rather than all at once at load time. The resulting object code is smaller, because it does not include the object code from the library as it does when linked with a static library. The one disadvantage of using a shared library is that your object code will have been written for a specific version of the library. If bug fixes are made but no interface changes are made, then your program will benefit from the newer library that works better. However, if calling interface changes are made, problems may (probably will) result when your program links with the newer version of the library at run time. It is therefore important to be aware of changes in supporting libraries when writing an application. The gcc command honors arguments (that are passed to the linker) to allow you to specify it to build a shared library rather than a static library. These arguments are -shared and -static. |