extern in C

Kevin Buettner kev@primenet.com
Tue, 6 Mar 2001 18:15:10 -0700


On Mar 6,  4:19pm, Brad Bonkoski wrote:

> I have a large project in which I have multiple .c files that I am
> making a Linux Module out of.  I am trying to create an API for it, and
> thought that an easy way would be to extern some of the functions that I
> would allow "users" to include in their programs.  I thought I good
> place to start is to make a demo package of the functionality, or make a
> program myself using the *API*
> So, the grunt of it:
> 
> I have three basic files that need to be used:
> demo.c --> which calls the function add_to_cache( )
> api.h --> which has the function prototype: extern int add_to_cache(
> MAC_Value, IP_ADDR)
> arp.c --> which has the function definition of add_to_cache( )
> 
> so, arp.c is part of the actual module, which builds and registers with
> Linux.
> 
> Then I try to build demo.c seperately, linking only with the header file
> (api.h) which is also included in arp.c
> When compiling demo.c I get a linking error from 'ld' which says that
> add_to_cache is an unresolved symbol.
> What am I doing wrong?  when running "ksyms" the function appears to be
> registered, so should it link, or is there somethine else I should do?

I don't understand where (or why) ksyms enters the picture.  (You aren't
trying to create a kernel module, are you?)

You need to make sure that you've linked (in some fashion) demo.o with
arp.o.  There are a number of ways that this can be done.  You could
do this:

    gcc -c demo.c
    gcc -c arp.c

This will leave you with two .o files that you'll need to link together:

    gcc -o demo demo.o arp.o

It is likely that the library that you're trying to construct consists
of more than one object file.  When this occurs, you normally group
them together within a library.  To create a library containing arp.o,
do:

    ar r libapi.a arp.o

If you had more files, you'd list them after arp.o.  Assuming that
libapi.a is found in a standard place that gcc looks for libraries,
you could then do the linking as follows:

    gcc -o demo demo.o -lapi

If it's not (e.g. if it's in the current directory), you could do

    gcc -o demo demo.o -L`pwd` -lapi

But, often times, I'm lazy and just do:

    gcc -o demo demo.o libapi.a

The library libapi.a is often called a static library because you need
to link it statically with the rest of your program (demo.o in this
case).  This means that the resulting executable will have everything
in demo.o in it as well as the necessary bits from libapi.o that were
needed to do the linking.  (Members which aren't needed are left out
of the final executable.  This would not (necessarily) be true if
you had specified all of the .o files together on the command line
for the final link.  The advantage of this approach is that the
resulting executable is self contained in the sense that you won't
also need to ship one ore more libraries in order for the program
to be able to run.

As you probably know there are also shared (or dynamic) libraries.
When you link against a shared library, the code from the library
in question does not reside in the final executable.  Instead,
the library code is dynamically loaded when the executable is run.
This means that the library needs to reside in some known location
on the system upon which the executable is run.  To create a shared
library, do:

    gcc -c -fpic arp.c
    gcc -o libapi.so -shared arp.o

To link against this shared library (assuming it's in the same directory
as demo.o), do

    gcc -o demo demo.o -Xlinker -rpath `pwd` -L`pwd` -lapi

The -Xlinker option causes gcc to pass -rpath `pwd` to the linker.
The linker then embeds this path information in the resulting
executable so that the dynamic linker knows where to look for
libapi.so.  (See the ld man page for more information.)

So now you know at least three ways to link your library with
an application:

    1) Via using the object files which form the library directly
       (this lacks a certain elegance)

    2) Statically

    3) Dynamically

You probably want to use one of the latter two methods.  Unless you
have very good reasons for wanting to link dynamically, it's probably
better to choose the static approach.

Kevin