2017-03-31 78 views
1

訪問的cpp文件我已經與對象創建一個問題對居住在2名不同的目錄,如下所示一個cpp文件:Makefile文件試圖從其他目錄

- Project-xyz 
    - Hello 
    - Hello.cpp 
    - World 
    - Main.cpp 
    - World.cpp 
    - Makefile 

爲了更清楚這裏代碼的外觀(只是一個虛擬代碼)。

你好/ Hello.h

#ifndef HELLO_H 
#define HELLO_H 

void HelloPrint(); 

#endif // HELLO_H 

你好/ Hell.cpp

#include <iostream> 
#include "Hello.h" 

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

世界/ World.h

#ifndef WORLD_H 
#define WORLD_H 

void WorldPrint(); 

#endif // WORLD_H 

世界/ World.cpp

#include <iostream> 
#include "World.h" 

void WorldPrint() 
{ 
std::cout <<"World!" << std::endl; 
} 

世界/ Makefile中 使用here給出一個makefile。哪個工作正常。但它不會創建任何obj文件。

# set non-optional compiler flags here 
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic-errors 

# set non-optional preprocessor flags here 
# eg. project specific include directories 
CPPFLAGS += 

# find cpp files in subdirectories 
SOURCES := $(shell find . -name '*.cpp') 
SOURCES += $(shell find ../hello -name '*.cpp') 

# find headers 
HEADERS := $(shell find . -name '*.h') 

OUTPUT := HelloWorld 

# Everything depends on the output 
all: $(OUTPUT) 

# The output depends on sources and headers 
$(OUTPUT): $(SOURCES) $(HEADERS) 
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(OUTPUT) $(SOURCES) 

clean: 
    $(RM) $(OUTPUT) 

我看着它採用如圖所示here產生在特定目錄中的OBJ文件生成文件的解決方案。

現在我試圖使用下面的make文件爲world/objdir/hello.o中的hello/hello.cpp文件生成obj文件。哪個不起作用。 如何讓它工作?

世界/ Makefile中

GCC=g++ 
CPPFLAGS=-c -Wall 
LDFLAGS= 
OBJDIR=objdir 
OBJ=$(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp))) 
TARGET=HelloWorld 

.PHONY: all clean 

all: $(OBJDIR) $(TARGET) 

$(OBJDIR): 
    mkdir $(OBJDIR) 

$(OBJDIR)/%.o: %.cpp 
    $(GCC) $(CPPFLAGS) -c $< -o [email protected] 
$(TARGET): $(OBJ) 
    $(GCC) $(LDFLAGS) -o [email protected] $^ 
clean: 
    @rm -f $(TARGET) $(wildcard *.o) 
    @rm -rf $(OBJDIR) 

當我嘗試運行,使其拋出下面的錯誤。

g++ -c -Wall -c main.cpp ../hello/Hello.cpp -o objdir/main.o 
g++: fatal error: cannot specify -o with -c, -S or -E with multiple files 
compilation terminated. 
make: *** [objdir/main.o] Error 4 

它不能爲hello/Hello.cpp文件生成obj文件,因此引發此錯誤。

從makefile大師的任何幫助表示讚賞! :)

+1

-o必須在鏈接「phase」中使用:'link:$(GCC)-o $(TARGET)$(OBJ)'。順便說一句,你的項目中沒有主要 – LPs

+0

哦,對不起,我錯過了補充。這只是一個簡單的代碼,我試圖解釋這個問題。這裏是 #include「../hello/Hello.h」 #include「World。H」 INT主要() { HelloPrint(); 器WorldPrint(); }。 – YOGI

回答

1

添加VPATH%的.cpp ../hello以及@ gaoithe的解決方案已解決此問題。

