The Wonderful World of Make

From UCLUG
Jump to: navigation, search

This page is approximately the talk from the July 14, 2009 meeting, wherein Jās showed the basics of how to use GNU Make. (I say "approximately", because I don't remember exactly everything that I said, but based on the source code, this is probably what I meant to say. --Jās)

Program files[edit]

The source code to be compiled into a program: (The code samples below are also combined into File:Wonderfulworldofmake.tar.gz.)

main.cpp[edit]

// demo program for make

#include <string>
#include "hello.h"

int main(int argc, char **argv)
{
    std::string toWhom("world");

    if (1 < argc) {
        toWhom = argv[1];
    }

    hello(toWhom.c_str());

    return 0;
}

hello.c[edit]

/* hello() function */

#include <stdio.h>

void hello(const char *to_whom)
{
    printf("Hello, %s\n", to_whom);
}

hello.h[edit]

/* header for hello() function */

#ifndef _HELLO_H_
#define _HELLO_H_

#ifdef __cplusplus
extern "C" {
#endif

void hello(const char *to_whom);

#ifdef __cplusplus
}
#endif

#endif  /* _HELLO_H_ */

The goal is to take these three files and compile them into a program called my_hello that takes one optional argument:

$ ./my_hello
Hello, world
$ ./my_hello jas
Hello, jas

To do this, hello.c and main.cpp need to be compiled into object code (hello.o and main.o, respectively), then the object codes need to be linked together (into my_hello). If you wanted to do this manually, you would issue:

gcc -c hello.c -o hello.o
g++ -c main.cpp -o main.o
gcc -lstdc++ hello.o main.o -o my_hello

First Makefile[edit]

To have make do these commands, you would create a file, called Makefile (Makefile.0 in the tarball) with the following contents:

# Makefile:  explicit rules

my_hello: hello.o main.o
        gcc -lstdc++ hello.o main.o -o my_hello

main.o: main.cpp
        g++ -c main.cpp -o main.o

hello.o: hello.c hello.h
        gcc -c hello.c -o hello.o

This Makefile has all the rules explicitly. What follows is a line-by-line description of the syntax of the above Makefile:

# Makefile:  explicit rules

Comments in a Makefile start with a # and end at the end of the line. Everything inside that is ignored by make.

my_hello: hello.o main.o

This is the first target, called my_hello. Its dependencies are hello.o and main.o. The form of all targets is: target(s) colon prerequisite(s). The block that follows a target line is the series of commands to execute if the target file is older than the dependency files. For example, if the file my_hello is missing or older than its dependencies, it will execute the command:

        gcc -lstdc++ hello.o main.o -o my_hello

Notice that the block of commands is indented with the <TAB> character, not a series of spaces. The <TAB> character indicates to make that this is a command script for a target. The <TAB> character at the beginning of the command is the first thing you should verify when debugging a Makefile.

The command gcc -lstdc++ hello.o main.o -o my_hello in this case executes the GNU C compiler (gcc), using the standard C++ library (-lstdc++), linking the object files hello.o and main.o into an output program binary (-o) called my_hello.

main.o: main.cpp

The next target is the object file main.o, and it depends on the file main.cpp.

        g++ -c main.cpp -o main.o

It is created with this line, the GNU C++ compiler (g++), compile without linking (-c, for creating object files), main.cpp is the source, and main.o is the output (-o).

hello.o: hello.c hello.h

Target hello.o is similar, it depends on hello.c and hello.h.

        gcc -c hello.c -o hello.o

Use gcc to -c(ompile-without-linking) the source file hello.c and -o(utput) the object file hello.o.

Now, to build our program, we issue make:

$ ls
Makefile Makefile.0 Makefile.1 Makefile.2 Makefile.3 Makefile.4 hello.c hello.h main.cpp make.cheat
$ make
gcc -c hello.c -o hello.o
g++ -c main.cpp -o main.o
gcc -lstdc++ hello.o main.o -o my_hello
$ ls
Makefile Makefile.0 Makefile.1 Makefile.2 Makefile.3 Makefile.4 hello.c hello.h hello.o main.cpp main.o make.cheat my_hello

Here you can see that make created the files hello.o, main.o and my_hello.

In order to know what to do, the program make looks in the current directory for a file named, in order: GNUmakefile, makefile, or Makefile. Common convention is to use Makefile. It finds Makefile, then begins reading it. Since there was no target given as a commandline parameter, make builds the first target, which is my_hello in this case. It determines its prerequisites have not been met, so it builds them, based on their rules: hello.o first, then main.o. Once they have been built, it executes the rule to make my_hello, then exits.

To be continued... chruck 01:07, 17 August 2009 (UTC)