Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Lab7 : Build system

IUT d'Orsay, Université Paris-Saclay

The goal of this Lab is to understand the following points:

Structuring your project

Here is the typical structure of your project:

Lab7/
└── main.cpp
main.cpp
#include <iostream>
#include <string>
#include <vector>

class Book {
private:
    std::string mTitle;
    std::string mAuthor;

public:
    Book(const std::string& title, const std::string& author) : mTitle(title), mAuthor(author) {}

    std::string getTitle() const {
        return mTitle;
    }

    std::string getAuthor() const {
        return mAuthor;
    }

    void display() const {
        std::cout << mTitle << " by " << mAuthor << std::endl;
    }
};

class Library {
private:
    std::string mName;
    std::vector<Book> mBooks;

public:
    Library(const std::string& name) : mName(name) {}

    void addBook(const Book& book) {
        mBooks.push_back(book);
    }

    void displayBooks() const {
        std::cout << "Library: " << mName << std::endl;
        for (const Book& book : mBooks) {
            book.display();
        }
    }
};

int main() {
    Book gameOfThrones("Game of Thrones", "G. R. R. Martin");
    Book theHobbit("The Hobbit", "J. R. R. Tolkien");

    Library library("City Library");
    library.addBook(gameOfThrones);
    library.addBook(theHobbit);

    library.displayBooks();

    return 0;
}
  1. Compile and run the program. Observe the output.

  2. Clean the project by removing files generated during compilation.

  3. Restructure your project as seen in class using the following structure and makefile:

Lab7/
├── include/
│    ├── book.h
│    └── library.h
├── source/
│    ├── book.cpp
│    ├── library.cpp
│    └── main.cpp
└── makefile
makefile
all: library-app

library-app: source/book.o source/library.o source/main.o
	g++ source/book.o source/library.o source/main.o -o library-app

source/book.o: source/book.cpp include/book.h
	g++ -std=c++17 -Iinclude -c source/book.cpp -o source/book.o

source/library.o: source/library.cpp include/library.h include/book.h
	g++ -std=c++17 -Iinclude -c source/library.cpp -o source/library.o

source/main.o: source/main.cpp include/library.h include/book.h
	g++ -std=c++17 -Iinclude -c source/main.cpp -o source/main.o

clean:
	rm -f source/book.o source/library.o source/main.o library-app

run:
	./library-app

.PHONY: all clean run
  1. By running make then make run from Lab7/, does your program produce the correct output?

  1. Clean the project using make clean.

Automatic compilation

  1. Go back to the previous makefile and try to understand it using the lecture. You can use the touch and make -d commands to better understand the different steps of the make process.

In the prerequisites of the source files, we manually added the headers being used, but we want to be able to easily add or remove them without modifying our automatic compilation script (makefile). In other words, we want dependency generation to also be automated.

  1. Run make clean before moving to the next step.

  2. Apply the following changes to the makefile:

makefile
all: library-app

library-app: source/book.o source/library.o source/main.o
	g++ source/book.o source/library.o source/main.o -o library-app

source/book.o: source/book.cpp
	g++ -std=c++17 -Iinclude -MMD -MF source/book.d -c source/book.cpp -o source/book.o

source/library.o: source/library.cpp
	g++ -std=c++17 -Iinclude -MMD -MF source/library.d -c source/library.cpp -o source/library.o

source/main.o: source/main.cpp
	g++ -std=c++17 -Iinclude -MMD -MF source/main.d -c source/main.cpp -o source/main.o

clean:
	rm -f source/book.o source/library.o source/main.o source/book.d source/library.d source/main.d library-app

run:
	./library-app

.PHONY: all clean run

-include source/book.d source/library.d source/main.d
  1. Run the make command and examine the contents of the generated .d files.

The files generated during compilation are currently mixed with the source files. To keep our project clean, we will move them into another subdirectory called build/.

  1. Run make clean before moving to the next step.

  2. Apply the following changes to the makefile:

makefile
all: build/binaries/library-app

build:
	mkdir -p build/objects build/dependencies build/binaries

build/binaries/library-app: build/objects/book.o build/objects/library.o build/objects/main.o | build
	g++ build/objects/book.o build/objects/library.o build/objects/main.o -o build/binaries/library-app

build/objects/book.o: source/book.cpp | build
	g++ -std=c++17 -Iinclude -MMD -MF build/dependencies/book.d -c source/book.cpp -o build/objects/book.o

build/objects/library.o: source/library.cpp | build
	g++ -std=c++17 -Iinclude -MMD -MF build/dependencies/library.d -c source/library.cpp -o build/objects/library.o

build/objects/main.o: source/main.cpp | build
	g++ -std=c++17 -Iinclude -MMD -MF build/dependencies/main.d -c source/main.cpp -o build/objects/main.o

clean:
	rm -rf build

run:
	./build/binaries/library-app

.PHONY: all build clean run

-include build/dependencies/book.d build/dependencies/library.d build/dependencies/main.d
  1. Run the different commands make, make run, and make clean, and observe the state of the directories after each command.

  2. Run make clean before moving to the next step.

Ideally, we want a makefile that works for all our projects with the following structure:

project/
├── include/
│    ├── header.h
│    └── ...
├── source/
│    ├── code.cpp
│    ├── ...
│    └── ...
└── makefile

To achieve this, we will use variables to refactor the makefile.

  1. Apply the following changes to the makefile:

makefile
EXECUTABLE = library-app

CXX = g++
CXXFLAGS = -std=c++17 -Iinclude

SOURCES = $(wildcard source/*.cpp)
OBJECTS = $(patsubst source/%.cpp,build/objects/%.o,$(SOURCES))
DEPENDENCIES = $(patsubst source/%.cpp,build/dependencies/%.d,$(SOURCES))

all: build/binaries/$(EXECUTABLE)

build:
	mkdir -p build/objects build/dependencies build/binaries

build/binaries/$(EXECUTABLE): $(OBJECTS) | build
	$(CXX) $(OBJECTS) -o build/binaries/$(EXECUTABLE)

build/objects/%.o: source/%.cpp | build
	$(CXX) $(CXXFLAGS) -MMD -MF build/dependencies/$*.d -c $< -o $@

clean:
	rm -rf build

run:
	./build/binaries/$(EXECUTABLE)

.PHONY: all build clean run

-include $(DEPENDENCIES)

Go back to the objectives and check off the points you have mastered. Review the points you do not yet fully understand. Ask your instructor if needed.