2017-08-12 5 views
2

Je tente de créer un seul makefile récursif de niveau supérieur, l'idée étant qu'une fois le fichier makefile créé, il ne nécessitera que peu de maintenance lorsque des fichiers sont ajoutés ou supprimés le projet. Le problème que j'ai est quand il y a des fichiers avec le même nom, mais réside dans des répertoires différents, GNU make utilisera le fichier .cpp du premier répertoire est voit dans le reste de la construction et quand l'éditeur de liens fonctionne , il se plaint de plusieurs définitions d'une fonction car les fichiers .o générés sont tous basés sur le même fichier source.GNU Réutiliser le fichier source lorsque d'autres fichiers portent le même nom

Le code que je référence ci-dessous n'est pas le code de mon projet actuel mais il présente les mêmes problèmes que ceux que j'ai en essayant de construire mon projet principal. Voici la disposition de mon répertoire de premier niveau avec le code source résidant dans les sous-répertoires.

[email protected]:~/work/temp/maketest$ tree 
. 
├── exec 
│   └── main.cpp 
├── hello 
│   ├── hello.cpp 
│   └── hello.h 
├── makefile 
└── world 
    ├── hello.cpp 
    └── hello.h 

Cet exemple est assez simple - bonjour/imprime bonjour.cpp "Bonjour" et monde/imprime bonjour.cpp "World !!". main.cpp appelle chaque fonction pour imprimer "HelloWorld !!"

Voici chaque fichier.

exec/main.cpp

#include <iostream> 
#include "../hello/hello.h" 
#include "../world/hello.h" 

int main() 
{ 
    print_hello(); 
    print_world(); 
    return 0; 
} 

bonjour/hello.cpp

#include "hello.h" 

void print_hello() 
{ 
    std::cout << "Hello"; 
} 

monde/hello.cpp

#include "hello.h" 

void print_world() 
{ 
    std::cout << "World!!\n"; 
} 

Voici mon makefile

#Specify modules to include in the build - corresponds to source code locations. 
MODULES := exec \ 
world \ 
hello 

CXX := g++ 
RM := rm -rf 

#Create a list of the source directories 
SRC_DIR  := $(addprefix ./,$(MODULES)) 

#Create a variable for the build output directory 
BUILD_DIR := $(addprefix ./build/,$(MODULES)) 

#C++ Compiler flags 
CPPFLAGS := -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c 

#Flags for generating dependency files. 
DEPFLAGS := -MMD -MP -MT "[email protected]" -MF "$$(@:%.o=%.d)" 

