calvinhobbes123
calvinhobbes123

Reputation: 41

How to create an executable that links to a static library using a Makefile?

I'm new to C, and Makefiles are giving me a hard time. Within the Makefile, I want to make an executable that links to a static library. My understanding is that to generate an executable from test.c located in src/project the command would be gcc src/project/test.c -o test, and this executable would be named test. If I wanted to have the executable also link with a static library, lib.a how would I do that?

Upvotes: 0

Views: 2490

Answers (2)

arfneto
arfneto

Reputation: 1765

If I wanted to have the executable also link with a static library, lib.a how would I do that?

Short answer is: just include the library in the gcc command using

        gcc src/project/test.c -o test libstuff.a

Or use

       gcc src/project/test.c -o test -lstuff -Llibfolder

-L adds the libfolder to the list of folders where search for libraries are done. There is a folder search sequence for libraries similar to what happens with #include processing.

back to make

I will show a minimal example of how to build and use an static library in C and manage its use via a very short makefile, under Linux Ubuntu 20.

This is minimal and just for demonstration purposes. There are better ways to write this but I hope that writing this way will make easier for you to follow the logic.

Note: ar is the archiver in Linux, just like LIB in Windows. The program that manages creation of libraries.

Example

Take a folder with these 4 files

    Makefile  myLib.c  myLib.h  testing.c

We want to build a library libmyLib.a from myLib.c and use it in testing

The C sources

For the library:

// myLib.h
int twice(int);
// myLib.c
#include    <stdio.h>
int twice(int value) { return value + value; }

The test program

// testing.c
#include <stdio.h>
#include "myLib.h"
int main(void)
{   int x = 42;
    printf("x = %d, twice(%d) = %d\n", x, x, twice(x)  );
    return 0;
}

test output

testing just calls twice(42) and outputs 84

x = 42, twice(42) = 84

using the makefile

We want to type make and have libmyLib.a built, testing.c compiled and testing generated.

Something like (with make output suppressed by now):

so_user@DSK-2009:~/projects/so0802$ ls -ltr
total 32
-rw-r--r-- 1 so_user so_user   266 Aug  2 17:46 Makefile
-rw-r--r-- 1 so_user so_user    26 Aug  2 18:23 myLib.h
-rw-r--r-- 1 so_user so_user   155 Aug  2 18:23 testing.c
-rw-r--r-- 1 so_user so_user    79 Aug  2 18:23 myLib.c
so_user@DSK-2009:~/projects/so0802$ make

// supressed output //

so_user@DSK-2009:~/projects/so0802$ ls -ltr
total 44
-rw-r--r-- 1 so_user so_user   266 Aug  2 17:46 Makefile
-rw-r--r-- 1 so_user so_user    26 Aug  2 18:23 myLib.h
-rw-r--r-- 1 so_user so_user   155 Aug  2 18:23 testing.c
-rw-r--r-- 1 so_user so_user    79 Aug  2 18:23 myLib.c
-rw-r--r-- 1 so_user so_user  1792 Aug  2 18:42 testing.o
-rw-r--r-- 1 so_user so_user  1368 Aug  2 18:42 myLib.o
-rw-r--r-- 1 so_user so_user  1510 Aug  2 18:42 libmyLib.a
-rwxr-xr-x 1 so_user so_user 16760 Aug  2 18:42 testing
so_user@DSK-2009:~/projects/so0802$ ./testing
x = 42, twice(42) = 84
so_user@DSK-2009:~/projects/so0802$ 

make is an absurdly clever program that takes into account the last modification time of the files to, yes, make things up to date. make is based on so called makefiles, whose name defaults to Makefile. In the makefile things to be updated are called targets.

A makefile, even for a short project, can be a complex thing. But is always easier than not using one.

what would a make run do?

you can present the so called targets to make. If you just type make the program will search for a file named Makefile and inside the file for a target named all.

The first command below only updates the library, while the second will try the target all

    make libMylib.a
    make

make -n

You can always try -n and make will list what the program will do to update the targets.

Following the example above...

