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.

TP7 : Build system

IUT d'Orsay, Université Paris-Saclay

Le but de ce TP est de comprendre les points suivants :

Structurer son projet

Voici la structure courante de votre projet :

TP7/
└── 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. Compilez et exécutez le programme. Observez la sortie.

  2. Nettoyez le projet en supprimant les fichiers générés par la compilation.

  3. Restructurez votre projet comme en cours en utilisant la structure et le makefile suivants :

TP7/
├── 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. En faisant make puis make run en se plaçant dans TP7/, est-ce que votre programme produit la bonne sortie ?

  1. Nettoyez le projet en utilisant make clean.

Compilation automatique

  1. Revenez au makefile précédent et essayez de le comprendre grâce au cours. Vous pouvez utiliser les commandes touch et make -d pour mieux comprendre les différentes étapes du processus de make.

Dans les prérequis des fichiers sources, nous avons ajouté manuellement les headers utilisés, mais nous voulons pouvoir facilement en ajouter ou en supprimer sans modifier notre script de compilation automatique (makefile). Autrement dit, nous souhaitons que la génération des dépendances soit également automatisée.

  1. Exécutez make clean avant de passer à l’étape suivante.

  2. Apportez les modifications suivantes au 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. Exécutez la commande make et examinez le contenu des fichiers .d générés.

Les fichiers générés par la compilation sont pour le moment mélangés avec les fichiers sources, pour garder notre projet propre, nous allons les mettre dans un autre sous-répertoire build/.

  1. Exécutez make clean avant de passer à l’étape suivante.

  2. Apportez les modifications suivantes au 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. Exécutez les différentes commandes make, make run et make clean et observez l’état des répertoires après chaque commande.

  2. Exécutez make clean avant de passer à l’étape suivante.

Idéalement, nous voulons un makefile qui fonctionnerait pour tous nos projets qui ont la structure :

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

Pour cela, nous allons utiliser des variables pour refactoriser le makefile.

  1. Apportez les modifications suivantes au 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)

Revenez aux objectifs et cochez les points que vous avez maîtrisés. Revenez sur les points que vous n’avez pas encore bien compris. Appelez votre encadrant si besoin.