Puis-je compiler tous les fichiers .cpp dans src / vers .o dans obj /, puis créer un lien vers le binaire dans ./?

116

Mon répertoire de projet ressemble à ceci:

/project
    Makefile
    main
    /src
        main.cpp
        foo.cpp
        foo.h
        bar.cpp
        bar.h
    /obj
        main.o
        foo.o
        bar.o

Ce que je voudrais que mon makefile fasse serait de compiler tous les .cppfichiers du /srcdossier vers des .ofichiers du /objdossier, puis de lier tous les .ofichiers /objdans le binaire de sortie dans le dossier de niveau supérieur /project.

Je n'ai pratiquement aucune expérience avec Makefiles, et je ne sais pas vraiment quoi rechercher pour y parvenir.

Est-ce également une «bonne» façon de faire cela, ou y a-t-il une approche plus standard de ce que j'essaie de faire?

Austin Hyde
la source
6
@aaa: Je suppose que l'OP veut une solution qui ne nécessite pas de lister explicitement chaque fichier source.
Cascabel
7
Je ne veux pas spécifier chaque fichier source que j'ai, et j'ai déjà essayé de lire ce manuel, mais je le trouve désorganisé et difficile à comprendre. J'apprends beaucoup mieux d'un exemple réel qui fait ce que j'attends et qui est bien expliqué, plutôt que de manuels techniques secs.
Austin Hyde
d'accord. Mais faire de la documentation est excellente avec de bons exemples (il ne s'agit pas d'essayer le manuel technique). vous recherchez des règles de modèle: gnu.org/software/make/manual/make.html#Pattern-Rules
Anycorn
11
Cela ressemble un peu plus à ce que je veux. Cependant, à mon humble avis, le manuel de fabrication est un peu sec, car il semble plus ciblé sur les développeurs qui sont à un niveau intermédiaire avec make, et au-delà, il est très large et approfondi. Peut-être trop.
Austin Hyde

Réponses:

180

Makefile partie de la question

C'est assez facile, sauf si vous n'avez pas besoin de généraliser, essayez quelque chose comme le code ci-dessous (mais remplacez l'indentation de l'espace par des tabulations près de g ++)

SRC_DIR := .../src
OBJ_DIR := .../obj
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES))
LDFLAGS := ...
CPPFLAGS := ...
CXXFLAGS := ...

main.exe: $(OBJ_FILES)
   g++ $(LDFLAGS) -o $@ $^

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
   g++ $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<

Génération automatique de graphiques de dépendances

Une fonctionnalité "incontournable" pour la plupart des systèmes de marque. Avec GCC in peut être fait en une seule passe comme effet secondaire de la compilation en ajoutant un -MMDdrapeau à CXXFLAGSet -include $(OBJ_FILES:.o=.d) à la fin du corps du makefile:

CXXFLAGS += -MMD
-include $(OBJ_FILES:.o=.d)

Et comme les gars l'ont déjà mentionné, ayez toujours GNU Make Manual à portée de main , c'est très utile.

bobah
la source
11
Ah, tu m'as battu par secondes. Mais je suggère OBJ_FILES = $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES)).
Bêta
1
J'ai dû changer cela pour que cela fonctionne: $<devrait être $^pour la règle de main.exe et je pense qu'il y a une faute de frappe avec obj/%.o: src/%cpp.
1
@bobah Il vous manque un "." dans la règle de vos objets pour le cpp
regomodo
1
les variables spéciales valent probablement la peine d'être expliquées, car elles sont spécifiques au makefile et difficiles à rechercher: gnu.org/software/make/manual/html_node/Automatic-Variables.html
Blake
2
Je sais que c'est une vieille question, mais j'ai un peu modifié en fonction de mon projet, mais ça ne marche pas. Voici mon makefile: pastebin.com/4CksG9Wc J'arrive dans la console:make: *** No rule to make target '/main.o', needed by 'bin/main'. Pare.
Mateus Felipe
5

Wildcard fonctionne aussi pour moi, mais je voudrais donner une note latérale pour ceux qui utilisent des variables de répertoire. Utilisez toujours la barre oblique pour l'arborescence des dossiers (pas la barre oblique inverse), sinon cela échouera:

BASEDIR = ../..
SRCDIR = $(BASEDIR)/src
INSTALLDIR = $(BASEDIR)/lib

MODULES = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(wildcard *.o)
xesf
la source
vouliez-vous dire barre oblique? Votre exemple montre ce qui est traditionnellement considéré comme la barre oblique. Plus précisément, ceux qui «se penchent à droite» sont considérés comme «en avant» et ceux de gauche sont considérés comme «en arrière»
Evan Teran
Oui, vous avez raison, je veux dire "slash" seulement. J'ai mis à jour le message.
xesf