GCC - GNU Compiler Collection

From GCC manual - When you invoke GCC, it normally does preprocessing, compilation, assembly and linking.

gcc -o hello.out hello.c

This creates an executable ‘hello.out’ from file ‘hello.c’ -o specifies the output file.

Specify Language:

Create a C file and save it as ‘hello.cpp’.

gcc -o hello.out hello.cpp

This results in an error as gcc tries to perform C++ compilation(assumed from the extension .cpp). We can specify that the file is a C file as follows:

gcc -x c -o hello.out hello.cpp

-x specifies the language.

Compile Only(No Linking):

gcc -c hello.c

-c tells gcc to compile ONLY. This creates ‘hello.o’, which is an object file.

Compiling and Linking multiple files:

File: hello.c

#include<stdio.h>

long myabs(long);
long factorial(long);

int main()
{
 printf("Hello World..\n");
 printf("Absolute(-3) = %d\nFactorial(5) = %d\n",myabs(-3),factorial(5));
 return 0;
}

File: myabs.c

long myabs(long a)
{
 if(a<0) return -a;
 return a;
}

File: myfac.c

long factorial(long no)
{
 if(no<=1) return 1;
 else return no*factorial(no-1);
}

METHOD 1: Use source files directly:

Make executable hello.out from 3 files by

 gcc -o hello.out hello.c myabs.c myfac.c

METHOD 2: Use a source file with one or more object files:

Compile one file

 gcc -c myabs.c

Now object code of myabs.c is obtained. Use this in usual gcc command:

 gcc -o hello.out hello.c myabs.o myfac.c

Or you can compile remaining files also and use their object files:

 gcc -o hello.out hello.c myabs.o myfac.o
 gcc -o hello.out hello.o myabs.o myfac.o

Create Library:

The above methods are suitable if the number of source files are really small. But if there are large number of source files, then its difficult to specify them each and every time you compile. To make this easy, you can create library. Library is a collection of object files. Create library with ‘ar’ command, which is short for ‘archive’. So first create object files (.o files). With above example we have two object files - myabs.o and myfac.o. Now create library:

 ar cr libMyCol.a myabs.o myfac.o

Now a library libMyCol.a is created. To see the contents of a library use ‘ar t’:

 ar t libMyCol.a

It will show the present contents (myabs.o and myfac.o).

Compile using the library:

 gcc -o hello.out hello.c libMyCol.a

OR

 gcc -o hello.out hello.c -L. -lMyCol

-Ldir specifies the direcory in which library files are present. Here we use current directory, so we use a ‘dot’ as directory. -llibrary specifies the library name. library should only contain library name - extensions and preceeding ‘lib’ is omitted. So here ‘libMyCol.a’ is represented by -lMyCol   . This is why library names should start with ‘lib’.

Create Shared Library:

To create shared libraries, object files must be created with -fPIC. From gcc manual : -fpic Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine.  Such code accesses all constant addresses through a global offset table (GOT). The dynamic loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC; it is part of the operating system).  If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead.

Here we use -fPIC Before continuing delete all files except the three C files - it looks nice to have a clean directory :)

STEP 1: Create object files as follows:

 gcc -c -fPIC myabs.c
 gcc -c -fPIC myfac.c

STEP 2: Now we create shared library or shared object(.so) file from the two .o files created above.

gcc -shared -o libMyCol.so myabs.o myfac.o

The shared library created is libMyCol.so. You can delete the .o files as they are no longer needed.

The Shared Library can be linked either Statically or Dynamically.

Static Linking of Shared Library:

METHOD 1: Give full path to .so file

 gcc -o hello.out hello.c ./libMyCol.so

METHOD 2: Use LD_LIBRARY_PATH environment variable

First set LD_LIBRARY_PATH variable to current directory (dot). Then export it. These two steps are shown below:

LD_LIBRARY_PATH=.
 export LD_LIBRARY_PATH

Now you can perform the final compilation and linking as follows:

 gcc -o hello.out hello.c libMyCol.so

Dynamic Linking of Shared Library:

To do dynamic linking, you need to modify the source file ‘hello.c’ as follows:

File: hello.c

#include<stdio.h>
#include<dlfcn.h>

typedef long (*FUN_PTR)(long);

int main()
{
 void *handle = dlopen("libMyCol.so",RTLD_LAZY);
 if(handle==0)
 {
  printf("ERROR: Failed to load the library\n");
  return -1;
 }
 FUN_PTR fptr1 = dlsym(handle,"myabs");
 FUN_PTR fptr2 = dlsym(handle,"factorial");
 if(fptr1==0 || fptr2==0)
 {
  printf("ERROR: Cannot retrieve function address\n");
  return -1;
 }
 long tp = (*fptr1)(-3);
 printf("Hello World..\n");
 printf("Absolute(-3) = %d",tp);
 tp = (*fptr2)(5);
 printf("\nFactorial(5) = %d\n",tp);
 dlclose(handle);
 return 0;
}

If you haven’t set LD_LIBRARY_PATH variable and exported it as mentioned above, then do it now. Now perform dynamic linking by

 gcc -o hello.out hello.c -ldl

dl is the dynamic linking library. -ldl asks gcc to use this library.

Dynamic Linking library provides 4 functions - dlopen, dlclose, dlsym and dlerror. These are in dlfcn.h. dlopen is used to open a .so file. It returns a handle to the file. FUN_PTR is a function pointer. fptr1 has address of function myabs(). dlsym takes two parameters - handle and function name. dlclose is used to close the .so file.

Thanks to Praseed.P for his session on GCC at ILUG Cochin. It had been very informative and this post is a result of that session.