Linux ar command: use it to create static libraries

The Linux "ar" command is used to create function libraries when you develop software. This tutorial will show you how to create a static library, modify it and use it in a program, as well as to complete with a sample code.

The ar command is a true veteran: it exists since 1971. The name refers to the original intended use of the tool, which was to create storage files.

A storage file is a single file that acts as a container for other files. Sometimes for many other files. These can be added, deleted or extracted. People looking for that type of functionality no longer use the ar command. That role has been assumed by other utilities such as the tar command.

However, the command is still used for some specialized purposes. It is used to create static libraries. These libraries are used in software development. And it is also used to create package files such as the ".deb" files used in the Debian Linux distribution and its derivatives such as Ubuntu.

We will follow the steps necessary to create and modify a static library, and demonstrate how to use the library in a program. To do that, we need a requirement for the static library to be met. The purpose of this library is to encode text strings and decode encoded text.

You should keep in mind that this is a quick trick for demonstration purposes. Do not use this encryption for anything of value. It is the simplest replacement cipher in the world, where A becomes B, B becomes C, and so on.

The cipher_encode () and cipher_decode () functions

We will work in a directory called «library», and then we will create a subdirectory called «test».

We have two files in this directory. In a text file called cipher_encode.c we have the cipher_encode () function:

 void cipher_encode(char *text)
{
 for (int i=0; text(i) != 0x0; i++) {
   text(i)++;
 }

} // end of cipher_encode

The corresponding cipher_decode () function is in a text file called cipher_decode.c:

void cipher_decode(char *text)
{
 for (int i=0; text(i) != 0x0; i++) {
   text(i)--;
 }

} // end of cipher_decode

Files that contain programming instructions are called source code files. We are going to make a library file called libcipher.a. It will contain the compiled versions of these two source code files.

We will also create a short text file called libcipher.h. This is a header file that contains the definitions of the two functions in our new library.

Anyone with the library and the header file can use both functions in their own programs. You do not need to reinvent the wheel and rewrite the functions; You simply use the copies in our library.

Compilation of the cipher_encode.c and cipher_decode.c files

To compile the source code files, we will use «gcc», the standard GNU compiler. The -c (compile, no link) option tells gcc to compile the files and then stop. So it produces an intermediary file of each source code file, called an object file.

The gcc linker generally takes all object files and links them to create an executable program. We are skipping that step using the -c option. So we need object files.

Let's verify that we have the files that we believe we have.

ls -l

The two source code files are present in this directory. Let's use gcc to compile them into object files.

gcc -c cipher_encode.c
gcc -c cipher_decode.c

There should be no exit from the gcc if everything goes well.

This generates two object files with the same name as the source code files, but with extensions ".o". These are the files we need to add to the library file.

ls -l

Creating the libcipher.a library

To create the library file, which is actually a storage file, we will use ar.

We are using the -c (create) option to create the library file, the -r (add with replace) option to add them to the library file. And the -s (index) option to create an index of the files within the library.

Let's call the library file libcipher.a. We provide that name on the command line, along with the names of the object files that we are going to add.

ar -crs libcipher.a cipher_encode.o cipher_decode.o

If we list the files in the directory, we will see that we now have a libcipher.a file.

ls -l

If we use the -t (table) option with the ar command, we can see the modules inside the library file.

ar -t libcipher.a

Create the libcipher.h header file

The libcipher.h file will be included in any program that uses the libcipher.a library. The libcipher.h file must contain the definition of the functions that are in the library.

To create the header file, we must write the function definitions in a text editor such as gedit. Name the file as "libcipher.h" and save it in the same directory as the libcipher.a file.

void cipher_encode(char *text);
void cipher_decode(char *text);

Using the libcipher library

The only sure way to test our new library is to write a small program to use it. First, we will make a directory called «test».

mkdir test

We will copy the library and header files to the new directory.

cp libcipher.* ./test

We will change to the new directory.

cd test

Let's see if our two files are here.

ls -l

We need to create a small program that can use the library and show that it works as expected. Write the following lines of text in an editor. Now, save the content of the editor in a file called «test.c» in the «test» directory.

#include 
#include 

#include "libcipher.h"

int main(int argc, char *argv())
{
 char text()="Amamos Linux";

 puts(text);

 cipher_encode(text);
 puts(text);

 cipher_decode(text);
 puts(text);

 exit (0);

} // end of main

The program flow is very simple:

  • Include the libcipher.h file so you can see the definitions of library functions.
  • Create a string called "text" and store the words "We love Linux" in it.
  • Print that string on the screen.
  • Call the cipher_encode () function to encode the string and print the encoded string on the screen.
  • Call cipher_decode () to decode the string and print the decoded string on the screen.

To generate the program called test, we need to compile the test.c program and link it to the library. The -o (output) option tells the gcc how to call the executable program it generates.