vpath %.cpp ../hello 
GCC=g++ 
CPPFLAGS=-c -Wall 
LDFLAGS= 
OBJDIR=objdir 
OBJ=$(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp))) 
OBJ+=$(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(notdir $(wildcard ../hello/*.cpp)))) 
TARGET=HelloWorld 

.PHONY: all clean 

all: $(OBJDIR) $(TARGET) 

$(OBJDIR): 
    mkdir $(OBJDIR) 

$(OBJDIR)/%.o: %.cpp 
    $(GCC) $(CPPFLAGS) -c $< -o [email protected] 
$(TARGET): $(OBJ) 
    $(GCC) $(LDFLAGS) -o [email protected] $^ 
clean: 
    @rm -f $(TARGET) $(wildcard *.o) 
    @rm -rf $(OBJDIR) 

現在

$ ls objdir/ 
Hello.o main.o World.o 

專家需要評估新的makefile文件並確認這是一個規模能夠解決?

有關優化/增強當前makefile並幫助減少構建時間的任何輸入信息,敬請關注。

0

您無法一次編譯多個c或cpp文件併爲它們指定一個目標文件。又見這個問題Compile multiple C source fles into a unique object file下面的命令爲您提供了錯誤:

g++ -c -Wall -c main.cpp ../hello/Hello.cpp -o objdir/main.o 

以下編譯成目標文件給你一個Main.o和Hello.o和World.o在當前目錄:

g++ -I./hello -c -Wall -c world/Main.cpp hello/Hello.cpp world/World.cpp 

您可以逐一編譯每個cpp文件併爲每個文件生成目標文件,然後將它們鏈接在一起。這是如何構建具有多個源代碼文件的任何大項目。手工做:

cd world 
g++ -I../hello -c -Wall -c Main.cpp -o objdir/Main.o 
g++ -c -Wall -c ../hello/Hello.cpp -o objdir/Hello.o 
g++ -c -Wall -c World.cpp -o objdir/World.o 
# link: 
g++ objdir/Main.o objdir/Hello.o objdir/World.o -o HelloWorld 

從人的gcc

-c Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file. 

    -o file 
     Place output in file file. This applies to whatever sort of output is being produced, whether it be an executable file, an object file, an assembler file or preprocessed C code. 

答:我的意思是沒有直接回答:-P但它是一個有點棘手。下面是你需要看看你的Makefile什麼:

# you want to add reference to hello as include dir 
# for compiling Main.cpp, In CPPFLAGS add -I ../hello 

# the OBJ list is missing a reference to files in hello directory: 
OBJ=$(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp))) 
OBJ+=$(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(notdir $(wildcard ../hello/*.cpp)))) 

# no change needed for the %.cpp 
# new rule needed to allow it to find hello dir: 

$(OBJDIR)/%.o: 
    $(GCC) $(CPPFLAGS) -c $< -o [email protected] 
$(OBJDIR)/%.o: ../hello/%.cpp 
    $(GCC) $(CPPFLAGS) -c $< -o [email protected] 

讀:https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html

+0

感謝您輸入我想你的建議的更改 但我依然收到以下錯誤 的mkdir objdir G ++。 -c -Wall -c World.cpp -o objdir/World.o g ++ -c -Wall -c main.cpp -o objdir/main.o make:***沒有規則使目標'objdir/Hello。 o',需要HelloWorld'。停止。 這基本上意味着Hello.o在**「world/objdir」**目錄下仍然沒有生成任何其他建議嗎?我很樂意嘗試並取回。 – YOGI

+0

檢查該$(OBJDIR)/%。o:../hello/%.cpp規則。你有沒有好嗎?是否有一個../hello/Hello.cpp文件? – gaoithe

0

這很奇怪,你要訪問當前目錄上面的目錄,因爲你不能使文件與名稱包含..

您需要編譯多個具有相似名稱的文件,例如:在World目錄中可能有另一個名爲Hello/Hello.cpp的文件,那麼您必須同時編譯../Hello/Hello.cppHello/Hello.cpp。雖然它們是兩個不同的文件,但無法生成具有不同名稱的目標文件。你可能會喜歡的東西UPPERDIRECTORY取代..但隨後如果有另一個文件編譯名UPPERDIRECTORY/Hello/Hello.cpp,你就完蛋了......

不管怎麼說,這是一個「臨時的解決辦法」:

CXX=g++ 
CPPFLAGS=-Wall 
LDFLAGS= 
OBJDIR=objdir 
TARGET=HelloWorld 

# PLACE ALL NEEDED DIRECTORIES HERE 
# List of directories that contains all needed cpp files 
MODULES=. ../Hello 

# Get all cpp source file names 
SRCS=$(foreach module, $(MODULES), $(wildcard $(module)/*.cpp)) #*/weird SO comment syntax 

# Convert them to object file names + $(OBJDIR) prefix 
OBJS=$(SRCS:%.cpp=$(OBJDIR)/%.o) 

# Get all directories of $(OBJS) so we can create object files with same name 
# but locate in different dirs, for example: 
#    Hello.cpp -> objdir/Hello.o      (need to create objdir/) 
#  Hello/Hello.cpp -> objdir/Hello/Hello.o    (need to create objdir/Hello/) 
# ../Hello/Hello.cpp -> objdir/UPPERDIRECTORY/Hello/Hello.o (need to create objdir/UPPERDIRECTORY/Hello/) 
ALL_OBJ_DIRS=$(subst ..,UPPERDIRECTORY, $(sort $(dir $(OBJS)))) 

.PHONY: all clean 

all: $(TARGET) 

# Rule to make all needed object directories 
$(ALL_OBJ_DIRS): 
    @mkdir -p [email protected] 

# Rule to make object files 
$(OBJDIR)/%.o: %.cpp | $(ALL_OBJ_DIRS) 
# We need to replace .. with UPPERDIRECTORY in .o (output) path, 
# but keep .cpp (input) path as it is 
    $(CXX) -c $(CPPFLAGS) $< -o $(subst ..,UPPERDIRECTORY,[email protected]) 

# Rule to make target file 
$(TARGET): $(OBJS) 
# We need to replace .. with UPPERDIRECTORY in all $(OBJS) paths 
    $(CXX) $(subst ..,UPPERDIRECTORY,$^) $(LDFLAGS) -o [email protected] 

clean: 
    @rm -f $(TARGET) 
    @rm -rf $(OBJDIR) 

如果我是你,我會放在Makefile所有cpp文件的頂部,以避免..

project/ 
    src/ 
    Makefile 
    Hello/ 
     Hello.h 
     Hello.cpp 
    World/ 
     World.h 
     World.cpp 
     main.cpp 

編輯:您可以在目標文件名與_取代/所以現在你可以在您的目標文件名..

GCC=g++ 
CPPFLAGS=-Wall 
LDFLAGS= 
OBJDIR=obj 
TARGET=HelloWorld 

# Modules: directories that contains all needed cpp files 
MODULES=. ../Hello 
# Get all cpp source file names 
SRCS_WITHCURRENTDIR=$(foreach module, $(MODULES), $(wildcard $(module)/*.cpp)) #*/weird SO comment syntax 
SRCS=$(SRCS_WITHCURRENTDIR:./%=%) # remove ./ 
# Convert them to object file names + $(OBJDIR) prefix 
OBJS=$(SRCS:%.cpp=$(OBJDIR)/%.o) 
OBJ_PREFIX=OBJ 

.PHONY: all clean 

all: $(OBJDIR) $(TARGET) 

$(OBJDIR): 
    @mkdir -p [email protected] 

$(OBJDIR)/%.o: %.cpp 
    $(GCC) -c $(CPPFLAGS) $< -o $(addprefix $(OBJDIR)/$(OBJ_PREFIX),$(subst /,_,$(patsubst $(OBJDIR)/%,%,[email protected]))) 

$(TARGET): $(OBJS) 
    $(GCC) $(addprefix $(OBJDIR)/$(OBJ_PREFIX),$(subst /,_,$(patsubst $(OBJDIR)/%,%,$^))) $(LDFLAGS) -o [email protected] 

clean: 
    @rm -f $(TARGET) 
    @rm -rf $(OBJDIR) 

make clean all給出obj/

g++ -c -Wall main.cpp -o obj/OBJmain.o 
g++ -c -Wall World.cpp -o obj/OBJWorld.o 
g++ -c -Wall ../Hello/Hello.cpp -o obj/OBJ.._Hello_Hello.o 
g++ obj/OBJmain.o obj/OBJWorld.o obj/OBJ.._Hello_Hello.o -o HelloWorld 

3個目標文件:OBJmain.oOBJWorld.oOBJ.._Hello_Hello.o

+0

謝謝Tntxtnt。 我完全同意你對我的看法。 :) 只是爲了澄清爲什麼不可能在「Hello」目錄下有makefile。 基本上我使用Apache thrift來自動生成一些代碼,它會在「Hello」目錄和「World」目錄中生成一些代碼,我將利用生成的「Hello.cpp」文件。所以我無法確定在「Hello」目錄中有makefile。但是我在項目的父目錄中有一個Makefile。哪個inturn應遞歸調用各自子文件夾中的makefile。 – YOGI

+0

這可以幫助我以模塊化的方式構建代碼,並且不需要從頂層構建代碼。相反,我可以建立在我的本地目錄中。 如果你有更好的方法來解決這個問題。我接受你的建議。 我會嘗試你的建議解決方案,然後回來。 – YOGI

+0

我發現了類似的情況[這裏](http://stackoverflow.com/questions/4102469/makefile-to-put-object-files-from-source-files-different-directories-into-a-sing)。你可能需要在不同的目錄結構中依賴單個makefile。 – YOGI