Building Multiple Programs

Instructions to use one makefile to build multiple programs from one code base. For example: you have code that is for a unit test project and code that is for your main program. You can't compile it into one program as the tests and "main" program each define a main function. So you need to build two separate programs.

These instructions are based on the MakeComplex project from Week01 in the CS260 code repository. Use it if you want to be able to follow along exactly. The instructions assume you have a terminal open in that directory.


  1. Examine the code in MakeComplex. There are two separate files with main functions - programA.cpp and programB.cpp. Those represent two separate programs that both happen to use code from Answer.cpp. We need to build the two files into two separate programs.

  2. Create a file called Makefile and start with a basic set of targets for programA.

    .PHONY: all
    all: programA.exe
    
    programA.exe: programA.cpp Answer.cpp Answer.h Templated.h
    	g++ -g -Wall -o programA.exe programA.cpp Answer.cpp
    
    .PHONY: clean
    clean:                  
    rm -f programA.exe
    

    As before, the target is named after the program to build, and it depends on all of the source files, both .cpp and .h, that I might want to edit and would require the program to be rebuilt if I did. The commands use g++ and list all of the .cpp files to be compiled.

  3. Add a rule for programB.

    .PHONY: all
    all: programA.exe programB.exe
    
    programA.exe: programA.cpp Answer.cpp Answer.h Templated.h
    	g++ -g -Wall -o programA.exe programA.cpp Answer.cpp
    
    programB.exe: programB.cpp Answer.cpp Answer.h Templated.h
    	g++ -g -Wall -o programB.exe programB.cpp Answer.cpp
    
    .PHONY: clean
    clean:                  
    rm -f programA.exe programB.exe
    

    The two .exe rules are similar, but note that each program only uses its own .cpp file that defines main. They both use the shared files such as Answer.cpp.

    The default rule all lists both programs as prerequisites. This forces both of those rules to run and builds both programs whenever you run make with no arguments. You can always run just make programA.exe or make programB.exe if you want to specify.

  4. Once any significant amount of information is shared, it becomes good practice to use variables to move the repeated information to just one place. For example, we are going to want to pass the same flags to the compiler each time, so let's put that information into a variable.

    CXXFLAGS = -g -Wall
    
    .PHONY: all
    all: programA.exe programB.exe
    
    programA.exe: programA.cpp Answer.cpp Answer.h Templated.h
    	g++ $(CXXFLAGS) -o programA.exe programA.cpp Answer.cpp
    
    programB.exe: programB.cpp Answer.cpp Answer.h Templated.h
    	g++ $(CXXFLAGS) -o programB.exe programB.cpp Answer.cpp
    
    .PHONY: clean
    clean:                  
    rm -f programA.exe programB.exe
    

    The new first line defines the variable, CXXFLAGS, and the commands can simply use its value as $(CXXFLAGS) instead of duplicating the list of flags. This is particularly useful once the list of flags you want to configure gets long.

    We can also use variables to avoid repeating the shared file names.

    CXXFLAGS = -g -Wall
    
    PROGRAM_A_FILES = programA.exe
    PROGRAM_B_FILES = programB.exe
    SHARED_HEADERS = Answer.h Templated.h
    SHARED_FILES = Answer.cpp
    
    .PHONY: all
    all: programA.exe programB.exe
    
    programA.exe: $(PROGRAM_A_FILES) $(SHARED_FILES) $(SHARED_HEADERS)
    	g++ $(CXXFLAGS) -o programA.exe $(PROGRAM_A_FILES) $(SHARED_FILES)
    
    programB.exe: $(PROGRAM_B_FILES) $(SHARED_FILES) $(SHARED_HEADERS)
    	g++ $(CXXFLAGS) -o programB.exe $(PROGRAM_B_FILES) $(SHARED_FILES)
    
    .PHONY: clean
    clean:                  
    rm -f programA.exe programB.exe
    

    With this sort of style, you can often control most things about the Makefile by editing variable definitions near the top, while the commands can sometimes get quite cryptic-looking but rarely require editing anyway.