2017-03-31 83 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