2010-10-27 9 views
37

J'ai une bibliothèque C++ construite en utilisant un Makefile. Jusqu'à récemment, toutes les sources étaient dans un seul répertoire, et le Makefile fait quelque chose comme çaSources de sous-répertoires dans Makefile

SOURCES = $(wildcard *.cpp)

qui a bien fonctionné.

Maintenant, j'ai ajouté certaines sources qui sont dans un sous-répertoire, disons subdir. Je sais que je peux le faire

SOURCES = $(wildcard *.cpp) $(wildcard subdir/*.cpp)

mais je suis à la recherche d'un moyen d'éviter de spécifier manuellement subdir, qui est, faire wildcard regarder dans les sous-répertoires, ou de générer une liste des sous-répertoires en quelque sorte et l'étendre avec plusieurs wildcard fonctions. À ce stade, avoir une solution non récursive (c'est-à-dire étendre seulement le premier niveau) serait bien.

Je n'ai rien trouvé - ma meilleure estimation est d'utiliser find -type d pour lister les sous-répertoires, mais cela ressemble à un hack. Y a-t-il un moyen intégré de le faire?

+0

duplication possible de [caractères génériques récursifs dans GNU make?] (Http://stackoverflow.com/questions/2483182/recursive-wildcards-in-gnu-make) –

+0

@Jeroen devrait être l'inverse car cette question a une réponse supérieure (en utilisant '**'). – rightfold

Répondre

53

Cela devrait le faire:

SOURCES = $(wildcard *.cpp) $(wildcard */*.cpp) 

Si vous vous changez d'avis et souhaitez un solution récursive (c'est-à-dire à n'importe quelle profondeur), cela peut être fait mais cela implique certaines des fonctions Make les plus puissantes. Vous savez, ceux qui vous permettent de faire des choses que vous ne devriez vraiment pas faire.

EDIT:
souligne Jack Kelly que $(wildcard **/*.cpp) œuvres à toute profondeur, au moins sur certaines plates-formes, en utilisant gnumake 3,81. (Comment il a compris cela, je n'ai aucune idée.)

+19

Pour chercher à n'importe quelle profondeur, je pense que $ (joker **/*. Cpp) 'fonctionnerait. –

+1

@Jack Kelly: J'ai juste essayé ça et ça n'a pas marché (GNU Make 3.81). Est-ce que cela fonctionne avec votre version? – Beta

+0

Oui. Je suis aussi sur GNU Make 3.81, donc peut-être parce que quelque chose d'autre (glob?) Se comporte différemment sur nos plateformes? Je suis sur Ubuntu 10.10 amd64. –

9

Common practice est de mettre un Makefile dans chaque subdir avec des sources, puis

all: recursive 
    $(MAKE) -C componentX 
    # stuff for current dir 

ou

all: recursive 
    cd componentX && $(MAKE) 
    # stuff for current dir 

recursive: true 

Il peut être judicieux de mettre les paramètres pour chaque Makefile dans un Makefile.inc dans le répertoire racine source . La cible recursive force make à aller dans les sous-répertoires. Assurez-vous qu'il ne recompile rien dans une cible nécessitant recursive.

+0

Bien sûr, mais je devrais encore écrire "componentX" à la main, ce que j'essaie d'éviter. – ggambett

+2

Veuillez le faire de cette façon. Simplement compiler et lier chaque fichier source/objet dans chaque sous-répertoire va casser une fois que vous voulez construire une bibliothèque, construire un fichier avec des paramètres spéciaux du compilateur, écrire des programmes de test, etc Je liste toujours chaque fichier objet dans mes Makefiles et parfois chaque fichier source unique. La liste de quelques répertoires à boucler n'est pas vraiment pénible. –

+4

N'appelez pas 'make -C' directement. Vous devez appeler '$ (MAKE) -C' à la place. La version de 'make' en cours d'exécution pourrait être différente du système' make'. De plus, n'allez-vous pas déclencher une boucle infinie en exécutant '$ (MAKE) $ @'? Enfin, la marque récursive est considérée comme nuisible par certains. Voir http://miller.emu.id.au/pmiller/books/rmch/ –

7

Ceci est une note de côté et ne répond pas à votre question, mais il y a un papier "Recursive Make Considered Nocif". Ça vaut le coup de lire.

Voici le lien. http://aegis.sourceforge.net/auug97.pdf

+3

+1. Je déteste la marque récursive et je ne pense pas que quiconque devrait la promouvoir. Donner aux sous-répertoires make.includes n'est pas plus difficile que de leur donner leurs propres makefiles. En fait, c'est un peu plus facile car ils n'ont pas besoin d'inclure un fichier "dieu" avec toutes les définitions du projet. Et bon, vous n'obtenez pas un tas de graphiques de dépendance incomplètes! Ce document donne également d'autres bons conseils. –

+2

Alors que make récursif peut être néfaste, la technique recherchée dans la question d'origine est en fait un moyen * d'éviter * récursif, en rendant le makefile de haut niveau conscient des sources dans tous les sous-répertoires. –

13

Si vous ne souhaitez pas utiliser makefiles récursives, cela pourrait vous donner quelques idées:

subdirs := $(wildcard */) 
sources := $(wildcard $(addsuffix *.cpp,$(subdirs))) 
objects := $(patsubst %.cpp,%.o,$(sources)) 

$(objects) : %.o : %.cpp 
+0

C'est une liste utile de commandes. 'subdirs: = $ (joker * /)' est ce que je cherchais! – Mike

2

Si vous pouvez utiliser la commande shell find, vous pouvez définir une fonction pour l'utiliser.

recurfind = $(shell find $(1) -name '$(2)') 
SRCS := $(call recurfind,subdir1,*.c) $(call recurfind,subdir2,*.cc) $(call recurfind,subdir2,*.cu) \ 
     ... 
16

Les caractères génériques récursifs peuvent être effectués uniquement dans Make, sans appeler le shell ou la commande find.Faire la recherche en utilisant uniquement Make signifie que cette solution fonctionne aussi bien sur Windows que sur * nix.

# Make does not offer a recursive wildcard function, so here's one: 
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)) 

# How to recursively find all files with the same name in a given folder 
ALL_INDEX_HTMLS := $(call rwildcard,foo/,index.html) 

# How to recursively find all files that match a pattern 
ALL_HTMLS := $(call rwildcard,foo/,*.html) 

La barre oblique finale dans le nom du dossier est requise. Cette fonction rwildcard ne prend pas en charge plusieurs caractères génériques de la même façon que la fonction générique intégrée de Make, mais l'ajout de ce support serait simple avec quelques utilisations supplémentaires de foreach.

+0

Cela ne fonctionne pas pour moi. Il renvoie tous les sous-répertoires et fichiers indépendamment du modèle fourni. – Antimony

+0

@Antimony: (Au cas où vous l'auriez fait ...) N'ajoutez pas d'espaces supplémentaires dans les $ récursifs (appel ...) autour des virgules séparant les arguments. L'ajout de tels espaces modifie le résultat. –