Amazon Best VPN GoSearch

Icône de favori OnWorks

makepp_cookbook - En ligne dans le Cloud

Exécutez makepp_cookbook dans le fournisseur d'hébergement gratuit OnWorks sur Ubuntu Online, Fedora Online, l'émulateur en ligne Windows ou l'émulateur en ligne MAC OS

Il s'agit de la commande makepp_cookbook qui peut être exécutée dans le fournisseur d'hébergement gratuit OnWorks en utilisant l'un de nos nombreux postes de travail en ligne gratuits tels que Ubuntu Online, Fedora Online, l'émulateur en ligne Windows ou l'émulateur en ligne MAC OS

PROGRAMME:

Nom


makepp_cookbook – La meilleure façon de configurer des makefiles pour diverses situations

DESCRIPTION


J'ai découvert que pratiquement personne ne lit jamais le manuel d'un outil de fabrication, car franchement
Personne ne s'intéresse vraiment au processus de fabrication lui-même : nous ne nous intéressons qu'aux résultats.
Ce livre de recettes a donc été élaboré dans l’espoir que les gens pourront obtenir ce dont ils ont besoin.
rapidement à partir des exemples sans parcourir le manuel. Ceci montre comment saisir
questions, tandis que les instructions d'installation et les obstacles se trouveront dans le
Questions fréquemment posées.

Développement bibliothèques
Do vous vraiment need a bibliothèque?

J'ai vu un certain nombre de grands programmes qui se composent d'un grand nombre de modules, chacun d'eux
qui réside dans son propre répertoire. Généralement, chaque répertoire est placé dans sa propre bibliothèque,
et ensuite le programme final est lié à toutes les bibliothèques.

Dans de nombreux cas, je pense qu'il existe une meilleure approche que de recourir à une bibliothèque.
ne sont pas vraiment la bonne solution si chaque module ne peut pas ou ne veut pas être réutilisé dans un autre
programme, car vous obtenez alors tous les inconvénients des bibliothèques et aucun des
Avantages. Les bibliothèques sont utiles dans les cas suivants :

1. Lorsque vous avez un tas de sous-routines qui doivent être liées à plusieurs
programmes, et aucun programme n'utilise réellement 100 % des sous-routines - chaque programme utilise un
sous-ensemble différent. Dans ce cas, il est probablement judicieux d'utiliser une bibliothèque statique (une
.a fichier ou un fichier d'archive).

2. Lorsque vous avez un module qui doit être lié à plusieurs programmes différents et que vous
je veux le charger dynamiquement afin que chaque programme n'ait pas besoin d'avoir une copie séparée de
la bibliothèque. Les bibliothèques dynamiques permettent d'économiser de l'espace sur les fichiers exécutables et parfois d'améliorer
performances du système car il n'y a qu'une seule copie de la bibliothèque chargée pour toutes les
différents programmes qui l'utilisent.

3. Lorsque votre temps de liaison est excessivement long, l'utilisation de bibliothèques partagées pour de gros morceaux de
le programme peut considérablement accélérer la liaison.

