Making A Simple Program

Instructions to build a simple makefile for a single program.


A makefile consists of a set of rules, each with 3 parts:

  • a target
  • a list of prerequisites
  • a list of commands

The general syntax for a rule is:

target: prerequisite-1 prerequisite-2 ...
	command1
	command2
...

The target and prerequisites are separated by a colon (:). The commands must be preceded by a tab (NOT spaces).

If a command is not preceded by a tab, you get an error message like this:
makefile:4: *** missing separator. Stop.
If you see this message it usually means you have spaces instead of tabs.

  1. From the terminal, navigate to the folder that has the code you wish to make a Makefile for. The sample shown below uses the MakeBasics project from the CS260 code (should be cs260Code/Week01/MakeBasics/).

  2. Using your text editor, make a file called Makefile in that directory. Make sure it does not have an extension (no .txt at the end).

  3. To edit the Makefile, you must use a text editor editor that will NOT put spaces in when you type a tab. By default, many programming tools will convert a press of the tab key into spaces. VSCode should correctly handle tabs (unless you have changed the settings). To see if you have tabs or spaces in VSCode, use View > Command Pallette and then View: Toggle Render Whitespace. Spaces will show as individual .s while tabs show as followed by blank space.

    Alternatively, you can use a simple text editor:

    • Windows: Notepad
    • Mac: Textedit (see these instructions for switching to plain text mode)
  4. In the Makefile put the following:

    .PHONY: program.exe
    program.exe: main.cpp Answer.cpp Answer.h
    	g++ -g -Wall -o program.exe main.cpp Answer.cpp
    
    • .PHONY: program.exe is a way to tell make that we always want make to run the commands when this target is invoked. Normally, make would try to figure out if program.exe actually needs to be rebuilt by comparing its date to that of its prerequisites. Normally, you might not declare program.exe as PHONY to prevent unnecessary rebuilds - especially if working on a large project where builds could take many minutes. However, always rebuilding is a nice way to make sure that your code ALWAYS gets rebuilt when you run make (which is essential if you are doing something like switching back and forth from Windows to Linux while developing.)

    • The next line - the first required one - defines the target program.exe. A target that builds a file is typically given a name that matches the file it builds.

    • After the : on that line, it lists three prerequisite files. These files must exist to run the rule. (If they are missing, make will try to build them using rules that match their names or, if those are not available, fail the build). If the rule is not declared .PHONY, the prerequisites also will be used to determine if the target is up to date and thus the build can be skipped.

    • The next line is the command to run. This command builds the file program.exe using g++

      • -g says to include debugging info. This helps if you use Valgrind on this project
      • -Wall says to mention ‘all’ warnings
      • -o program.exe gives the output file the correct name
      • main.cpp Answer.cpp are the list of files that need to be compiled

    Note that you should not list the .h files in the list of files to be compiled. They are not compiled, they are included into the .cpp files as appropriate. Any .h files you might edit should be listed in the prerequisites, but only there.

    Save the Makefile.

  5. Continuing in the terminal, type:

    make
    

    The default behavior for make is to run the first target in the file. In this, case that is the target program.exe. You can also run a particular rule by calling it explicitly.

    make program.exe
    
  6. Now type:

    ./program.exe
    

    To run the program program.exe which is in the current directory (.). In general, this is how you will want to run your programs.

  7. Usually, people add some additional rules to every makefile with some common behavior. These are called ‘phony’ rules, because they are not named after a file they produce but just given convenient names. You always should use .PHONY for these rules.

    Add a rule to clean up, leaving the Makefile

    .PHONY: program.exe
    program.exe: main.cpp Answer.cpp Answer.h
    	g++ -g -Wall -o program.exe main.cpp Answer.cpp
    
    .PHONY: clean
    clean:                  
    	rm -f program.exe
    

    The all target should come first, so that running make with no arguments builds everything by default. The all target simply depends on all of the files you want to make sure are always up-to-date, and does not need a recipe. The clean target doesn't have any prerequisites, so it always runs, and it deletes files created by the build process. It uses rm to remove files, and the -f option means that it won't ask for confirmation or complain if the file(s) already don't exist.

    Note that rm is a Linux/MacOS command. The clean rule will not work if run in Windows. (To work in Windows it would have to execute the command del program.exe)

  8. Now if you run make clean, you should end up with only your source files and not the compiled program.

  9. You can rebuild the program with make or make all. If you try to rebuild it after the program has already been built and there are no changes to the source files, make will detect that nothing needs to be done.