so_user@DSK-2009:~/projects/so0802$ make -n
make: Nothing to be done for 'all'.
so_user@DSK-2009:~/projects/so0802$ 

As the targets are all updated. Now suppose testing.c is changed:

so_user@DSK-2009:~/projects/so0802$ touch testing.c
so_user@DSK-2009:~/projects/so0802$ ls -ltr
total 44
-rw-r--r-- 1 so_user so_user   266 Aug  2 17:46 Makefile
-rw-r--r-- 1 so_user so_user    26 Aug  2 18:23 myLib.h
-rw-r--r-- 1 so_user so_user    79 Aug  2 18:23 myLib.c
-rw-r--r-- 1 so_user so_user  1792 Aug  2 18:42 testing.o
-rw-r--r-- 1 so_user so_user  1368 Aug  2 18:42 myLib.o
-rw-r--r-- 1 so_user so_user  1510 Aug  2 18:42 libmyLib.a
-rwxr-xr-x 1 so_user so_user 16760 Aug  2 18:42 testing
-rw-r--r-- 1 so_user so_user   155 Aug  2 18:57 testing.c
so_user@DSK-2009:~/projects/so0802$ make -n 
gcc -c -Wall testing.c
gcc -o testing testing.o libmyLib.a
so_user@DSK-2009:~/projects/so0802$ 

And you see that, as testing.c is newer, but as the library has not changed, we need to compile the program and link it with the library:

-rw-r--r-- 1 toninho toninho   266 Aug  2 17:46 Makefile
-rw-r--r-- 1 toninho toninho    26 Aug  2 18:23 myLib.h
-rw-r--r-- 1 toninho toninho    79 Aug  2 18:23 myLib.c
-rw-r--r-- 1 toninho toninho  1368 Aug  2 18:42 myLib.o
-rw-r--r-- 1 toninho toninho  1510 Aug  2 18:42 libmyLib.a
-rw-r--r-- 1 toninho toninho   155 Aug  2 18:57 testing.c
-rw-r--r-- 1 toninho toninho  1792 Aug  2 19:00 testing.o
-rwxr-xr-x 1 toninho toninho 16760 Aug  2 19:00 testing

But now we change myLib.c and try make -n:

so_user@DSK-2009:~/projects/so0802$ touch myLib.c
so_user@DSK-2009:~/projects/so0802$ make -n
gcc -c -Wall testing.c
gcc -c -Wall myLib.c
ar rcs libmyLib.a myLib.o
gcc -o testing testing.o libmyLib.a
so_user@DSK-2009:~/projects/so0802$ 

since the library changed, the header file could have also changed so we need to compile testing.c also. And call ar to rebuild the library, before generating a new testing executable.

The makefile used here

all: testing

clean:  
    rm *.o
    rm *.a
    rm testing

testing: testing.o libmyLib.a
    gcc -o testing testing.o libmyLib.a

testing.o: testing.c myLib.c myLib.h
    gcc -c -Wall testing.c

myLib.o:    myLib.c myLib.h
    gcc -c -Wall myLib.c

libmyLib.a: myLib.o
    ar rcs libmyLib.a myLib.o

I hope it is a bit clear how things go with make. Fell free to ask back about this.

the things before : are the targets

  • the clean target is usual, and you see here it just removes things
  • the things listed after a target are called dependencies, and it makes sense: if any of the dependencies are newer than the target the commands below the line of dependencies are run.
  • make is deeply recursive in the search of targets to update

Upvotes: 1

Marco Bonelli
Marco Bonelli

Reputation: 69276

First of all, lib.a is not a canonically "valid" static library filename, library filenames should start with lib and continue with the actual name of the library, e.g. libsomething.a. You would then link such library with -lsomething, assuming it is in the appropriate system directories. If not, you can add -Lpath/to/directory to make the linker also look into path/to/directory for libsomething.a. See also: Order in which library directories are searched and linked. Alternatively, in case of a static library you could also add the library directly to the GCC command line: gcc prog.c libsomething.a.

In a very basic Makefile I would do something like this:

test: src/project/test.c path/to/libsomething.a
    gcc $^ -o $@

Upvotes: 2

Related Questions