L'utilisation de bibliothèques statiques présente un inconvénient majeur : sur certains systèmes (par exemple Linux), l'ordre
La manière dont vous liez les bibliothèques est cruciale. L'éditeur de liens traite les bibliothèques.
dans l'ordre spécifié sur sa ligne de commande. Il récupère tout ce dont il pense avoir besoin
chaque bibliothèque, puis passe à la suivante. Si une bibliothèque ultérieure fait référence à une
symbole qui n'a pas encore été incorporé à partir d'une bibliothèque précédente, le linker ne
savoir revenir le récupérer dans la bibliothèque précédente. Par conséquent, il peut être nécessaire
pour lister la bibliothèque plusieurs fois sur la ligne de commande du linker. (J'ai travaillé sur un projet
où nous avons dû répéter la liste complète des bibliothèques trois fois. Ce projet est ce qui a rendu
Je préfère l'approche alternative suggérée ci-dessous, celle de la liaison incrémentale.)

L'utilisation de bibliothèques dynamiques présente plusieurs inconvénients. Premièrement, votre programme peut être légèrement
plus lent à démarrer si la bibliothèque n'est pas déjà utilisée par un autre programme, car
Il faut le trouver et le charger. Ensuite, il peut être très compliqué d'obtenir toute la dynamique
bibliothèques installées aux bons emplacements ; vous ne pouvez pas simplement copier l'exécutable du programme,
Vous devez également vous assurer de copier toutes ses bibliothèques. Troisièmement, sur certains systèmes,
il est difficile de déboguer du code dans les bibliothèques partagées car les débogueurs ne prennent pas en charge
eux bien.

Si votre module ne sera jamais utilisé dans un autre programme, il y a peu de raisons de l'utiliser.
une bibliothèque : vous obtenez tous les inconvénients de l’utilisation des bibliothèques et aucun des avantages.
La technique que je préfère est d’utiliser la liaison incrémentielle, lorsqu’elle est disponible.

Voici comment vous pouvez procéder sous Linux :

mon_module.o : $(filter_out mon_module.o, $(wildcard *.o))
ld -r -o $(sortie) $(entrées)

Ce que cela fera, c'est créer un autre .o fichier appelé mon_module.o, qui consistera en
tous les .o fichiers dans ce sous-répertoire. L'éditeur de liens résoudra autant de
références comme il le peut, et laissera les références restantes à résoudre dans un
Étape suivante de la liaison. Au niveau supérieur, lorsque vous construisez enfin votre programme,
au lieu de se lier avec libmy_module.a or libmy_module.so, vous créeriez simplement un lien avec
mon_module.o. Lorsque vous créez un lien .o fichiers, vous n'avez pas de problèmes de dépendance d'ordre dans le
ligne de commande du linker.

Location makepp comprendre ande qui bibliothèque modules sommes-nous nécessaire

Même si vous disposez d'une véritable bibliothèque, où un programme donné n'a besoin que de quelques fichiers
(plutôt que chaque module individuel), Makepp pourrait être en mesure de déterminer quels modules sont
nécessaires de la bibliothèque et n'inclure que ceux-ci dans la compilation. Cela permet d'économiser la compilation.
temps si vous développez la bibliothèque avec un programme, car vous ne vous souciez pas de
compiler les modules de bibliothèque qui ne sont pas nécessaires pour le programme particulier sur lequel vous travaillez.

Si votre bibliothèque respecte strictement la convention selon laquelle toutes les fonctions ou classes déclarées dans
un fichier xyz.h sont entièrement implémentés dans un fichier source qui compile en xyz.o (c'est-à-dire toi
ne divisez pas l'implémentation en xyz1.o et xyz2.o), alors vous pouvez utiliser le
Fonction « $(infer_objects) » pour indiquer à Makepp de récupérer uniquement les modules pertinents du
Bibliothèque. Cela peut fonctionner étonnamment bien pour des bibliothèques contenant même des dizaines de fichiers inclus.
Fondamentalement, "$(infer_objects)" examine la liste des .h fichiers inclus et apparence
pour correspondre .o fichiers. Si vous développez rapidement une bibliothèque et un programme
ensemble, cela peut économiser du temps de compilation, car vous n'avez jamais à vous soucier de compiler des modules de
la bibliothèque que le programme n'utilise pas.

Voici un exemple de la façon dont je l'utilise :

mon_programme : $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(entrées) -o $(sortie) $(SYSTEM_LIBRARIES)

La fonction "$(infer_objects )" renvoie son premier argument (après avoir effectué un caractère générique
extension dessus), et examine également la liste des fichiers dans son deuxième argument, pour
fichiers dont le nom est le même que le nom de n'importe quel .h fichiers inclus par n'importe quel fichier dans sa première
argument. Si de tels fichiers sont trouvés, ils sont ajoutés à la liste.

Développement a statique bibliothèque

Si vous êtes sûr d'avoir réellement besoin d'une bibliothèque et que la liaison incrémentielle n'est pas disponible ou
Si ce n'est pas ce que vous souhaitez faire, il existe plusieurs façons de procéder. Voici d'abord un exemple.
où tous les fichiers sont explicitement répertoriés :

LIBRARY_FILES = abcde

libmine.a : $(LIBRARY_FILES).o
&rm -f $(sortie)
$(AR) cr $(sortie) $(entrées)
ranlib $(output) # Peut ne pas être nécessaire, selon votre système d'exploitation.

La commande &rm est la commande « rm » intégrée à Makepp. Si vous avez l'habitude d'écrire des makefiles, vous pourriez
un peu surpris par cette commande ; vous êtes peut-être habitué à quelque chose de plus proche de ceci :

libmine.a : $(LIBRARY_FILES).o
$(AR) ru $@ $? # Non recommandé!!!!!!!
ranlib $(sortie)

où $? (également connu sous le nom de « $(changed_inputs) ») est une variable automatique qui signifie que tous les fichiers
qui ont changé depuis la dernière fois que la bibliothèque a été construite, et $@ est à peu près le même
comme "$(sortie)".

Cette approche n’est pas recommandée pour plusieurs raisons :

· Supposons que vous supprimiez un fichier source du répertoire courant. Il est toujours dans le
bibliothèque, car vous ne l'avez pas reconstruite à partir de zéro. Par conséquent, tout
que les liens avec cette bibliothèque auront l'ancienneté .o fichier, et cela peut gâcher votre
builds. (J'ai été complètement dérouté par cela une fois lorsque j'essayais de supprimer du code mort
d'un projet : j'ai continué à supprimer des fichiers et il était toujours lié, donc je pensais que le code était
mort. Cependant, lorsque quelqu'un d'autre a reconstruit le projet à partir de zéro, il n'a lié aucun
plus ! Le problème était que l'ancien .o (les fichiers étaient toujours dans les archives.)

De plus, en fonction de vos options pour « ar » et de votre implémentation de « ar » (par exemple, si vous
utilisez l'option « q » au lieu de « r »), vous pouvez vous retrouver avec plusieurs versions du
même .o à l'intérieur de l' .a fichier. Si les différentes versions définissent des variables globales différentes, le
Le linker pourrait tenter de les intégrer tous les deux. C'est probablement une mauvaise chose.

C'est pourquoi nous supprimons d'abord le fichier de bibliothèque et le créons à partir de zéro. Cela
prendre un peu plus de temps que la simple mise à jour des modules dans une bibliothèque, mais pas beaucoup plus longtemps ; sur
un ordinateur moderne, la quantité de temps consommée par le ar le programme est minuscule comparé
à ce que le compilateur C prend en charge dans une construction typique, donc cela ne vaut pas la peine de s'inquiéter
sur.

· L'une des façons dont makepp tente de garantir des builds correctes est qu'il
reconstruit automatiquement si la ligne de commande pour construire une cible donnée a changé. Mais
l'utilisation de la variable $? peut poser des problèmes, car à chaque mise à jour de la bibliothèque,
la commande de construction est différente. (Vous pouvez supprimer cela en utilisant
":build_check ignore_action"; voir makepp_build_check pour plus de détails.)

· Mettre à jour l'archive plutôt que de la reconstruire rendra impossible pour makepp de
placez correctement le fichier dans un cache de build (voir makepp_build_cache pour plus de détails).

Parfois, vous pouvez trouver que répertorier tous les fichiers est un peu pénible, surtout si un
Le projet connaît un développement rapide et la liste des fichiers est en constante évolution.
il peut être plus facile de construire la bibliothèque en utilisant des caractères génériques, comme ceci :

libmine.a : $(only_targets *.o)
&rm $(sortie)
$(AR) cr $(sortie) $(entrées)

Cela met tout le .o fichiers du répertoire courant dans la bibliothèque. Le caractère générique
correspond à n'importe quel .o fichier qui existe ou qui peut être construit, donc il fonctionnera même si les fichiers ne sont pas
n'existent pas encore.

La fonction « only_targets » est utilisée pour exclure .o fichiers qui n'ont pas de correspondant
fichiers sources. Imaginez que vous ayez un fichier appelé xyz.c que tu mettais dans ton
bibliothèque. Cela signifie qu'il y a une xyz.o fichier qui traîne. Maintenant, supprimez-le xyz.c
parce que c'est obsolète, mais vous oubliez de supprimer xyz.o. Sans les « only_targets »
fonction, xyz.o serait toujours inclus dans la liste des .o fichiers inclus dans la bibliothèque.

Développement a Dynamic bibliothèque

Le processus de création de bibliothèques dynamiques dépend entièrement du système. Je recommande vivement
recommande d'utiliser libtool pour créer une bibliothèque dynamique (voir
<http://www.gnu.org/software/libtool/>), vous n'avez donc pas à chercher comment le faire sur
votre plateforme, et pour que votre makefile continue de fonctionner même lorsque vous passez à une
Système d'exploitation différent. Consultez la documentation de libtool pour plus de détails. Voici un exemple de Makefile :

LIBTOOL := libtool

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(entrées) -o $(sortie)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(entrée) -o $(sortie)

Développement on plusieurs différent machines or réseaux
L’un des problèmes les plus ennuyeux avec les makefiles est qu’ils ne fonctionnent presque jamais lorsque vous
basculez vers une autre machine ou un autre réseau. Si vos makefiles doivent fonctionner sur
toutes les machines possibles sur la planète, alors vous avez probablement besoin d'une sorte de configuration
script. Mais si vous ne devez travailler que sur quelques machines différentes, il existe plusieurs façons
vous pouvez aborder ce problème :

Utilisez le a différent comprennent filet in tous le et rapides.

Au début de chaque makefile, vous pouvez inclure une ligne comme celle-ci :

inclure system_defs.mk

Le fichier system_defs.mk serait normalement situé à un endroit différent pour chaque
environnement. Si vous souhaitez que vos répertoires de build soient identiques sur toutes les machines, placez
system_defs.mk dans un répertoire au-dessus des répertoires de construction, ou bien fournissez un chemin d'inclusion
pour makepp en utilisant l'option de ligne de commande "-I".

C'est généralement un peu pénible à faire, mais cela fonctionne bien s'il y a un grand nombre de
différences.

Utilisez le if déclarations

C'est la façon la plus moche de le faire, mais cela fonctionnera généralement.

ifsys i386
CC := gcc
sinon ifsys sun4u
CC := cc
sinon ifsys hpux11
CC = c89
fin si

Si tout ce que vous avez à faire est de trouver quelques programmes ou bibliothèques ou d'inclure des fichiers dans différents
Dans certains endroits, il existe peut-être de meilleures méthodes (voir ci-dessous).

trouver_programme, premier_disponible, trouver un fichier

Ces fonctions peuvent rechercher différents répertoires de votre système pour trouver le
fichiers appropriés. Ce n'est pas aussi puissant qu'un script de configuration, bien sûr, mais je le trouve
utile. Par exemple, je fais ce qui suit :

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# Choisissez le premier compilateur C++ disponible dans PATH.
# (D'ailleurs, si vous ne définissez pas du tout CXX, cela
# est la façon dont il est défini.)
TCL_INCLUDE ;= -I$(dir_noslash $(findfile tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 /usr/include/tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile ) recherche tcl.h dans chacun des éléments indiqués
# répertoires et renvoie le chemin complet. Ceci est alors
# converti en une option de compilation en supprimant le
# nom de fichier (en quittant le répertoire) et préfixé par -I.
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(entrée) -o $(sortie)

TCL_LIB ;= $((premier_disponible
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Trouver où se trouve la bibliothèque Tcl. Ceci est alors explicitement
# répertorié sur la commande de lien :
mon_programme : *.o
$(CXX) $(CXXFLAGS) $(entrées) -o $(sortie) $(TCL_LIB)

Prenez avantage of De Perl config d'information

Les techniques ci-dessus peuvent ne pas être suffisantes si vous avez besoin d’informations supplémentaires sur
votre système, par exemple si un double long existe ou quel est l'ordre des octets. Cependant,
perl a déjà calculé ces choses, vous pouvez donc simplement utiliser ses réponses.

Le script d'autoconfiguration de Perl rend toutes ses informations de configuration disponibles via
le hachage %Config. Il n'existe pas de syntaxe permettant d'accéder directement à un hachage Perl dans makepp, mais vous pouvez
passez dans Perl et définissez des variables scalaires, qui sont directement accessibles depuis makepp :

perl_begin
# Récupérer les valeurs du hachage de configuration.
utilisez la configuration ;
$CC = $Config{'cc'}; # compilateur C utilisé par Perl ;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_defined = $Config{'d_longdbl'} eq 'define';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

De plus, une fois que vous avez effectué « use Config », vous pouvez utiliser l'instruction « $(perl ) », comme
ce:

EXTENSION_BIBLIOTHÈQUE_PARTAGÉE := $(perl $Config{'dlext'})

Tapez « perldoc Config » pour voir quelles informations sont disponibles via le hachage %Config.

La configuration de Perl est un bon endroit pour obtenir des informations sur les types d'entiers, les octets et les
commande, et d'autres éléments qui nécessitent généralement un script de configuration distinct pour être localisés.
ses informations relatives à la présence d'éléments dans le système de fichiers peuvent ne pas être
valide. Par exemple, $Config{'cc'} fait référence au compilateur C avec lequel Perl a été construit,
Ce compilateur C pourrait ne pas être celui que vous souhaitez utiliser. Il pourrait même ne pas exister.
sur votre système, puisque vous avez probablement installé Perl via un paquet binaire.

Tips pour grâce à caractères génériques
Adapter tous fichiers sauf a certaines sous-ensemble

Les caractères génériques de Makepp n'ont actuellement aucun moyen de faire correspondre tous les fichiers sauf un certain
définir, mais vous pouvez le faire avec une combinaison de fonctions.

Par exemple, supposons que vous ayez un programme de test pour chaque module d'une bibliothèque, mais que vous n'en ayez pas.
Je souhaite inclure les programmes de test dans la bibliothèque. Si tous les programmes de test commencent par
tester, alors vous pouvez les exclure comme ceci :

libproduction.a : $(test de filtrage*, $(caractère générique *.o))

Les fonctions « $(filter ) » et « $(filter_out ) » sont un ensemble de filtres très puissants à réaliser
toutes sortes d'opérations d'intersection et de différence d'ensembles. Par exemple,

SOUS-RÉPERTOIRES ;= $(filter_out *test* *$(ARCH)*, $(shell find . -type d -print))
# Renvoie tous les sous-répertoires qui n'ont pas
# "test" ou $(ARCH) dedans.

$(filtre $(patsubst test_dir/test_%.o, %.o, $(wildcard test_dir/*.o)), \
$(caractère générique *.o))
# Renvoie une liste de fichiers .o dans le répertoire actuel
# répertoire pour lequel il existe un correspondant
# fichier test_*.o dans le sous-répertoire test_dir.
$(filter_out $(patsubst man/man3/%.3, %.o, $(wildcard man/man3/*.3)), \
$(caractère générique *.o))
# Renvoie une liste de fichiers .o dans le répertoire actuel
# répertoire pour lequel il n'existe pas de page de manuel
# avec le même nom de fichier dans le sous-répertoire man/man3.

En utilisant le "$(cibles_uniques )" fonction à éliminé rassis .o fichiers

Supposons que vous construisiez un programme ou une bibliothèque avec une commande de construction comme celle-ci :

programme : *.o
$(CC) $(entrées) -o $(sortie)

Supposons que vous supprimiez maintenant un fichier source. Si vous oubliez de supprimer le fichier correspondant, .o fichier,
Il sera toujours lié, même s'il n'y a plus moyen de le construire.
À l'avenir, Makepp reconnaîtra probablement cette situation automatiquement et l'exclura de
la liste des caractères génériques, mais pour le moment, vous devez lui dire de l'exclure manuellement :

programme : $(only_targets *.o)
$(CC) $(entrées) -o $(sorties)

Makepp ne connaît aucun moyen de construire l'ancien .o fichier plus puisque son fichier source est
disparu, donc la fonction "$(only_targets )" l'exclura de la liste des dépendances.

Tips pour plusieurs répertoires
L’une des principales raisons pour lesquelles j’ai écrit makepp était de simplifier la gestion de plusieurs
répertoires. Makepp est capable de combiner les commandes de construction de plusieurs fichiers Makefiles, ce qui lui permet
traiter correctement une règle dans un makefile qui dépend d'un fichier construit par un
fichier makefile différent.

Organisateur Ce que à do in endroit of récursif a prendre une

Makepp prend en charge la création récursive pour la compatibilité descendante, mais cela est fortement recommandé
que vous pas Utilisez-le. Si vous ne savez pas ce que c'est, tant mieux.

Voir « Meilleur système pour les builds hiérarchiques » dans makepp pour plus de détails sur les raisons pour lesquelles vous ne voulez pas
utilisez le make récursif, ou bien recherchez sur le Web « make récursif considéré comme dangereux ».

Au lieu de faire un make récursif pour créer la cible « all » dans chaque makefile, il est
Il est généralement plus facile de laisser Makepp déterminer quelles cibles devront réellement être construites.
De plus, si vous mettez tout votre .o et les fichiers de bibliothèque dans le même répertoire que le
makefiles, puis makepp déterminera automatiquement quels makefiles sont également nécessaires - le
la seule chose nécessaire est que votre niveau supérieur dresse la liste des fichiers nécessaires
Pour l'étape finale de liaison. Voir les exemples ci-dessous.

UN makefile pour chacun annuaire: avec implicitement chargement

La manière la plus courante de gérer plusieurs répertoires est de placer un makefile dans chaque répertoire.
qui décrit comment tout construire dans ou à partir de ce répertoire. Si vous mettez .o les fichiers
le même répertoire que les fichiers sources, puis chargement implicite (voir « Chargement implicite » dans
makepp_build_algorithm) trouvera automatiquement tous les makefiles. Si vous placez votre .o
fichiers dans un répertoire différent (par exemple, dans un sous-répertoire dépendant de l'architecture), alors vous
il faudra probablement charger tous les makefiles pertinents en utilisant l'instruction "load_makefile".

Voici un exemple de fichier Makefile de niveau supérieur pour une hiérarchie de répertoires qui utilise le chargement implicite
pour construire un programme composé de nombreuses bibliothèques partagées (mais voir « Avez-vous vraiment besoin d'un
bibliothèque ?" dans makepp_cookbook, car créer un programme à partir d'un ensemble de bibliothèques partagées
n'est pas forcément une bonne idée) :

# Makefile de niveau supérieur :
programme : main.o **/*.la # Lien dans les bibliothèques partagées de tous les sous-répertoires.
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(entrées) -o $(sortie) $(LIBS)

C'est à peu près tout ce dont vous avez besoin dans le fichier Makefile de niveau supérieur. Dans chaque sous-répertoire,
je ferais probablement quelque chose comme ça :

# Makefile dans chaque sous-répertoire :
inclure standard_defs.mk # Recherches ., .., ../ .., etc. jusqu'à ce qu'il
# trouve le fichier d'inclusion indiqué.
# remplacer certaines définitions de variables ici
SPECIAL_FLAGS := -faire_quelque_chose_de_différent

Chaque makefile peut probablement être à peu près le même si les commandes pour construire les cibles
sont assez similaires.

Enfin, vous devez mettre les éléments suivants dans le standard_defs.mk fichier (qui devrait probablement
être situé dans le répertoire de niveau supérieur) :

# Paramètres de variables communs et règles de construction pour tous les répertoires.
CLAPET := -g -O2
INCLUDE_DIR := $(find_upwards inclut)
# Recherches ., .., ../ .., etc. pour un fichier ou
# répertoire appelé includes, donc si vous mettez
# tous vos fichiers inclus là-dedans, cela va
# les trouver.
INCLUT := -I$(INCLUDE_DIR)

%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(entrée) -o $(sortie)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(sortie) $(entrées)
# $(relative_to ., ..) renvoie le nom du fichier courant
# sous-répertoire relatif au niveau supérieur
# sous-répertoire. Donc, si ce makefile est xyz/Makefile,
# cette règle va construire xyz/libxyz.la.

# Publier les fichiers d'inclusion publics dans le répertoire d'inclusion de niveau supérieur :
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check symbole
&ln -fr $(entrée) $(sortie)

UN makefile pour chacun annuaire: explicite chargement

Si vous voulez mettre tous vos .o fichiers dans un sous-répertoire dépendant de l'architecture, puis
l'exemple ci-dessus devrait être modifié pour ressembler à ceci :

# Makefile de niveau supérieur :
MAKEFILES := $(wildcard **/Makeppfile) # Liste de tous les sous-répertoires à
# obtenir les makefiles à partir de.

load_makefile $(MAKEFILES) # Chargez-les tous.

inclure standard_defs.mk # Obtenir la commande de compilation pour main.o.

programme : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(entrées) -o $(sortie) $(LIBS)
# */**/$(ARCH) exclut le sous-répertoire
# $(ARCH), où nous ne voulons pas construire
# une bibliothèque partagée.

Chaque makefile serait exactement le même qu'avant :

# Makefile dans chaque sous-répertoire :
inclure standard_defs.mk
# ... les variables remplacent ici

Et enfin, standard_defs.mk contiendrait quelque chose comme ce qui suit :

# Paramètres de variables communs et règles de construction pour tous les répertoires.
ARCH ;= $(shell uname -s)-$(shell uname -m)-$(shell uname -r)
# Parfois, les gens n'utilisent que $(shell uname -m), mais
# ce sera la même chose pour FreeBSD et Linux sur
# un x86. Le -r n'est pas vraiment utile sous Linux,
# mais c'est important pour d'autres systèmes d'exploitation : binaires pour
# SunOS 5.8 ne fonctionnera généralement pas sur SunOS 5.7.
&mkdir -p $(ARCH) # Assurez-vous que le répertoire de sortie existe.
CLAPET := -g -O2
INCLUDE_DIR := $(find_upwards inclut)
# Recherches ., .., ../ .., etc. pour un fichier ou
# répertoire appelé includes, donc si vous mettez
# tous vos fichiers inclus là-dedans, cela va
# les trouver.
INCLUT := -I$(INCLUDE_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(INCLUDES) -c $(entrée) -o $(sortie)

$(ARCH)/ lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(sortie) $(entrées)
# $(relative_to ., ..) renvoie le nom du fichier courant
# sous-répertoire relatif au niveau supérieur
# sous-répertoire. Donc, si ce makefile est xyz/Makefile,
# cette règle construira xyz/$(ARCH)/libxyz.la.

# Copiez les fichiers d'inclusion publics dans le répertoire d'inclusion de niveau supérieur :
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(entrée) $(sortie)

Automatiquement Rendre le le fichiers make

Si vos makefiles sont tous extrêmement similaires (comme dans l'exemple ci-dessus), vous pouvez indiquer à Makepp
pour les générer automatiquement s'ils n'existent pas. Ajoutez simplement ce qui suit à votre niveau supérieur.
fichier makefile:

SUBDIRS := $(filter_out indésirable_dir1 indésirable_dir2, $(wildcard */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "inclure standard_defs.mk" -o $(sortie)
&echo "_include additional_defs.mk" -o >>$(sortie)
# Si le fichier additional_defs.mk existe, alors
# il sera inclus, mais s'il n'existe pas,
# l'instruction _include sera ignorée.

Désormais, les makefiles eux-mêmes seront automatiquement construits.

UN makefile uniquement at le top niveau

Si tous vos makefiles sont identiques, vous vous demandez peut-être : pourquoi devrais-je avoir un makefile à chaque fois ?
niveau ? Pourquoi ne pas tout mettre dans le makefile de niveau supérieur ?

Oui, c'est possible. Le principal inconvénient est qu'il devient plus difficile à spécifier.
différentes options de construction pour chaque sous-répertoire. Un deuxième inconvénient est que votre
Le makefile deviendra probablement un peu plus difficile à lire.

Voici un exemple qui illustre exactement cela :

# Makefile de niveau supérieur pour la hiérarchie des répertoires. Crée le programme.
# parmi un ensemble de bibliothèques partagées à titre d'exemple. (Voir les mises en garde ci-dessus
# pourquoi vous pourriez vouloir utiliser la liaison incrémentielle ou une autre
# approche plutôt que des bibliothèques partagées.)
makepp_percent_subdirs := 1 # Autoriser % à correspondre à plusieurs répertoires.
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(wildcard **))
CLAPET := -g -O2
INCLUT := -Iincludes

%.lo: %.c
$(LIBTOOL) --mode=compile $(CC) $(INCLUS) $(CFLAGS) -c $(entrée) -o $(sortie)

$(foreach)/ lib$(notdir $(foreach)).la : $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(sortie) $(entrées)
# Règle pour créer toutes les bibliothèques.

programme : main.o **/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(sortie) $(entrées)

inclut/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(entrée) $(sortie)
# Exemple de règle pour copier le public
# fichiers .h accessibles au bon endroit.

A espace extérieur plus propre, l'objectif

Les makefiles traditionnels contiennent une cible propre, qui permet de supprimer tout ce qui a été
Construit. Il y a trois raisons pour lesquelles vous ne devriez pas faire cela avec makepp :

1. Makepp met tout en œuvre pour garantir une construction correcte. Ainsi, les désespérés qui disent « Je ne sais pas
"savoir ce qui ne va pas", vous donner envie de tout recommencer à zéro est une chose du passé.

2. Les gens essaient parfois de gagner du temps en faisant deux choses contradictoires à la fois :
« make clean all ». Cela peut perturber le système de caractères génériques intelligents de makepp, car cela
Il faut d'abord se renseigner avant d'agir. Vient ensuite l'action propre, qui
ne pas dire à Makepp ce qu'il fait (en effet, il ne peut pas, car il annule quelque chose - le
(contrairement à la fonction d'un outil de compilation). Vient ensuite « tous », sauf les fichiers à jour,
qui étaient là, ont mystérieusement disparu.

3. Il existe la commande « makeppclean », qui fait la même chose, et plus efficacement.

Néanmoins, nous conservons cette section historique, car elle vous dit quelque chose sur la
Comment fonctionne Makepp : une fausse cible appelée « clean » n'est qu'un nom pour un ensemble de commandes à exécuter.
supprimer tous les fichiers résultant du processus de création. En général, une cible propre
quelque chose comme ça:

$(faux nettoyage) :
&rm -fm $(caractère générique *.o .makepp_log)
# -m et .makepp_log se débarrassent de tous les fichiers indésirables de makepp.

Au lieu de lister explicitement les fichiers que vous souhaitez supprimer, vous pouvez également demander à makepp de
supprimer tout ce qu'il sait construire, comme ceci :

$(faux nettoyage) :
&rm -fm .makepp_log $(only_targets *)

Cela présente l’avantage que si l’un de vos fichiers sources peut être construit à partir d’autres fichiers,
ils seront également supprimés ; d'autre part, les fichiers obsolètes .o fichiers (fichiers qui étaient auparavant
constructible mais dont le fichier source a depuis été supprimé) ne sera pas supprimé.

Si vous avez une construction qui implique des makefiles dans plusieurs répertoires différents, votre top-
Le makefile de niveau peut référencer la cible « propre » (ou toute autre fausse cible) dans un fichier différent
fichier makefile:

# Makefile de niveau supérieur
SOUS-RÉPERTOIRES := sub1 sub2

# règles de construction ici

# Nettoyage après la construction :
$(propreté factice) : $(SUBDIRS)/clean
&rm -fm .makepp_log $(only_targets *)

Alternativement, vous pouvez placer votre cible « propre » uniquement dans le makefile de niveau supérieur et le faire
traiter tous les répertoires, comme ceci :

$(faux nettoyage) :
&rm -fm $(cibles_uniquement **/*)

En utilisant Qt moqueur préprocesseur
Cet exemple montre un fichier makefile pour un utilitaire qui utilise la bibliothèque Qt GUI de Nokia (voir
<http://qt.nokia.com>). La seule chose qui est légèrement inhabituelle à ce sujet est que vous
doit exécuter un préprocesseur appelé « moc » sur la plupart des fichiers « .h » qui contiennent des définitions de widgets,
mais vous ne voulez pas exécuter « moc » sur des fichiers « .h » qui n'utilisent pas la macro « Q_OBJECT ».

Automatiquement détermination qui fichiers need moqueur fichiers

Vous pouvez, bien sûr, simplement lister tous les fichiers « .h » sur lesquels « moc » doit être exécuté.
Cependant, si vous développez rapidement de nouveaux widgets, cela peut être quelque peu gênant.
Continuez à mettre à jour la liste dans le makefile. Vous pouvez contourner la nécessité de lister le moc.
modules explicitement avec quelque chose comme ceci :

MOC := $(QTDIR)/bin/moc
MODULES := quels modules que vous avez dans votre programme
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# Analyse tous les fichiers .h pour la macro Q_OBJECT.

mon_programme : $(MODULES).o $(MOC_MODULES).o
$(CXX) $(entrées) -o $(sortie)

moc_%.cxx : %.h # Crée les fichiers moc à partir des fichiers .h.
$(MOC) $(entrée) -o $(sortie)

%.o : %cxx
$(CXX) $(CXXFLAGS) -c $(entrée) -o $(sortie)

Cette approche analyse chacun de vos .h fichiers à chaque fois que makepp est exécuté, à la recherche du
Macro « Q_OBJECT ». Cela semble coûteux, mais cela ne devrait pas prendre beaucoup de temps. .h
les fichiers devront tous être chargés à partir du disque de toute façon par le processus de compilation, donc ils seront
être mis en cache.)

#comprendre le .moc filet

Une autre approche consiste à « #inclure » ​​la sortie du préprocesseur « moc » dans votre widget
fichier d'implémentation. Cela signifie que vous devez penser à écrire le « #include », mais il a
l'avantage qu'il y a moins de modules à compiler, et donc la compilation est plus rapide.
(Pour la plupart des compilations C++, la majorité du temps est consacrée à la lecture des fichiers d'en-tête, et
la sortie du préprocesseur doit inclure presque autant de fichiers que votre widget
de toute façon.) Par exemple :

// mon_widget.h
classe MonWidget : public QWidget {
Q_OBJET
/ / ...
}

// mon_widget.cpp

#include "mon_widget.h"
#include "my_widget.moc" // my_widget.moc est la sortie du
// préprocesseur moc.
// Autres éléments d'implémentation ici.
MyWidget::MyWidget(QWidget * parent, const char * nom) :
QWidget(parent, nom)
{
/ / ...
}

Vous devez maintenant avoir une règle dans votre makefile pour créer tous les fichiers « .moc », comme ceci :

MOC := $(QTDIR)/bin/moc
# Règle pour créer des fichiers .moc :
%.moc: %.h
$(MOC) $(entrée) -o $(sortie)

Makepp est suffisamment intelligent pour comprendre qu'il doit créer "my_widget.moc" s'il ne le fait pas
existe déjà, ou s'il est obsolète.

Cette deuxième approche est celle que j’utilise habituellement car elle accélère la compilation.

Remplaçants pour obsolète a prendre une expressions idiomatiques
MAKECMD OBJECTIFS

Parfois, les gens ont des règles dans leur makefile qui dépendent de la cible qu'ils construisent,
en utilisant la variable spéciale « MAKECMDGOALS ». Par exemple, on voit parfois des choses comme
ce:

ifneq ($(filtre de production, $(MAKECMDGOALS)),)
CLAPET := -O2
d'autre
CLAGS := -g
fin si

Cela fonctionnera parfaitement avec Makepp. Cependant, je recommande de ne pas utiliser « MAKECMDGOALS » pour ce type de tâche.
cas (et le manuel GNU Make aussi). Il est préférable de placer vos fichiers optimisés et
compilé pour le débogage .o fichiers dans des répertoires séparés, ou en leur donnant des préfixes différents ou
suffixes, ou en utilisant des référentiels, pour les garder séparés.

Le seul moment où vous pourriez réellement vouloir faire référence à « MAKECMDGOALS » est probablement si
le chargement de vos makefiles prend beaucoup de temps, et vous n'en avez pas besoin pour votre cible « propre »
(mais vous n'avez pas besoin d'une cible propre). Par exemple,

ifneq ($(MAKECMDGOALS),nettoyer)
load_makefile $(caractère générique **/Makeppfile)
d'autre
no_implicit_load . # Empêche le chargement automatique de tout autre makefile.
fin si

$(faux nettoyage) :
&rm -f $(caractère générique **/*.o)

Récursif a prendre une à construire in différent répertoires

Voir « Conseils pour plusieurs répertoires » dans makepp_cookbook.

Récursif a prendre une à Change Plus-value of a variable

Certains makefiles se réinvoquent avec une valeur différente d'une variable, par exemple, le debug
cible dans le fragment de makefile suivant

.PHONY : tout débogage

optimisé:
programme $(MAKE) CFLAGS=-O2

déboguer:
programme $(MAKE) CFLAGS=-g

programme : ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

Si l'utilisateur tape « make debug », il construit le programme en mode par défaut avec le débogage activé
au lieu d'une optimisation.

Une meilleure façon de procéder est de créer deux programmes différents, avec deux ensembles de
fichiers objets, comme ceci :

CLAPET := -O2
DEBUG_FLAGS := -g
MODULES := ab

programme : $(MODULES).o
$(CC) $(CFLAGS) $(entrées) -o $(sortie)

débogage/programme : debug/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(entrées) -o $(sortie)

%.o : %.c
$(CC) $(CFLAGS) -c $(entrée) -o $(sortie)

débogage/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(entrée) -o $(sortie)

$(phony debug) : débogage/programme

L'avantage de procéder de cette façon est que (a) vous n'avez pas besoin de tout reconstruire lorsque vous
passer du débogage à l'optimisation et inversement ; (b)

Ce qui précède peut être rédigé de manière plus concise à l'aide de référentiels.
makefile est exactement équivalent :

repository debug=. # Fait en sorte que le sous-répertoire de débogage ressemble à une copie de
# le sous-répertoire actuel.
load_makefile debug CFLAGS=-g
# Remplacer CFLAGS lorsqu'il est invoqué dans le sous-répertoire de débogage
CFLAGS := -O2 # Valeur de CFLAGS lorsqu'il est invoqué dans ce sous-répertoire

programme : ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

$(phony debug) : débogage/programme
# Si l'utilisateur tape « makepp debug », il construit
# debug/program au lieu de program.

Divers conseils
Comment la do I construire UN partie différemment juste une fois?

Makepp rend cela difficile à faire car le résultat est incohérent par rapport aux règles.
Mais il existe des situations où vous pourriez en avoir besoin, par exemple pour compiler un seul module avec
informations de débogage importantes. Vous pouvez y parvenir en deux étapes : d'abord,
dépendance séparément, puis en l'excluant de la phase de liaison :

makepp DEBUG=3 buggy.o # Construisez-le avec une autre option.
makepp --dont-build=buggy.o buggy # Utilisez-le, malgré une option de construction « erronée ».

Comment la do I a prendre une sûr my sortie répertoires exister?

Vous pouvez spécifier une règle pour créer le répertoire de sortie, puis vous assurer que chaque fichier qui
Le répertoire de sortie dépend de cela. Il est généralement plus simple de procéder comme suit :
ce:

# La voie classique
factice := $(shell test -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# C'est généralement plus simple que de faire dépendre tous les fichiers de
# $(OUTPUT_DIRECTORY) et avoir une règle pour le faire.
# Notez que vous devez utiliser := au lieu de = pour le forcer à
# exécuter immédiatement.
# Une approche alternative : utiliser du code Perl, OUTPUT_DIRECTORY var locale
perl_begin
-d $OUTPUT_DIRECTORY ou mkdir $OUTPUT_DIRECTORY ;
perl_end
# La méthode moderne ne fait rien pour les répertoires existants
&mkdir -p $(RÉPERTOIRE_DE_SORTIE)

L'une de ces instructions doit être située en haut de votre fichier makefile, afin qu'elles soient exécutées.
avant tout ce qui pourrait éventuellement nécessiter le répertoire.

Comment la do I forcer a commander à exécuter on chaque construire?

Le moyen le plus simple est de ne pas utiliser du tout le mécanisme de règle, mais simplement de l'exécuter, comme
ce:

factice := $(date du shell > horodatage de la dernière construction)

Ou placez-le dans un bloc Perl, comme ceci :

perl_begin
system("commande à exécuter");
perl_end

Cette approche présente l’inconvénient qu’elle sera exécutée même si une cible non liée est
étant exécuté.

Une deuxième approche consiste à déclarer le fichier comme une fausse cible, même s’il s’agit d’un vrai fichier.
Cela forcera makepp à réexécuter la commande pour la construire à chaque fois, mais seulement si elle
apparaît dans la liste des dépendances d'une règle.

Comment la do I raccourcir le dans construire commandes?

Souvent, il existe tellement d'options pour les commandes de compilation que ce qui est affiché sur l'écran
L'écran est illisible. Vous pouvez modifier le contenu affiché en supprimant l'affichage de
commande entière, puis imprimez explicitement la partie intéressante de la commande. C'est
il est facile d'imprimer uniquement la partie pertinente de la commande en utilisant "$(filter_out )", comme
ce:

ALL_CFLAGS = $(CFLAGS) $(INCLUT) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o : %.c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(entrée)
@$(CC) $(ALL_CFLAGS) -c $(entrée) -o $(sortie)

(Le « @ » devant la commande supprime l’impression de la commande.)

Cela vous permettra de voir la plupart des options intéressantes, mais n'affichera pas toutes les
inclure des répertoires (souvent très nombreux !). Si la partie qui vous intéresse
dans est contigu dans votre commande, vous pouvez également utiliser la fonction « imprimer » (qui ajoute un
nouvelle ligne, vous n'en voulez donc pas plusieurs) :

Cible:
@... $(imprimer la partie intéressante) ...

Comment la do I convertir a filet développement dépendances ?

Pour certains formats de fichiers peu connus, l'implémentation d'un scanner n'est pas rentable. Dans un projet,
nous avons des fichiers xml, disons foobar.xml qui contient les dépendances pour foobar.out:


un
b
c


Nous avons décidé de conserver cette mise en page simple, afin de ne pas avoir à analyser le XML.
builtin &sed, voici ce que nous faisons avec trois substitutions simples pour les trois types de
lignes:

%.d: %.xml
&sed 's! !$(stem).out: \\! || s! (.+) !$$1 \\! || s! !# Vide!' \
$(entrée) -o $(sortie)

inclure foobar.d

En essayant d'inclure ceci, on obtient d'abord « foobar.d » :

foobar.out: \
une \
b \
c\
# Vide

Une ligne vide (juste un commentaire ou vraiment vide) évite d'avoir à se soucier de la fin
Barre oblique inverse. Une alternative pour produire une liste multiligne est :

%.d: %.xml
&sed 's! !$(tige).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(entrée) -o $(sortie)

inclure foobar.d

Cela produit un équivalent :

foobar.out: $((
a
b
c
))

Si vous avez une réécriture plus complexe à faire, définissez une fonction dans le makefile ou dans un
Module que vous incluez. Par exemple, si vous annulez la définition de $_, les lignes d'entrée seront ignorées :

sous mon filtre {
renvoie undef $_ si /
mon $stem = f_stem;
s! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&sed 's! !$(tige).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(entrée) -o $(sortie)

inclure foobar.d

Utilisez makepp_cookbook en ligne avec les services onworks.net


Serveurs et postes de travail gratuits

Télécharger des applications Windows et Linux

Commandes Linux

Ad




×
Publicité
❤ ️Achetez, réservez ou achetez ici — gratuitement, contribue à maintenir la gratuité des services.