来自一个源目录的Makefile尝试从其他目录访问cpp文件

时间:2017-03-31 12:18:33

标签: c++ makefile

对于位于2个不同目录中的cpp文件的对象创建存在问题,如下所示:

- 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;
}

世界/生成文件 使用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)

我正在查看使用makefile的解决方案,该解决方案在特定目录中生成obj文件,如here所示。

现在我尝试使用Below make文件在world / objdir / hello.o中生成hello / hello.cpp文件的obj文件。哪个不行。 如何让它运作?

世界/生成文件

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 $@
$(TARGET): $(OBJ)
    $(GCC) $(LDFLAGS) -o $@ $^
clean:
    @rm -f $(TARGET) $(wildcard *.o)
    @rm -rf $(OBJDIR)

当我尝试运行make时会抛出以下错误。

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大师的任何帮助表示赞赏! :)

3 个答案:

答案 0 :(得分: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 $@
$(TARGET): $(OBJ)
    $(GCC) $(LDFLAGS) -o $@ $^
clean:
    @rm -f $(TARGET) $(wildcard *.o)
    @rm -rf $(OBJDIR)

现在

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

专家需要评估新的makefile并确认这是否是一个可扩展的解决方案?

有关优化/增强当前makefile以及减少构建时间的任何输入都非常受欢迎。

答案 1 :(得分: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

来自man 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 $@
$(OBJDIR)/%.o: ../hello/%.cpp
    $(GCC) $(CPPFLAGS) -c $< -o $@

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

答案 2 :(得分:0)

您想访问当前目录上方的目录很奇怪,因为您无法创建名称包含..的文件

您需要这个来编译具有相似名称的多个文件,例如:在World目录中,您可能有另一个名为Hello/Hello.cpp的文件,那么您必须同时编译../Hello/Hello.cpp和{{ 1}}。虽然它们是两个不同的文件,但是无法生成具有不同名称的目标文件。您可以将Hello/Hello.cpp替换为..之类的内容,但如果您有其他文件要使用名称UPPERDIRECTORY进行编译,那么您已经搞砸了......

无论如何,这是一个&#34;临时修复&#34;:

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 $@ # 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,$@) # Rule to make target file $(TARGET): $(OBJS) # We need to replace .. with UPPERDIRECTORY in all $(OBJS) paths $(CXX) $(subst ..,UPPERDIRECTORY,$^) $(LDFLAGS) -o $@ clean: @rm -f $(TARGET) @rm -rf $(OBJDIR) 置于所有cpp文件之上以避免Makefile

..

编辑:您可以在对象文件名中将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 $@ $(OBJDIR)/%.o: %.cpp $(GCC) -c $(CPPFLAGS) $< -o $(addprefix $(OBJDIR)/$(OBJ_PREFIX),$(subst /,_,$(patsubst $(OBJDIR)/%,%,$@))) $(TARGET): $(OBJS) $(GCC) $(addprefix $(OBJDIR)/$(OBJ_PREFIX),$(subst /,_,$(patsubst $(OBJDIR)/%,%,$^))) $(LDFLAGS) -o $@ clean: @rm -f $(TARGET) @rm -rf $(OBJDIR) 给出了

make clean all

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个目标文件:obj/OBJmain.oOBJWorld.o