User Tools

Site Tools


guides:software:make:start

This is an old revision of the document!


Make

Make is a build automation tool that is designed to automatically construct executable programs from source code.

Simple Use

Make has a set of built in rules that allow you to compile single file programs with no additional configuration. The only requirement is that you provide the correct extension to your source code file. Make uses this extension to decide which compiler to run.

A simple Example

Make recognizes files ending with .cpp, .C and several other extensions as c++ source code. To build an executable from a file with an appropriate extension type make progname. In the following example, the user wishes to construct the executable hello from the program hello.cpp.

$ ls
hello.cpp
$ make hello
g++     hello.cpp   -o hello
$ ls
hello*  hello.cpp

In the example:

  1. The user typed ls to show the files in the directory
  2. The user next typed make hello
    1. This caused make to compile hello.cpp and produce the output file hello.
  3. The user typed ls again to show that the file hello had been produced.

Make Only Rebuilds when Necessary

Make will only rebuild an executable if it is necessary. Make looks at the timesamp on the source files and executable to determine if such a rebuild is required. If the executable is newer than the source code, make will not rebuild the executable.

$ ls
hello.cpp
$ make hello
g++     hello.cpp   -o hello
$ make hello
make: 'hello' is up to date.

In this example

  1. The user typed ls to show the contents of the directory
  2. The user typed make hello
    1. make built the executable hello from the source code hello.cpp
  3. The user typed make hello again
    1. Make observed that the time stamp on hello was newer than that on hello.cpp
    2. Based on that observation, make decided that there was no need to rebuild hello

If the user wished to rebuild hello in the above example they could do one of several things:

  • Remove the executable hello (rm hello)
  • Change the timestamp on hello.cpp (touch hello.cpp)
  • Edit the file hello.cpp and save the new file.

Make Can Not Build an Unknown Target

Unless directed otherwise, make uses the files in the current directory when attempting to build an executable. In the next example, the user attempts to build an executable when source code is missing.

$ ls
hello*  hello.cpp
$ make bad
make: *** No rule to make target 'bad'.  Stop.

In this example:

  1. The user types ls to show the contents of the directory
  2. The user types make bad to attempt to build an executable bad
    1. Make does not detect a source code file that can be used to construct bad, so it reports an error and exits.

Setting Compiler Flags for Make

Make uses a file called either Makefile or makefile as a configuration file. If one of these two files are present, make will read the this file and use it to determine how to build the executable. In general Makefile is the preferred name for this file.

Using a Makefile to Provide Compiler Flags

A relatively powerful yet simple use of a Makefile is to provide the proper command line arguments to build your executable.

Assume that your instructor wishes you to compile your program with the following compiler flags:

 -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion

You could

  • Memorize these flags and type them every time you compile.
  • Type in these flags once for each session and use command line history to recompile each time.
  • Write a shell script to compile your programs for you.
  • Create a Makefile that instructs make to use these flags.

The last option is fairly easy. Simple edit Makefile with your favorite editor and add the following line:

CXXFLAGS = -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion

CXXFLAGS is a variable that is used to tell make what compiler flags should be used to compile c++ programs.

$ ls
Makefile  hello.cpp
$ cat Makefile
CXXFLAGS = -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion

$ make hello
g++ -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion    hello.cpp   -o hello
$ ls
Makefile  hello*  hello.cpp

In this example:

  1. The user types ls to show the contents of the directory.
    1. Note in this case, both hello.cpp and Makefile are present.
  2. The user types cat Makefile to display the contents of the Makefile.
  3. The user types make hello to build the executable
    1. Make uses the contents of the Makefile to construct hello using the desired compiler flags

Specifying a Single Target in a Makefile

A second easy use of the makefile is to specify what you wish to build when you type make. In all of the examples so far, the user has typed make hello. This is acceptable while you are working on a project but becomes problematic when you return to a project after some time, or a new to a project. In this case, you might not remember to type make hello.

To solve this problem make allows you to specify default targets. A default target will be constructed when the user types make.

A common way to specify a default target is to declare a rule to build the target all. Make will use the first target appearing in the makefile as the default target. In the following example, such a rule has been added to the makefile.

$ ls
Makefile  hello.cpp
$ cat Makefile
CXXFLAGS = -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion

all: hello
$ make
g++ -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion    hello.cpp   -o hello

In the example:

  1. The user types ls to show the contents of the directory
  2. The user types cat Makefile to show the contents of the makefile.
    1. Notice that the line all: hello has been added.
  3. The user types make to build the project

In the example above, all is a target. Since it is the first target, make will attempt to build this target when no target is specified. The target all is a standard target for make. You could call this anything, but it is traditional to call the default target all.

A target consists of a target name, in this case all and a dependency list. The dependency list consists of a single dependency hello. This tells make that if you want to build everything, you need to build hello. Make uses the default rules to build hello.

Adding a Rule to Remove Executable Files and Other Compiler Generated Files

Another standard target is clean. Usually makefiles are constructed so that when the user types make clean all executable files are removed from the directory.

$ ls
Makefile  hello.cpp
$ cat Makefile
CXXFLAGS = -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion

all: hello

clean:
        rm -f hello
$ make
g++ -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion    hello.cpp   -o hello
$ ls
Makefile  hello*  hello.cpp
$ make clean
rm -f hello
$ ls
Makefile  hello.cpp

In the example:

  1. The user types ls to show the contents of the directory
  2. The user types cat Makefile to show the contents of the Makefile
  3. The user types make to build the default target hello
  4. The user types ls to show that hello was constructed
  5. The user types make clean to remove project executable files.
  6. The user types ls to show that the executable files have been removed.

The Makefile contains the following:

CXXFLAGS = -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion
 
all: hello
 
clean:
        rm -f hello

Note that an additional target, clean, has been added to the Makefile. This target is different from the default target for all in two ways:

  1. There are no dependencies
  2. There is a rule to be applied when building the target.

The rule is rm -f hello. This is a shell command that will be executed when make attempts to build the target. In this case, the result is to remove the file hello. The -f flag says to force the removal of the file, but in this case the purpose is to make rm ignore non-existent files. This keeps make from reporting an error if hello is not present.

Note that when constructing rules in make, the rules need to be indented by a tab. The following example demonstrates what would happen if rm -f hello were not preceded by a tab.

$ cat Makefile
CXXFLAGS = -g -O3 -Wpedantic -Wall -Wextra -Wmisleading-indentation -Wunused -Wuninitialized -Wshadow -Wconversion

all: hello

clean:
 rm -f hello
$ make
Makefile:6: *** missing separator.  Stop.

In this example:

  1. The user types cat Makefile to show the contents of the Makefile
    1. Notice that the rule for clean has a space and not a tab.
  2. The user types make to build the project
    1. Make reports an error because it can not parse the Makefile due to the missing tab.

It is extremely important that all rules for a target begin with a tab.

Makefiles for Multiple File Compilation

guides/software/make/start.1595257218.txt.gz · Last modified: 2022/08/02 11:59 (external edit)