Puisqu'il s'agit d'Unix, les exécutables n'ont pas d'extensions.
Il convient de noter que root-config
est un utilitaire qui fournit les bons drapeaux de compilation et d'édition de liens, ainsi que les bonnes bibliothèques pour construire des applications avec Root. Ce n'est qu'un détail lié à l'audience initiale de ce document.
Make Me Baby
ou On n'oublie jamais la première fois qu'on s'est fait avoir
Une introduction à make et à l'écriture d'un fichier makefile simple.
Qu'est-ce que Make ? Et pourquoi devrais-je m'en préoccuper ?
L'outil appelé Faire est un gestionnaire de dépendances de construction. C'est-à-dire qu'il s'occupe de savoir quelles commandes doivent être exécutées dans quel ordre pour prendre votre projet logiciel à partir d'une collection de fichiers sources, de fichiers objets, de bibliothèques, d'en-têtes, etc., etc. -- dont certains peuvent avoir changé récemment -- et de les transformer en une version correcte et à jour du programme.
En fait, vous pouvez utiliser Make pour d'autres choses, mais je ne vais pas en parler.
Un Makefile trivial
Supposons que vous ayez un répertoire contenant : tool
tool.cc
tool.o
support.cc
support.hh
et support.o
qui dépendent de root
et sont censés être compilés dans un programme appelé tool
et supposons que vous ayez travaillé sur les fichiers source (ce qui signifie que les fichiers tool
est désormais obsolète) et souhaite compiler le programme.
Pour ce faire, vous pouvez
-
Vérifier si l'un ou l'autre support.cc
o support.hh
est plus récent que support.o
et si c'est le cas, lancez une commande comme
g++ -g -c -pthread -I/sw/include/root support.cc
-
Vérifier si l'un ou l'autre support.hh
o tool.cc
sont plus récents que tool.o
et si c'est le cas, lancez une commande comme
g++ -g -c -pthread -I/sw/include/root tool.cc
-
Vérifier si tool.o
est plus récent que tool
et si c'est le cas, lancez une commande comme
g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
Ouf ! Quelle galère ! Il y a beaucoup de choses à retenir et plusieurs occasions de faire des erreurs. (BTW-- les particularités des lignes de commande présentées ici dépendent de notre environnement logiciel. Celles-ci fonctionnent sur mon ordinateur).
Bien entendu, vous pouvez exécuter les trois commandes à chaque fois. Cela fonctionnerait, mais n'est pas adapté à un logiciel important (comme DOGS qui prend plus de 15 minutes à compiler sur mon MacBook).
Au lieu de cela, vous pouvez écrire un fichier appelé makefile
comme ceci :
tool: tool.o support.o
g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
tool.o: tool.cc support.hh
g++ -g -c -pthread -I/sw/include/root tool.cc
support.o: support.hh support.cc
g++ -g -c -pthread -I/sw/include/root support.cc
et tapez simplement make
à la ligne de commande. Ce dernier effectuera automatiquement les trois étapes décrites ci-dessus.
Les lignes non indentées ont la forme suivante "cible : dépendances" et indiquer à Make que les commandes associées (lignes en retrait) doivent être exécutées si l'une des dépendances est plus récente que la cible. En d'autres termes, les lignes de dépendances décrivent la logique de ce qui doit être reconstruit pour prendre en compte les changements dans les différents fichiers. Si les dépendances sont plus récentes que la cible, les commandes associées doivent être exécutées. support.cc
change, ce qui signifie que support.o
doit être reconstruite, mais tool.o
peuvent être laissés tranquilles. Quand support.o
changements tool
doit être reconstruit.
Les commandes associées à chaque ligne de dépendance sont séparées par un onglet (voir ci-dessous) et doivent modifier la cible (ou au moins la toucher pour mettre à jour l'heure de modification).
Variables, règles intégrées et autres avantages
A ce stade, notre makefile se souvient simplement du travail à faire, mais nous devons encore trouver et taper chaque commande nécessaire dans son intégralité. Il n'est pas nécessaire de procéder ainsi : Make est un langage puissant avec des variables, des fonctions de manipulation de texte, et toute une série de règles intégrées qui peuvent nous faciliter la tâche.
Créer des variables
La syntaxe pour accéder à une variable make est la suivante $(VAR)
.
La syntaxe de l'affectation à une variable Make est la suivante : VAR = A text value of some kind
(ou VAR := A different text value but ignore this for the moment
).
Vous pouvez utiliser des variables dans des règles comme cette version améliorée de notre makefile :
CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
-lm -ldl
tool: tool.o support.o
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
qui est un peu plus lisible, mais qui nécessite encore beaucoup de saisie
Faire des fonctions
GNU make supporte une variété de fonctions pour accéder aux informations du système de fichiers ou à d'autres commandes sur le système. Dans le cas présent, nous nous intéressons à $(shell ...)
qui s'étend à la sortie du ou des arguments, et $(subst opat,npat,text)
qui remplace toutes les instances de opat
con npat
dans le texte.
En tirant parti de cette situation, nous pouvons
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
tool: $(OBJS)
g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
qui est plus facile à taper et beaucoup plus lisible.
Notez que
- Nous continuons à indiquer explicitement les dépendances pour chaque fichier objet et l'exécutable final
- Nous avons dû saisir explicitement la règle de compilation pour les deux fichiers sources
Règles implicites et modèles
Nous nous attendons généralement à ce que tous les fichiers sources C++ soient traités de la même manière, et Make fournit trois façons de l'indiquer :
- règles de suffixe (considérées comme obsolètes dans GNU make, mais conservées pour des raisons de compatibilité ascendante)
- règles implicites
- règles de modélisation
Des règles implicites sont intégrées, et quelques-unes d'entre elles seront examinées ci-dessous. Les règles de modèle sont spécifiées sous une forme telle que
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
ce qui signifie que les fichiers objets sont générés à partir des fichiers sources C en exécutant la commande indiquée, où la variable "automatique" est $<
se développe jusqu'au nom de la première dépendance.
Règles intégrées
Make possède toute une série de règles intégrées qui font que très souvent, un projet peut être compilé par un makefile très simple.
La règle intégrée de GNU make pour les fichiers source C est celle présentée ci-dessus. De même, nous créons des fichiers objets à partir de fichiers sources C++ avec une règle telle que $(CXX) -c $(CPPFLAGS) $(CFLAGS)
.
Les fichiers d'objets individuels sont liés à l'aide de $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
mais cela ne fonctionnera pas dans notre cas, car nous voulons lier plusieurs fichiers d'objets.
Variables utilisées par les règles intégrées
Les règles intégrées utilisent un ensemble de variables standard qui vous permettent de spécifier des informations sur l'environnement local (comme l'emplacement des fichiers Root include) sans avoir à réécrire toutes les règles. Les plus susceptibles de nous intéresser sont les suivantes :
CC
-- le compilateur C à utiliser
CXX
-- le compilateur C++ à utiliser
LD
-- l'éditeur de liens à utiliser
CFLAGS
-- drapeau de compilation pour les fichiers sources C
CXXFLAGS
-- drapeaux de compilation pour les fichiers sources C
CPPFLAGS
-- drapeaux pour le préprocesseur c (incluent typiquement les chemins de fichiers et les symboles définis sur la ligne de commande), utilisés par C et C++.
LDFLAGS
-- drapeaux de l'éditeur de liens
LDLIBS
-- bibliothèques à relier
Un Makefile de base
En profitant des règles intégrées, nous pouvons simplifier notre fichier makefile :
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
support.o: support.hh support.cc
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) tool
Nous avons également ajouté plusieurs cibles standard qui effectuent des actions spéciales (comme le nettoyage du répertoire source).
Notez que lorsque make est invoqué sans argument, il utilise la première cible trouvée dans le fichier (dans ce cas, all), mais vous pouvez également nommer la cible à obtenir, ce qui permet à make d'utiliser la fonction make clean
supprimer les fichiers objets dans ce cas.
Toutes les dépendances sont encore codées en dur.
Des améliorations mystérieuses
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
$(RM) ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) *~ .depend
include .depend
Notez que
- Il n'y a plus de lignes de dépendance pour les fichiers source !?!
- Il existe une magie étrange liée à .depend et depend
- Si vous le faites
make
puis ls -A
vous voyez un fichier nommé .depend
qui contient des éléments qui ressemblent à des lignes de dépendance make
Autre lecture
Connaître les bogues et les notes historiques
Le langage d'entrée de Make est sensible aux espaces blancs. En particulier, les lignes d'action qui suivent les dépendances doivent commencer par une tabulation . Mais une série d'espaces peut avoir la même apparence (et il existe en effet des éditeurs qui convertissent silencieusement les tabulations en espaces ou vice versa), ce qui donne un fichier Make qui a l'air correct mais qui ne fonctionne toujours pas. Ceci a été identifié comme un bogue très tôt, mais ( l'histoire est la suivante ), il n'a pas été corrigé, car il y avait déjà 10 utilisateurs.
(Ceci a été copié à partir d'un billet wiki que j'ai écrit pour les étudiants diplômés en physique).
14 votes
.EXE, il s'agit donc bien de Windows. En y réfléchissant bien, le chemin d'accès est de type Unix. Il utilise probablement Mingw-32.
3 votes
Soupir. Je suppose qu'il faut apprendre les bases de chaque métier, même si on ne les utilisera jamais. Il faut juste comprendre comment les choses fonctionnent. Il y a de bonnes chances que vous développiez toujours dans un IDE, comme Eclipse. Vous obtiendrez une réponse ici pour votre cas simple d'une ligne et il y a beaucoup de tutoriels sur le web, mais si vous voulez des connaissances approfondies, vous ne pouvez pas battre le livre d'O'reilly (même chose pour la plupart des sujets s/w). amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/ Choisissez un exemplaire d'occasion sur amazon, half.com, betterworldbooks eBay
3 votes
Le lien posté par @Dennis est maintenant mort, mais le même matériel peut être trouvé dans ceci archive.org page .
0 votes
Je préfère les idées de cette personne. ( hiltmon.com/blog/2013/07/03/ ) La structure du projet peut être facilement modifiée. Je suis également d'accord sur le fait que le temps des développeurs devrait être consacré à d'autres choses qu'à automake/autoconf. Ces outils ont leur place, mais peut-être pas pour des projets internes. Je suis en train de construire un script qui produira une telle structure de projet.
0 votes
@GuilhermeSalomé Merci, je crois que c'est le meilleur tutoriel simple et complet.
0 votes
Bonne question. J'y répondrai probablement lorsque j'aurai le temps de le faire.