#Creates a list of all the source files that we wish to include in the build 
CPP_SRCS := $(foreach sdir, $(SRC_DIR), $(wildcard $(sdir)/*.cpp)) 

#Creates a list of all the object files that we need to build based off source files 
OBJ_TARGET := $(foreach sdir, $(MODULES), $(wildcard $(sdir)/*.cpp)) 
OBJS  := $(patsubst %.cpp, ./build/%.o, $(OBJ_TARGET)) 

#Specify directories to search 
vpath %.cpp $(SRC_DIR) $(BUILD_DIR) 

#"function" that contains the rule to make the .o files that exist within a source director and sub-directory 
define make-goal 
$1/%.o: %.cpp 
    @echo 'Building file: $$<' 
    @echo 'Invoking: Linux G++ Compiler' 
    $(CXX) $(CPPFLAGS) "$$<" -o "[email protected]" $(DEPFLAGS) 
    @echo 'Finished building: $$<' 
    @echo ' ' 
endef 

.PHONY: all checkdirs clean build/HelloWorld 

all: checkdirs build/HelloWorld 

build/HelloWorld: $(OBJS) 
    @echo 'Building Target: [email protected]' 
    @echo 'Invoking: G++ Linker' 
    $(CXX) -L/usr/local/lib $^ -o [email protected] 
    @echo 'Finished building target: [email protected]' 
    @echo ' ' 

clean: 
    -$(RM) $(BUILD_DIR) 

#Makes sure that the output directory exists 
checkdirs: $(BUILD_DIR) 

#Creates the output directory, build, if it doesn't exist 
$(BUILD_DIR): 
    @mkdir -p [email protected] 

#This is the important "recursive" part - this will loop through all source directories and call 'make-goal', which contains the rule to make the associated .o file. 
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir)))) 

Et quand je tente de construire ce petit projet, je reçois ce qui suit. Notez que ./world/hello.cpp est utilisé deux fois lors de la construction des fichiers .o - la première fois est sortie pour construire/world/hello.o et la seconde fois pour /build/hello/hello.o, puis l'éditeur de liens échoue car Les fichiers .o sont les mêmes.

Building file: ./exec/main.cpp 
Invoking: Linux G++ Compiler 
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./exec/main.cpp" -o "build/exec/main.o" -MMD -MP -MT "build/exec/main.o" -MF "build/exec/main.d" 
Finished building: ./exec/main.cpp 

Building file: ./world/hello.cpp 
Invoking: Linux G++ Compiler 
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./world/hello.cpp" -o "build/world/hello.o" -MMD -MP -MT "build/world/hello.o" -MF "build/world/hello.d" 
Finished building: ./world/hello.cpp 

Building file: ./world/hello.cpp 
Invoking: Linux G++ Compiler 
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./world/hello.cpp" -o "build/hello/hello.o" -MMD -MP -MT "build/hello/hello.o" -MF "build/hello/hello.d" 
Finished building: ./world/hello.cpp 

Building Target: build/HelloWorld 
Invoking: G++ Linker 

CPP_SRCS: ./exec/main.cpp ./world/hello.cpp ./hello/hello.cpp 

g++ -L/usr/local/lib build/exec/main.o build/world/hello.o build/hello/hello.o -o build/HelloWorld 
build/hello/hello.o: In function `print_world()': 
/home/otter/work/temp/maketest/./world/hello.cpp:4: multiple definition of `print_world()' 
build/world/hello.o:/home/otter/work/temp/maketest/./world/hello.cpp:4: first defined here 
build/exec/main.o: In function `main': 
/home/otter/work/temp/maketest/./exec/main.cpp:7: undefined reference to `print_hello()' 
collect2: error: ld returned 1 exit status 
makefile:46: recipe for target 'build/HelloWorld' failed 
make: *** [build/HelloWorld] Error 1 

Cela veut-il que quelqu'un sait pourquoi ./world/hello.cpp est utilisé deux fois lors de la construction des fichiers .o? Même si les fichiers .cpp ont le même nom, ils sont dans des répertoires différents et je pense que make serait assez intelligent pour les traiter comme des fichiers différents et ne pas réutiliser le premier fichier chaque fois qu'il voit les fichiers suivants avec le même nom.

+0

'$ 1 /% o:% .cpp' - la partie" $ 1 "semble incorrecte. –

+1

Votre répertoire 'vpath' indique à make de chercher dans' SRC_DIR' et 'BUILD_DIR'. Bien que placer le répertoire de construction comme un répertoire source 'vpath' n'a aucun sens, la cause première de votre problème est que' vpath' va chercher les répertoires que vous fournissez dans l'ordre, et 'world' vient avant' hello' dans ' MODULES'. – user657267

Répondre

1

Je ne sais pas pourquoi votre approche ne fonctionne pas - je vais essayer de résoudre plus tard si j'ai le temps - mais il y a une approche beaucoup plus facile:

build/HelloWorld: $(OBJS) 
    @echo 'Building Target: [email protected]' 
    @echo 'Invoking: G++ Linker' 
    $(CXX) -L/usr/local/lib $^ -o [email protected] 
    @echo 'Finished building target: [email protected]' 
    @echo ' ' 


$(OBJS): build/%.o: %.cpp 
    @echo building [email protected] from $< 
    mkdir -p $(dir [email protected]) 
    $(CXX) $(CPPFLAGS) $< -o [email protected] 

EDIT: user657267 a trouvé pourquoi votre approche ne fonctionnait pas.