gcc test.c libcipher.a -o test

If gcc silently returns you to the command prompt, everything is fine. Now let's try our program. It is the moment of truth:

./test

And we see the expected departure. The test program prints the plain text. It also prints the encrypted text and then prints the decrypted text. And you are using the functions within our new library. So our library is working.

We succeeded. But why stop there?

Ar command: Add another module to the library

Let's add another function to the library. A function that the programmer can use to display the version of the library he is using. We will have to create the new function, compile it and add the new object file to the existing library file.

Write the following lines in an editor. Save the content in a file called cipher_version.c, in the library directory.

#include 

void cipher_version(void)
{
 puts("Este archivo es :: MUY INSEGURO Cipher Library");
 puts("Version 0.0.1 Alphan");

} // end of cipher_version

We need to add the definition of the new function to the libcipher.h header file. Add a new line at the end of that file, so it looks like this:

void cipher_encode(char *text);
void cipher_decode(char *text);
void cipher_version(void);

Save the modified file as "libcipher.h."

We need to compile the cipher_version.c file so that we have a cipher_version.o object file.

gcc -c cipher_version.c

This creates a cipher_version.o file. We can add the new object file to the libcipher.a library with the following command. The -v (detailed) option usually makes ar tell us what he has done.

ar -rsv libcipher.a cipher_version.o

The new object file is added to the library file. the ar command prints the confirmation. "A" means "aggregate."

We can use the -t (table) option to see which modules are inside the library file.

ar -t libcipher.a

Now there are three modules within our library file. Let's use the new function we just did.

Using the cipher_version () function

Let's remove the old library and header files from the "test" directory, copy the new files and then return to the test directory.

We will delete the previous versions of the files.

rm ./test/libcipher.*

We will copy the new versions in the test directory.

cp libcipher.* ./test

Now we will change to the test directory.

cd test

And now we can modify the test.c program to use the new library function.

We need to add a new line to the test.c program that calls the cipher_version () function. We will place this before the first line puts (text);

#include 
#include  

#include "libcipher.h" 

int main(int argc, char *argv()) 
{
 char text()="How-To Geek loves Linux"; 

 // new line added here
 cipher_version(); 

 puts(text); 
 
 cipher_encode(text); 
 puts(text); 
 
 cipher_decode(text); 
 puts(text); 

 exit (0); 

} // end of main

Save this code as test.c. Now we can compile it and prove that the new function is operational.

gcc test.c libcipher.a -o test

Now, let's run the new test version:

The new function is working, so we can see the library version at the beginning of the test output. But there may be a problem.

Ar command: Replacing a module in the library

This is not the first version of the library; It is the second. Our version number is incorrect, because the first version had no cipher_version () function. This one Then this should be the "0.0.2" version. So we need to replace the cipher_version () function in the library by making corrections.

Fortunately, the ar command makes it very easy.

First, let's edit the cipher_version.c file in the library directory. Change the text "Version 0.0.1 Alpha" to "Version 0.0.2 Alpha". It should look like this:

#include 

void cipher_version(void)
{
 puts("How-To Geek :: VERY INSECURE Cipher Library");  
 puts("Version 0.0.2 Alphan"); 

} // end of cipher_version

Save this file. We need to compile it again to create a new cipher_version.o object file.

gcc -c cipher_version.c

Now we will replace the existing cipher_version.o object in the library with our newly compiled version.

We have used the -r (add with replace) option before, to add new modules to the library. When we use it with a module that already exists, ar replaces the previous version with the new one. The -s (index) option will update the library index and the -v (detailed) option will make ar tell us what it has done.

ar -rsv libcipher.a cipher_version.o

This time ar reports that it has replaced the cipher_version.o module. The "r" means "replaced."

Use of the updated cipher_version () function

We should use our modified library and verify that it works. So we will copy the library files to the test directory.

cp libcipher.* ./test

We will change to the «test» directory.

cd ./test

We need to compile our "test" program again with our new library.

gcc test.c libcipher.a -o test

And now we can try our program.

./test

The result of the test program is what we expected. The correct version number is shown in the version string and the encryption and decryption routines are working.

Ar command: remove modules from a library

To do this, we will use the -d option (delete). We will also use the -v (detailed) option, so that ar can tell us what he has done. We will also include the -s (index) option to update the index in the library file.

ar -dsv libcipher.a cipher_version.o

The ar command reports that you have removed the module. "D" means "removed." If we ask «ar» to list the modules within the library file, we will see that we have returned to the two modules.

ar -t libcipher.a

If you are removing modules from your library, remember to delete your definition from the library header file.

Share your code with the ar command!

Libraries allow code to be shared in a practical but private way. Anyone to whom you give the file in question and the header file can use your library, but your real source code remains private.